diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/CA.pl.in | 134 | ||||
-rw-r--r-- | apps/asn1parse.c (renamed from apps/asn1pars.c) | 27 | ||||
-rw-r--r-- | apps/bf_prefix.c | 177 | ||||
-rw-r--r-- | apps/build.info | 147 | ||||
-rw-r--r--[-rwxr-xr-x] | apps/ca.c | 502 | ||||
-rw-r--r-- | apps/ciphers.c | 66 | ||||
-rw-r--r-- | apps/cmp.c | 3023 | ||||
-rw-r--r-- | apps/cms.c | 685 | ||||
-rw-r--r-- | apps/crl.c | 134 | ||||
-rw-r--r-- | apps/crl2pkcs7.c (renamed from apps/crl2p7.c) | 26 | ||||
-rw-r--r-- | apps/dgst.c | 302 | ||||
-rw-r--r-- | apps/dh1024.pem | 10 | ||||
-rw-r--r-- | apps/dh2048.pem | 14 | ||||
-rw-r--r-- | apps/dh4096.pem | 19 | ||||
-rw-r--r-- | apps/dhparam.c | 432 | ||||
-rw-r--r-- | apps/dsa.c | 219 | ||||
-rw-r--r-- | apps/dsaparam.c | 211 | ||||
-rw-r--r-- | apps/ec.c | 266 | ||||
-rw-r--r-- | apps/ecparam.c | 476 | ||||
-rw-r--r-- | apps/enc.c | 228 | ||||
-rw-r--r-- | apps/engine.c | 27 | ||||
-rw-r--r-- | apps/errstr.c | 23 | ||||
-rw-r--r-- | apps/fipsinstall.c | 590 | ||||
-rw-r--r-- | apps/gendsa.c | 103 | ||||
-rw-r--r-- | apps/genpkey.c | 206 | ||||
-rw-r--r-- | apps/genrsa.c | 173 | ||||
-rw-r--r-- | apps/include/__DECC_INCLUDE_EPILOGUE.H | 22 | ||||
-rw-r--r-- | apps/include/__DECC_INCLUDE_PROLOGUE.H | 26 | ||||
-rw-r--r-- | apps/include/app_libctx.h | 20 | ||||
-rw-r--r-- | apps/include/app_params.h | 14 | ||||
-rw-r--r-- | apps/include/apps.h | 348 | ||||
-rw-r--r-- | apps/include/apps_ui.h | 29 | ||||
-rw-r--r-- | apps/include/cmp_mock_srv.h | 35 | ||||
-rw-r--r-- | apps/include/ec_common.h | 23 | ||||
-rw-r--r-- | apps/include/engine_loader.h | 21 | ||||
-rw-r--r-- | apps/include/fmt.h | 45 | ||||
-rw-r--r-- | apps/include/function.h | 44 | ||||
-rw-r--r-- | apps/include/http_server.h | 125 | ||||
-rw-r--r-- | apps/include/names.h | 17 | ||||
-rw-r--r-- | apps/include/opt.h (renamed from apps/apps.h) | 421 | ||||
-rw-r--r-- | apps/include/platform.h | 32 | ||||
-rw-r--r-- | apps/include/s_apps.h (renamed from apps/s_apps.h) | 43 | ||||
-rw-r--r-- | apps/include/vms_term_sock.h | 31 | ||||
-rw-r--r-- | apps/info.c | 104 | ||||
-rw-r--r-- | apps/insta.ca.crt | bin | 0 -> 916 bytes | |||
-rw-r--r-- | apps/kdf.c | 211 | ||||
-rw-r--r-- | apps/lib/app_libctx.c | 48 | ||||
-rw-r--r-- | apps/lib/app_params.c | 132 | ||||
-rw-r--r-- | apps/lib/app_provider.c | 92 | ||||
-rw-r--r-- | apps/lib/app_rand.c (renamed from apps/app_rand.c) | 43 | ||||
-rw-r--r-- | apps/lib/app_x509.c | 137 | ||||
-rw-r--r-- | apps/lib/apps.c (renamed from apps/apps.c) | 2269 | ||||
-rw-r--r-- | apps/lib/apps_ui.c | 223 | ||||
-rw-r--r-- | apps/lib/build.info | 23 | ||||
-rw-r--r-- | apps/lib/cmp_mock_srv.c | 450 | ||||
-rw-r--r-- | apps/lib/columns.c | 27 | ||||
-rw-r--r-- | apps/lib/engine.c | 193 | ||||
-rw-r--r-- | apps/lib/engine_loader.c | 203 | ||||
-rw-r--r-- | apps/lib/fmt.c | 15 | ||||
-rw-r--r-- | apps/lib/http_server.c | 533 | ||||
-rw-r--r-- | apps/lib/names.c | 45 | ||||
-rw-r--r-- | apps/lib/opt.c (renamed from apps/opt.c) | 586 | ||||
-rw-r--r-- | apps/lib/s_cb.c (renamed from apps/s_cb.c) | 271 | ||||
-rw-r--r-- | apps/lib/s_socket.c (renamed from apps/s_socket.c) | 112 | ||||
-rw-r--r-- | apps/lib/tlssrp_depr.c | 231 | ||||
-rw-r--r-- | apps/lib/vms_decc_argv.c | 72 | ||||
-rw-r--r-- | apps/lib/vms_term_sock.c | 591 | ||||
-rw-r--r-- | apps/lib/win32_init.c | 307 | ||||
-rw-r--r-- | apps/list.c | 1706 | ||||
-rw-r--r-- | apps/mac.c | 237 | ||||
-rw-r--r-- | apps/nseq.c | 30 | ||||
-rw-r--r-- | apps/ocsp.c | 915 | ||||
-rw-r--r-- | apps/openssl.c | 766 | ||||
-rw-r--r-- | apps/openssl.cnf | 154 | ||||
-rw-r--r-- | apps/passwd.c | 80 | ||||
-rw-r--r-- | apps/pkcs12.c | 493 | ||||
-rw-r--r-- | apps/pkcs7.c | 46 | ||||
-rw-r--r-- | apps/pkcs8.c | 82 | ||||
-rw-r--r-- | apps/pkey.c | 195 | ||||
-rw-r--r-- | apps/pkeyparam.c | 62 | ||||
-rw-r--r-- | apps/pkeyutl.c | 439 | ||||
-rw-r--r-- | apps/prime.c | 43 | ||||
-rw-r--r-- | apps/progs.pl | 285 | ||||
-rw-r--r-- | apps/rand.c | 42 | ||||
-rw-r--r-- | apps/rehash.c | 61 | ||||
-rw-r--r-- | apps/req.c | 1003 | ||||
-rw-r--r-- | apps/rsa.c | 322 | ||||
-rw-r--r-- | apps/rsautl.c | 126 | ||||
-rw-r--r-- | apps/s_client.c | 812 | ||||
-rw-r--r-- | apps/s_server.c | 923 | ||||
-rw-r--r-- | apps/s_time.c | 142 | ||||
-rw-r--r-- | apps/sess_id.c | 19 | ||||
-rw-r--r-- | apps/smime.c | 186 | ||||
-rw-r--r-- | apps/speed.c | 3476 | ||||
-rw-r--r-- | apps/spkac.c | 59 | ||||
-rw-r--r-- | apps/srp.c | 55 | ||||
-rw-r--r-- | apps/storeutl.c | 113 | ||||
-rw-r--r-- | apps/testdsa.h | 51 | ||||
-rw-r--r-- | apps/testrsa.h | 2 | ||||
-rw-r--r-- | apps/timeouts.h | 2 | ||||
-rw-r--r-- | apps/ts.c | 195 | ||||
-rw-r--r-- | apps/tsget.in | 56 | ||||
-rw-r--r-- | apps/verify.c | 179 | ||||
-rw-r--r-- | apps/version.c | 137 | ||||
-rw-r--r-- | apps/x509.c | 1179 |
105 files changed, 21482 insertions, 9625 deletions
diff --git a/apps/CA.pl.in b/apps/CA.pl.in index db3cc383189e..f029470005d9 100644 --- a/apps/CA.pl.in +++ b/apps/CA.pl.in @@ -1,7 +1,7 @@ #!{- $config{HASHBANGPERL} -} -# Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. # -# Licensed under the OpenSSL license (the "License"). You may not use +# 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 @@ -14,57 +14,63 @@ use strict; use warnings; -my $openssl = "openssl"; -if(defined $ENV{'OPENSSL'}) { - $openssl = $ENV{'OPENSSL'}; -} else { - $ENV{'OPENSSL'} = $openssl; -} - my $verbose = 1; +my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); -my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || ""; -my $DAYS = "-days 365"; -my $CADAYS = "-days 1095"; # 3 years +my $openssl = $ENV{'OPENSSL'} // "openssl"; +$ENV{'OPENSSL'} = $openssl; +my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // ""; + +# Command invocations. my $REQ = "$openssl req $OPENSSL_CONFIG"; my $CA = "$openssl ca $OPENSSL_CONFIG"; my $VERIFY = "$openssl verify"; my $X509 = "$openssl x509"; my $PKCS12 = "$openssl pkcs12"; -# default openssl.cnf file has setup as per the following +# Default values for various configuration settings. my $CATOP = "./demoCA"; my $CAKEY = "cakey.pem"; my $CAREQ = "careq.pem"; my $CACERT = "cacert.pem"; my $CACRL = "crl.pem"; -my $DIRMODE = 0777; - +my $DAYS = "-days 365"; +my $CADAYS = "-days 1095"; # 3 years my $NEWKEY = "newkey.pem"; my $NEWREQ = "newreq.pem"; my $NEWCERT = "newcert.pem"; my $NEWP12 = "newcert.p12"; -my $RET = 0; + +# Commandline parsing +my %EXTRA; my $WHAT = shift @ARGV || ""; -my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); -my %EXTRA = extra_args(\@ARGV, "-extra-"); -my $FILE; - -sub extra_args { - my ($args_ref, $arg_prefix) = @_; - my %eargs = map { - if ($_ < $#$args_ref) { - my ($arg, $value) = splice(@$args_ref, $_, 2); - $arg =~ s/$arg_prefix//; - ($arg, $value); - } else { - (); - } - } reverse grep($$args_ref[$_] =~ /$arg_prefix/, 0..$#$args_ref); - my %empty = map { ($_, "") } @OPENSSL_CMDS; - return (%empty, %eargs); +@ARGV = parse_extra(@ARGV); +my $RET = 0; + +# Split out "-extra-CMD value", and return new |@ARGV|. Fill in +# |EXTRA{CMD}| with list of values. +sub parse_extra +{ + foreach ( @OPENSSL_CMDS ) { + $EXTRA{$_} = ''; + } + + my @result; + while ( scalar(@_) > 0 ) { + my $arg = shift; + if ( $arg !~ m/-extra-([a-z0-9]+)/ ) { + push @result, $arg; + next; + } + $arg =~ s/-extra-//; + die("Unknown \"-${arg}-extra\" option, exiting") + unless scalar grep { $arg eq $_ } @OPENSSL_CMDS; + $EXTRA{$arg} .= " " . shift; + } + return @result; } + # See if reason for a CRL entry is valid; exit if not. sub crl_reason_ok { @@ -113,19 +119,25 @@ sub run if ( $WHAT =~ /^(-\?|-h|-help)$/ ) { - print STDERR "usage: CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd extra-params]\n"; - print STDERR " CA.pl -pkcs12 [-extra-pkcs12 extra-params] [certname]\n"; - print STDERR " CA.pl -verify [-extra-verify extra-params] certfile ...\n"; - print STDERR " CA.pl -revoke [-extra-ca extra-params] certfile [reason]\n"; + print STDERR <<EOF; +Usage: + CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter] + CA.pl -pkcs12 [certname] + CA.pl -verify certfile ... + CA.pl -revoke certfile [reason] +EOF exit 0; } + if ($WHAT eq '-newcert' ) { # create a certificate - $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS $EXTRA{req}"); + $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS" + . " $EXTRA{req}"); print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; } elsif ($WHAT eq '-precert' ) { # create a pre-certificate - $RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"); + $RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS" + . " $EXTRA{req}"); print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; } elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) { # create a certificate request @@ -133,11 +145,20 @@ if ($WHAT eq '-newcert' ) { print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; } elsif ($WHAT eq '-newca' ) { # create the directory hierarchy - mkdir ${CATOP}, $DIRMODE; - mkdir "${CATOP}/certs", $DIRMODE; - mkdir "${CATOP}/crl", $DIRMODE ; - mkdir "${CATOP}/newcerts", $DIRMODE; - mkdir "${CATOP}/private", $DIRMODE; + my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl", + "${CATOP}/newcerts", "${CATOP}/private" ); + die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed," + if -f "${CATOP}/index.txt"; + die "${CATOP}/serial exists.\nRemove old sub-tree to proceed," + if -f "${CATOP}/serial"; + foreach my $d ( @dirs ) { + if ( -d $d ) { + warn "Directory $d exists" if -d $d; + } else { + mkdir $d or die "Can't mkdir $d, $!"; + } + } + open OUT, ">${CATOP}/index.txt"; close OUT; open OUT, ">${CATOP}/crlnumber"; @@ -145,6 +166,7 @@ if ($WHAT eq '-newcert' ) { close OUT; # ask user for existing CA certificate print "CA certificate filename (or enter to create)\n"; + my $FILE; $FILE = "" unless defined($FILE = <STDIN>); $FILE =~ s{\R$}{}; if ($FILE ne "") { @@ -152,43 +174,43 @@ if ($WHAT eq '-newcert' ) { copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); } else { print "Making CA certificate ...\n"; - $RET = run("$REQ -new -keyout" - . " ${CATOP}/private/$CAKEY" + $RET = run("$REQ -new -keyout ${CATOP}/private/$CAKEY" . " -out ${CATOP}/$CAREQ $EXTRA{req}"); $RET = run("$CA -create_serial" . " -out ${CATOP}/$CACERT $CADAYS -batch" . " -keyfile ${CATOP}/private/$CAKEY -selfsign" - . " -extensions v3_ca $EXTRA{ca}" - . " -infiles ${CATOP}/$CAREQ") if $RET == 0; + . " -extensions v3_ca" + . " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0; print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0; } } elsif ($WHAT eq '-pkcs12' ) { my $cname = $ARGV[0]; $cname = "My Certificate" unless defined $cname; $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY" - . " -certfile ${CATOP}/$CACERT" - . " -out $NEWP12" + . " -certfile ${CATOP}/$CACERT -out $NEWP12" . " -export -name \"$cname\" $EXTRA{pkcs12}"); print "PKCS #12 file is in $NEWP12\n" if $RET == 0; } elsif ($WHAT eq '-xsign' ) { - $RET = run("$CA -policy policy_anything $EXTRA{ca} -infiles $NEWREQ"); + $RET = run("$CA -policy policy_anything -infiles $NEWREQ $EXTRA{ca}"); } elsif ($WHAT eq '-sign' ) { - $RET = run("$CA -policy policy_anything -out $NEWCERT $EXTRA{ca} -infiles $NEWREQ"); + $RET = run("$CA -policy policy_anything -out $NEWCERT" + . " -infiles $NEWREQ $EXTRA{ca}"); print "Signed certificate is in $NEWCERT\n" if $RET == 0; } elsif ($WHAT eq '-signCA' ) { $RET = run("$CA -policy policy_anything -out $NEWCERT" - . " -extensions v3_ca $EXTRA{ca} -infiles $NEWREQ"); + . " -extensions v3_ca -infiles $NEWREQ $EXTRA{ca}"); print "Signed CA certificate is in $NEWCERT\n" if $RET == 0; } elsif ($WHAT eq '-signcert' ) { $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ" . " -out tmp.pem $EXTRA{x509}"); $RET = run("$CA -policy policy_anything -out $NEWCERT" - . "$EXTRA{ca} -infiles tmp.pem") if $RET == 0; + . "-infiles tmp.pem $EXTRA{ca}") if $RET == 0; print "Signed certificate is in $NEWCERT\n" if $RET == 0; } elsif ($WHAT eq '-verify' ) { my @files = @ARGV ? @ARGV : ( $NEWCERT ); - my $file; - foreach $file (@files) { + foreach my $file (@files) { + # -CAfile quoted for VMS, since the C RTL downcases all unquoted + # arguments to C programs my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}"); $RET = $status if $status != 0; } diff --git a/apps/asn1pars.c b/apps/asn1parse.c index 6c44df7de490..f0bfd1d45fc4 100644 --- a/apps/asn1pars.c +++ b/apps/asn1parse.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -19,7 +19,7 @@ #include <openssl/asn1t.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_IN, OPT_OUT, OPT_INDENT, OPT_NOOUT, OPT_OID, OPT_OFFSET, OPT_LENGTH, OPT_DUMP, OPT_DLIMIT, OPT_STRPARSE, OPT_GENSTR, OPT_GENCONF, OPT_STRICTPEM, @@ -27,27 +27,32 @@ typedef enum OPTION_choice { } OPTION_CHOICE; const OPTIONS asn1parse_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"oid", OPT_OID, '<', "file of extra oid definitions"}, + + OPT_SECTION("I/O"), {"inform", OPT_INFORM, 'F', "input format - one of DER PEM"}, {"in", OPT_IN, '<', "input file"}, {"out", OPT_OUT, '>', "output file (output format is always DER)"}, - {"i", OPT_INDENT, 0, "indents the output"}, {"noout", OPT_NOOUT, 0, "do not produce any output"}, {"offset", OPT_OFFSET, 'p', "offset into file"}, {"length", OPT_LENGTH, 'p', "length of section in file"}, - {"oid", OPT_OID, '<', "file of extra oid definitions"}, - {"dump", OPT_DUMP, 0, "unknown data in hex form"}, - {"dlimit", OPT_DLIMIT, 'p', - "dump the first arg bytes of unknown data in hex form"}, {"strparse", OPT_STRPARSE, 'p', "offset; a series of these can be used to 'dig'"}, - {OPT_MORE_STR, 0, 0, "into multiple ASN1 blob wrappings"}, {"genstr", OPT_GENSTR, 's', "string to generate ASN1 structure from"}, + {OPT_MORE_STR, 0, 0, "into multiple ASN1 blob wrappings"}, {"genconf", OPT_GENCONF, 's', "file to generate ASN1 structure from"}, - {OPT_MORE_STR, 0, 0, "(-inform will be ignored)"}, {"strictpem", OPT_STRICTPEM, 0, "do not attempt base64 decode outside PEM markers"}, {"item", OPT_ITEM, 's', "item to parse and print"}, + {OPT_MORE_STR, 0, 0, "(-inform will be ignored)"}, + + OPT_SECTION("Formatting"), + {"i", OPT_INDENT, 0, "indents the output"}, + {"dump", OPT_DUMP, 0, "unknown data in hex form"}, + {"dlimit", OPT_DLIMIT, 'p', + "dump the first arg bytes of unknown data in hex form"}, {NULL} }; @@ -152,6 +157,8 @@ int asn1parse_main(int argc, char **argv) break; } } + + /* No extra args. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; diff --git a/apps/bf_prefix.c b/apps/bf_prefix.c deleted file mode 100644 index bae3c91bf8b3..000000000000 --- a/apps/bf_prefix.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2018 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 <stdio.h> -#include <string.h> -#include <errno.h> -#include <openssl/bio.h> -#include "apps.h" - -static int prefix_write(BIO *b, const char *out, size_t outl, - size_t *numwritten); -static int prefix_read(BIO *b, char *buf, size_t size, size_t *numread); -static int prefix_puts(BIO *b, const char *str); -static int prefix_gets(BIO *b, char *str, int size); -static long prefix_ctrl(BIO *b, int cmd, long arg1, void *arg2); -static int prefix_create(BIO *b); -static int prefix_destroy(BIO *b); -static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp); - -static BIO_METHOD *prefix_meth = NULL; - -BIO_METHOD *apps_bf_prefix(void) -{ - if (prefix_meth == NULL) { - if ((prefix_meth = - BIO_meth_new(BIO_TYPE_FILTER, "Prefix filter")) == NULL - || !BIO_meth_set_create(prefix_meth, prefix_create) - || !BIO_meth_set_destroy(prefix_meth, prefix_destroy) - || !BIO_meth_set_write_ex(prefix_meth, prefix_write) - || !BIO_meth_set_read_ex(prefix_meth, prefix_read) - || !BIO_meth_set_puts(prefix_meth, prefix_puts) - || !BIO_meth_set_gets(prefix_meth, prefix_gets) - || !BIO_meth_set_ctrl(prefix_meth, prefix_ctrl) - || !BIO_meth_set_callback_ctrl(prefix_meth, prefix_callback_ctrl)) { - BIO_meth_free(prefix_meth); - prefix_meth = NULL; - } - } - return prefix_meth; -} - -typedef struct prefix_ctx_st { - char *prefix; - int linestart; /* flag to indicate we're at the line start */ -} PREFIX_CTX; - -static int prefix_create(BIO *b) -{ - PREFIX_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); - - if (ctx == NULL) - return 0; - - ctx->prefix = NULL; - ctx->linestart = 1; - BIO_set_data(b, ctx); - BIO_set_init(b, 1); - return 1; -} - -static int prefix_destroy(BIO *b) -{ - PREFIX_CTX *ctx = BIO_get_data(b); - - OPENSSL_free(ctx->prefix); - OPENSSL_free(ctx); - return 1; -} - -static int prefix_read(BIO *b, char *in, size_t size, size_t *numread) -{ - return BIO_read_ex(BIO_next(b), in, size, numread); -} - -static int prefix_write(BIO *b, const char *out, size_t outl, - size_t *numwritten) -{ - PREFIX_CTX *ctx = BIO_get_data(b); - - if (ctx == NULL) - return 0; - - /* If no prefix is set or if it's empty, we've got nothing to do here */ - if (ctx->prefix == NULL || *ctx->prefix == '\0') { - /* We do note if what comes next will be a new line, though */ - if (outl > 0) - ctx->linestart = (out[outl-1] == '\n'); - return BIO_write_ex(BIO_next(b), out, outl, numwritten); - } - - *numwritten = 0; - - while (outl > 0) { - size_t i; - char c; - - /* If we know that we're at the start of the line, output the prefix */ - if (ctx->linestart) { - size_t dontcare; - - if (!BIO_write_ex(BIO_next(b), ctx->prefix, strlen(ctx->prefix), - &dontcare)) - return 0; - ctx->linestart = 0; - } - - /* Now, go look for the next LF, or the end of the string */ - for (i = 0, c = '\0'; i < outl && (c = out[i]) != '\n'; i++) - continue; - if (c == '\n') - i++; - - /* Output what we found so far */ - while (i > 0) { - size_t num = 0; - - if (!BIO_write_ex(BIO_next(b), out, i, &num)) - return 0; - out += num; - outl -= num; - *numwritten += num; - i -= num; - } - - /* If we found a LF, what follows is a new line, so take note */ - if (c == '\n') - ctx->linestart = 1; - } - - return 1; -} - -static long prefix_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 0; - - switch (cmd) { - case PREFIX_CTRL_SET_PREFIX: - { - PREFIX_CTX *ctx = BIO_get_data(b); - - if (ctx == NULL) - break; - - OPENSSL_free(ctx->prefix); - ctx->prefix = OPENSSL_strdup((const char *)ptr); - ret = ctx->prefix != NULL; - } - break; - default: - if (BIO_next(b) != NULL) - ret = BIO_ctrl(BIO_next(b), cmd, num, ptr); - break; - } - return ret; -} - -static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - return BIO_callback_ctrl(BIO_next(b), cmd, fp); -} - -static int prefix_gets(BIO *b, char *buf, int size) -{ - return BIO_gets(BIO_next(b), buf, size); -} - -static int prefix_puts(BIO *b, const char *str) -{ - return BIO_write(b, str, strlen(str)); -} diff --git a/apps/build.info b/apps/build.info index 01537361820e..020d129f8cac 100644 --- a/apps/build.info +++ b/apps/build.info @@ -1,79 +1,90 @@ -{- our @apps_openssl_src = - qw(openssl.c - asn1pars.c ca.c ciphers.c cms.c crl.c crl2p7.c dgst.c - enc.c errstr.c - genpkey.c nseq.c passwd.c pkcs7.c pkcs8.c - pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c - s_client.c s_server.c s_time.c sess_id.c smime.c speed.c spkac.c - verify.c version.c x509.c rehash.c storeutl.c); - our @apps_lib_src = - ( qw(apps.c opt.c s_cb.c s_socket.c app_rand.c bf_prefix.c), - split(/\s+/, $target{apps_aux_src}) ); - our @apps_init_src = split(/\s+/, $target{apps_init_src}); - "" -} +SUBDIRS=lib -IF[{- !$disabled{apps} -}] - LIBS_NO_INST=libapps.a - SOURCE[libapps.a]={- join(" ", @apps_lib_src) -} - INCLUDE[libapps.a]=.. ../include +# Program init source, that don't have direct linkage with the rest of the +# source, and can therefore not be part of a library. +IF[{- !$disabled{uplink} -}] + $INITSRC=../ms/applink.c +ENDIF +IF[{- $config{target} =~ /^vms-/ -}] + $INITSRC=vms_decc_init.c +ENDIF - PROGRAMS=openssl - SOURCE[openssl]={- join(" ", @apps_init_src) -} - SOURCE[openssl]={- join(" ", @apps_openssl_src) -} - INCLUDE[openssl]=.. ../include - DEPEND[openssl]=libapps.a ../libssl - IF[{- !$disabled{'des'} -}] - SOURCE[openssl]=pkcs12.c - DEPEND[pkcs12.o]=progs.h - ENDIF - IF[{- !$disabled{'ec'} -}] - SOURCE[openssl]=ec.c ecparam.c - DEPEND[ec.o]=progs.h - DEPEND[ecparam.o]=progs.h - ENDIF - IF[{- !$disabled{'ocsp'} -}] - SOURCE[openssl]=ocsp.c - DEPEND[ocsp.o]=progs.h - ENDIF - IF[{- !$disabled{'srp'} -}] - SOURCE[openssl]=srp.c - DEPEND[srp.o]=progs.h - ENDIF - IF[{- !$disabled{'ts'} -}] - SOURCE[openssl]=ts.c - DEPEND[ts.o]=progs.h - ENDIF - IF[{- !$disabled{'dh'} -}] - SOURCE[openssl]=dhparam.c - DEPEND[dhparam.o]=progs.h - ENDIF - IF[{- !$disabled{'dsa'} -}] - SOURCE[openssl]=dsa.c dsaparam.c gendsa.c - DEPEND[dsa.o]=progs.h - DEPEND[dsaparam.o]=progs.h - DEPEND[gendsa.o]=progs.h - ENDIF - IF[{- !$disabled{'engine'} -}] - SOURCE[openssl]=engine.c - DEPEND[engine.o]=progs.h - ENDIF +# Source for the 'openssl' program +$OPENSSLSRC=\ + openssl.c \ + asn1parse.c ca.c ciphers.c crl.c crl2pkcs7.c dgst.c \ + enc.c errstr.c \ + genpkey.c kdf.c mac.c nseq.c passwd.c pkcs7.c \ + pkcs8.c pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c \ + s_client.c s_server.c s_time.c sess_id.c smime.c speed.c \ + spkac.c verify.c version.c x509.c rehash.c storeutl.c \ + list.c info.c fipsinstall.c pkcs12.c +IF[{- !$disabled{'ec'} -}] + $OPENSSLSRC=$OPENSSLSRC ec.c ecparam.c +ENDIF +IF[{- !$disabled{'ocsp'} -}] + $OPENSSLSRC=$OPENSSLSRC ocsp.c +ENDIF +IF[{- !$disabled{'srp'} -}] + $OPENSSLSRC=$OPENSSLSRC srp.c +ENDIF +IF[{- !$disabled{'ts'} -}] + $OPENSSLSRC=$OPENSSLSRC ts.c +ENDIF +IF[{- !$disabled{'dh'} -}] +$OPENSSLSRC=$OPENSSLSRC dhparam.c +ENDIF +IF[{- !$disabled{'dsa'} -}] +$OPENSSLSRC=$OPENSSLSRC dsa.c dsaparam.c gendsa.c +ENDIF +IF[{- !$disabled{'engine'} -}] +$OPENSSLSRC=$OPENSSLSRC engine.c +ENDIF +IF[{- !$disabled{'rsa'} -}] +$OPENSSLSRC=$OPENSSLSRC rsa.c genrsa.c +ENDIF +IF[{- !$disabled{'deprecated-3.0'} -}] IF[{- !$disabled{'rsa'} -}] - SOURCE[openssl]=rsa.c rsautl.c genrsa.c - DEPEND[rsa.o]=progs.h - DEPEND[rsautl.o]=progs.h - DEPEND[genrsa.o]=progs.h + $OPENSSLSRC=$OPENSSLSRC rsautl.c ENDIF - IF[{- $config{target} =~ /^(?:Cygwin|mingw|VC-)/ -}] +ENDIF +IF[{- !$disabled{'cms'} -}] + $OPENSSLSRC=$OPENSSLSRC cms.c +ENDIF +IF[{- !$disabled{'cmp'} -}] + $OPENSSLSRC=$OPENSSLSRC cmp.c lib/cmp_mock_srv.c +ENDIF + +IF[{- !$disabled{apps} -}] + PROGRAMS=openssl + SOURCE[openssl]=$INITSRC $OPENSSLSRC + INCLUDE[openssl]=.. ../include include + DEPEND[openssl]=libapps.a ../libssl + + # The nocheck attribute is picked up by progs.pl as a signal not to look + # at that file; some systems may have locked it as the output file, and + # therefore don't allow it to be read at the same time, making progs.pl + # fail. + SOURCE[openssl]{nocheck}=progs.c + DEPEND[${OPENSSLSRC/.c/.o} progs.o]=progs.h + GENERATE[progs.c]=progs.pl "-C" $(APPS_OPENSSL) + GENERATE[progs.h]=progs.pl "-H" $(APPS_OPENSSL) + # progs.pl tries to read all 'openssl' sources, including progs.c, so we make + # sure things are generated in the correct order. + DEPEND[progs.h]=progs.c + # Because the files to look through may change (depends on $OPENSSLSRC), + # always depend on a changed configuration. + DEPEND[progs.c]=../configdata.pm + + IF[{- $config{target} =~ /^(?:Cygwin|mingw|VC-|BC-)/ -}] GENERATE[openssl.rc]=../util/mkrc.pl openssl SOURCE[openssl]=openssl.rc ENDIF - {- join("\n ", map { (my $x = $_) =~ s|\.c$|.o|; "DEPEND[$x]=progs.h" } - @apps_openssl_src) -} - GENERATE[progs.h]=progs.pl $(APPS_OPENSSL) - DEPEND[progs.h]=../configdata.pm - - SCRIPTS=CA.pl tsget.pl + SCRIPTS{misc}=CA.pl SOURCE[CA.pl]=CA.pl.in + # linkname tells build files that a symbolic link or copy of this script + # without extension must be installed as well. Unix or Unix lookalike only. + SCRIPTS{misc,linkname=tsget}=tsget.pl SOURCE[tsget.pl]=tsget.in ENDIF diff --git a/apps/ca.c b/apps/ca.c index ea375ca0b1d3..e14a5cff7802 100755..100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -26,7 +26,7 @@ #ifndef W_OK # ifdef OPENSSL_SYS_VMS # include <unistd.h> -# elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) +# elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_TANDEM) # include <sys/file.h> # endif #endif @@ -88,40 +88,46 @@ typedef enum { static char *lookup_conf(const CONF *conf, const char *group, const char *tag); -static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, - const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, +static int certify(X509 **xret, const char *infile, int informat, + EVP_PKEY *pkey, X509 *x509, + const char *dgst, + STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(OPENSSL_STRING) *vfyopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, int batch, const char *ext_sect, CONF *conf, int verbose, unsigned long certopt, unsigned long nameopt, - int default_op, int ext_copy, int selfsign); -static int certify_cert(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, - const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, + int default_op, int ext_copy, int selfsign, unsigned long dateopt); +static int certify_cert(X509 **xret, const char *infile, int certformat, + const char *passin, EVP_PKEY *pkey, X509 *x509, + const char *dgst, + STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(OPENSSL_STRING) *vfyopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, int batch, const char *ext_sect, CONF *conf, int verbose, unsigned long certopt, - unsigned long nameopt, int default_op, int ext_copy); + unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt); static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, - X509 *x509, const EVP_MD *dgst, + X509 *x509, const char *dgst, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, const char *ext_sect, CONF *conf, int verbose, unsigned long certopt, - unsigned long nameopt, int default_op, int ext_copy); + unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt); static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, - const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, + const char *dgst, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, int batch, int verbose, X509_REQ *req, const char *ext_sect, CONF *conf, unsigned long certopt, unsigned long nameopt, - int default_op, int ext_copy, int selfsign); + int default_op, int ext_copy, int selfsign, unsigned long dateopt); static int get_certificate_status(const char *ser_status, CA_DB *db); static int do_updatedb(CA_DB *db); static int check_time_format(const char *str); @@ -132,77 +138,97 @@ static int make_revoked(X509_REVOKED *rev, const char *str); static int old_entry_print(const ASN1_OBJECT *obj, const ASN1_STRING *str); static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext); -static CONF *extconf = NULL; +static CONF *extfile_conf = NULL; static int preserve = 0; static int msie_hack = 0; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_ENGINE, OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SUBJ, OPT_UTF8, OPT_CREATE_SERIAL, OPT_MULTIVALUE_RDN, OPT_STARTDATE, OPT_ENDDATE, OPT_DAYS, OPT_MD, OPT_POLICY, OPT_KEYFILE, OPT_KEYFORM, OPT_PASSIN, - OPT_KEY, OPT_CERT, OPT_SELFSIGN, OPT_IN, OPT_OUT, OPT_OUTDIR, + OPT_KEY, OPT_CERT, OPT_CERTFORM, OPT_SELFSIGN, + OPT_IN, OPT_INFORM, OPT_OUT, OPT_DATEOPT, OPT_OUTDIR, OPT_VFYOPT, OPT_SIGOPT, OPT_NOTEXT, OPT_BATCH, OPT_PRESERVEDN, OPT_NOEMAILDN, - OPT_GENCRL, OPT_MSIE_HACK, OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC, + OPT_GENCRL, OPT_MSIE_HACK, OPT_CRL_LASTUPDATE, OPT_CRL_NEXTUPDATE, + OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC, OPT_INFILES, OPT_SS_CERT, OPT_SPKAC, OPT_REVOKE, OPT_VALID, OPT_EXTENSIONS, OPT_EXTFILE, OPT_STATUS, OPT_UPDATEDB, OPT_CRLEXTS, OPT_RAND_SERIAL, - OPT_R_ENUM, + OPT_R_ENUM, OPT_PROV_ENUM, /* Do not change the order here; see related case statements below */ OPT_CRL_REASON, OPT_CRL_HOLD, OPT_CRL_COMPROMISE, OPT_CRL_CA_COMPROMISE } OPTION_CHOICE; const OPTIONS ca_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [certreq...]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, {"verbose", OPT_VERBOSE, '-', "Verbose output during processing"}, + {"outdir", OPT_OUTDIR, '/', "Where to put output cert"}, + {"in", OPT_IN, '<', "The input cert request(s)"}, + {"inform", OPT_INFORM, 'F', "CSR input format (DER or PEM); default PEM"}, + {"infiles", OPT_INFILES, '-', "The last argument, requests to process"}, + {"out", OPT_OUT, '>', "Where to put the output file(s)"}, + {"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."}, + {"notext", OPT_NOTEXT, '-', "Do not print the generated certificate"}, + {"batch", OPT_BATCH, '-', "Don't ask questions"}, + {"msie_hack", OPT_MSIE_HACK, '-', + "msie modifications to handle all Universal Strings"}, + {"ss_cert", OPT_SS_CERT, '<', "File contains a self signed cert to sign"}, + {"spkac", OPT_SPKAC, '<', + "File contains DN and signed public key and challenge"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Configuration"), {"config", OPT_CONFIG, 's', "A config file"}, {"name", OPT_NAME, 's', "The particular CA definition to use"}, + {"section", OPT_NAME, 's', "An alias for -name"}, + {"policy", OPT_POLICY, 's', "The CA 'policy' to support"}, + + OPT_SECTION("Certificate"), {"subj", OPT_SUBJ, 's', "Use arg instead of request's subject"}, - {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"}, + {"utf8", OPT_UTF8, '-', "Input characters are UTF8; default ASCII"}, {"create_serial", OPT_CREATE_SERIAL, '-', "If reading serial fails, create a new random serial"}, {"rand_serial", OPT_RAND_SERIAL, '-', "Always create a random serial; do not store it"}, {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-', - "Enable support for multivalued RDNs"}, + "Deprecated; multi-valued RDNs support is always on."}, {"startdate", OPT_STARTDATE, 's', "Cert notBefore, YYMMDDHHMMSSZ"}, {"enddate", OPT_ENDDATE, 's', "YYMMDDHHMMSSZ cert notAfter (overrides -days)"}, {"days", OPT_DAYS, 'p', "Number of days to certify the cert for"}, - {"md", OPT_MD, 's', "md to use; one of md2, md5, sha or sha1"}, - {"policy", OPT_POLICY, 's', "The CA 'policy' to support"}, - {"keyfile", OPT_KEYFILE, 's', "Private key"}, - {"keyform", OPT_KEYFORM, 'f', "Private key file format (PEM or ENGINE)"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"key", OPT_KEY, 's', "Key to decode the private key if it is encrypted"}, + {"extensions", OPT_EXTENSIONS, 's', + "Extension section (override value in config file)"}, + {"extfile", OPT_EXTFILE, '<', + "Configuration file with X509v3 extensions to add"}, + {"preserveDN", OPT_PRESERVEDN, '-', "Don't re-order the DN"}, + {"noemailDN", OPT_NOEMAILDN, '-', "Don't add the EMAIL field to the DN"}, + + OPT_SECTION("Signing"), + {"md", OPT_MD, 's', "Digest to use, such as sha256"}, + {"keyfile", OPT_KEYFILE, 's', "The CA private key"}, + {"keyform", OPT_KEYFORM, 'f', + "Private key file format (ENGINE, other values ignored)"}, + {"passin", OPT_PASSIN, 's', "Key and cert input file pass phrase source"}, + {"key", OPT_KEY, 's', + "Key to decrypt the private key or cert files if encrypted. Better use -passin"}, {"cert", OPT_CERT, '<', "The CA cert"}, + {"certform", OPT_CERTFORM, 'F', + "Certificate input format (DER/PEM/P12); has no effect"}, {"selfsign", OPT_SELFSIGN, '-', "Sign a cert with the key associated with it"}, - {"in", OPT_IN, '<', "The input PEM encoded cert request(s)"}, - {"out", OPT_OUT, '>', "Where to put the output file(s)"}, - {"outdir", OPT_OUTDIR, '/', "Where to put output cert"}, {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, - {"notext", OPT_NOTEXT, '-', "Do not print the generated certificate"}, - {"batch", OPT_BATCH, '-', "Don't ask questions"}, - {"preserveDN", OPT_PRESERVEDN, '-', "Don't re-order the DN"}, - {"noemailDN", OPT_NOEMAILDN, '-', "Don't add the EMAIL field to the DN"}, + {"vfyopt", OPT_VFYOPT, 's', "Verification parameter in n:v form"}, + + OPT_SECTION("Revocation"), {"gencrl", OPT_GENCRL, '-', "Generate a new CRL"}, - {"msie_hack", OPT_MSIE_HACK, '-', - "msie modifications to handle all those universal strings"}, - {"crldays", OPT_CRLDAYS, 'p', "Days until the next CRL is due"}, - {"crlhours", OPT_CRLHOURS, 'p', "Hours until the next CRL is due"}, - {"crlsec", OPT_CRLSEC, 'p', "Seconds until the next CRL is due"}, - {"infiles", OPT_INFILES, '-', "The last argument, requests to process"}, - {"ss_cert", OPT_SS_CERT, '<', "File contains a self signed cert to sign"}, - {"spkac", OPT_SPKAC, '<', - "File contains DN and signed public key and challenge"}, - {"revoke", OPT_REVOKE, '<', "Revoke a cert (given in file)"}, {"valid", OPT_VALID, 's', "Add a Valid(not-revoked) DB entry about a cert (given in file)"}, - {"extensions", OPT_EXTENSIONS, 's', - "Extension section (override value in config file)"}, - {"extfile", OPT_EXTFILE, '<', - "Configuration file with X509v3 extensions to add"}, {"status", OPT_STATUS, 's', "Shows cert status given the serial number"}, {"updatedb", OPT_UPDATEDB, '-', "Updates db for expired cert"}, {"crlexts", OPT_CRLEXTS, 's', @@ -214,10 +240,20 @@ const OPTIONS ca_options[] = { "sets compromise time to val and the revocation reason to keyCompromise"}, {"crl_CA_compromise", OPT_CRL_CA_COMPROMISE, 's', "sets compromise time to val and the revocation reason to CACompromise"}, + {"crl_lastupdate", OPT_CRL_LASTUPDATE, 's', + "Sets the CRL lastUpdate time to val (YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ)"}, + {"crl_nextupdate", OPT_CRL_NEXTUPDATE, 's', + "Sets the CRL nextUpdate time to val (YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ)"}, + {"crldays", OPT_CRLDAYS, 'p', "Days until the next CRL is due"}, + {"crlhours", OPT_CRLHOURS, 'p', "Hours until the next CRL is due"}, + {"crlsec", OPT_CRLSEC, 'p', "Seconds until the next CRL is due"}, + {"revoke", OPT_REVOKE, '<', "Revoke a cert (given in file)"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"certreq", 0, 0, "Certificate requests to be signed (optional)"}, {NULL} }; @@ -229,19 +265,21 @@ int ca_main(int argc, char **argv) EVP_PKEY *pkey = NULL; BIO *in = NULL, *out = NULL, *Sout = NULL; ASN1_INTEGER *tmpser; - ASN1_TIME *tmptm; CA_DB *db = NULL; DB_ATTR db_attr; STACK_OF(CONF_VALUE) *attribs = NULL; - STACK_OF(OPENSSL_STRING) *sigopts = NULL; + STACK_OF(OPENSSL_STRING) *sigopts = NULL, *vfyopts = NULL; STACK_OF(X509) *cert_sk = NULL; X509_CRL *crl = NULL; - const EVP_MD *dgst = NULL; char *configfile = default_config_file, *section = NULL; - char *md = NULL, *policy = NULL, *keyfile = NULL; - char *certfile = NULL, *crl_ext = NULL, *crlnumberfile = NULL, *key = NULL; + char def_dgst[80] = ""; + char *dgst = NULL, *policy = NULL, *keyfile = NULL; + char *certfile = NULL, *crl_ext = NULL, *crlnumberfile = NULL; + int certformat = FORMAT_UNDEF, informat = FORMAT_UNDEF; + unsigned long dateopt = ASN1_DTFLGS_RFC822; const char *infile = NULL, *spkac_file = NULL, *ss_cert_file = NULL; const char *extensions = NULL, *extfile = NULL, *passinarg = NULL; + char *passin = NULL; char *outdir = NULL, *outfile = NULL, *rev_arg = NULL, *ser_status = NULL; const char *serialfile = NULL, *subj = NULL; char *prog, *startdate = NULL, *enddate = NULL; @@ -251,11 +289,12 @@ int ca_main(int argc, char **argv) char *const *pp; const char *p; size_t outdirlen = 0; - int create_ser = 0, free_key = 0, total = 0, total_done = 0; + int create_ser = 0, free_passin = 0, total = 0, total_done = 0; int batch = 0, default_op = 1, doupdatedb = 0, ext_copy = EXT_COPY_NONE; - int keyformat = FORMAT_PEM, multirdn = 0, notext = 0, output_der = 0; + int keyformat = FORMAT_UNDEF, multirdn = 1, notext = 0, output_der = 0; int ret = 1, email_dn = 1, req = 0, verbose = 0, gencrl = 0, dorevoke = 0; - int rand_ser = 0, i, j, selfsign = 0, def_nid, def_ret; + int rand_ser = 0, i, j, selfsign = 0, def_ret; + char *crl_lastupdate = NULL, *crl_nextupdate = NULL; long crldays = 0, crlhours = 0, crlsec = 0, days = 0; unsigned long chtype = MBSTRING_ASC, certopt = 0; X509 *x509 = NULL, *x509p = NULL, *x = NULL; @@ -279,9 +318,17 @@ opthelp: req = 1; infile = opt_arg(); break; + case OPT_INFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) + goto opthelp; + break; case OPT_OUT: outfile = opt_arg(); break; + case OPT_DATEOPT: + if (!set_dateopt(&dateopt, opt_arg())) + goto opthelp; + break; case OPT_VERBOSE: verbose = 1; break; @@ -305,7 +352,7 @@ opthelp: create_ser = 1; break; case OPT_MULTIVALUE_RDN: - multirdn = 1; + /* obsolete */ break; case OPT_STARTDATE: startdate = opt_arg(); @@ -317,7 +364,7 @@ opthelp: days = atoi(opt_arg()); break; case OPT_MD: - md = opt_arg(); + dgst = opt_arg(); break; case OPT_POLICY: policy = opt_arg(); @@ -336,12 +383,20 @@ opthelp: if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_KEY: - key = opt_arg(); + passin = opt_arg(); break; case OPT_CERT: certfile = opt_arg(); break; + case OPT_CERTFORM: + if (!opt_format(opt_arg(), OPT_FMT_ANY, &certformat)) + goto opthelp; + break; case OPT_SELFSIGN: selfsign = 1; break; @@ -354,6 +409,12 @@ opthelp: if (sigopts == NULL || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) goto end; break; + case OPT_VFYOPT: + if (vfyopts == NULL) + vfyopts = sk_OPENSSL_STRING_new_null(); + if (vfyopts == NULL || !sk_OPENSSL_STRING_push(vfyopts, opt_arg())) + goto end; + break; case OPT_NOTEXT: notext = 1; break; @@ -372,6 +433,12 @@ opthelp: case OPT_MSIE_HACK: msie_hack = 1; break; + case OPT_CRL_LASTUPDATE: + crl_lastupdate = opt_arg(); + break; + case OPT_CRL_NEXTUPDATE: + crl_nextupdate = opt_arg(); + break; case OPT_CRLDAYS: crldays = atol(opt_arg()); break; @@ -427,13 +494,13 @@ opthelp: break; } } + end_of_options: + /* Remaining args are files to certify. */ argc = opt_num_rest(); argv = opt_rest(); - BIO_printf(bio_err, "Using configuration from %s\n", configfile); - - if ((conf = app_load_config(configfile)) == NULL) + if ((conf = app_load_config_verbose(configfile, 1)) == NULL) goto end; if (configfile != default_config_file && !app_load_modules(conf)) goto end; @@ -456,12 +523,12 @@ end_of_options: BIO_free(oid_bio); } } - if (!add_oid_section(conf)) { - ERR_print_errors(bio_err); + if (!add_oid_section(conf)) goto end; - } app_RAND_load_conf(conf, BASE_SECTION); + if (!app_RAND_load()) + goto end; f = NCONF_get_string(conf, section, STRING_MASK); if (f == NULL) @@ -495,8 +562,10 @@ end_of_options: goto end; db = load_index(dbfile, &db_attr); - if (db == NULL) + if (db == NULL) { + BIO_printf(bio_err, "Problem with index file: %s (could not load/parse file)\n", dbfile); goto end; + } if (index_index(db) <= 0) goto end; @@ -513,16 +582,15 @@ end_of_options: && (keyfile = lookup_conf(conf, section, ENV_PRIVATE_KEY)) == NULL) goto end; - if (key == NULL) { - free_key = 1; - if (!app_passwd(passinarg, NULL, &key, NULL)) { + if (passin == NULL) { + free_passin = 1; + if (!app_passwd(passinarg, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } } - pkey = load_key(keyfile, keyformat, 0, key, e, "CA private key"); - if (key != NULL) - OPENSSL_cleanse(key, strlen(key)); + pkey = load_key(keyfile, keyformat, 0, passin, e, "CA private key"); + cleanse(passin); if (pkey == NULL) /* load_key() has already printed an appropriate message */ goto end; @@ -534,7 +602,7 @@ end_of_options: && (certfile = lookup_conf(conf, section, ENV_CERTIFICATE)) == NULL) goto end; - x509 = load_cert(certfile, FORMAT_PEM, "CA certificate"); + x509 = load_cert_pass(certfile, certformat, 1, passin, "CA certificate"); if (x509 == NULL) goto end; @@ -624,8 +692,10 @@ end_of_options: goto end; db = load_index(dbfile, &db_attr); - if (db == NULL) + if (db == NULL) { + BIO_printf(bio_err, "Problem with index file: %s (could not load/parse file)\n", dbfile); goto end; + } /* Lets check some fields */ for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { @@ -703,7 +773,7 @@ end_of_options: /*****************************************************************/ /* Read extensions config file */ if (extfile) { - if ((extconf = app_load_config(extfile)) == NULL) { + if ((extfile_conf = app_load_config(extfile)) == NULL) { ret = 1; goto end; } @@ -714,7 +784,7 @@ end_of_options: /* We can have sections in the ext file */ if (extensions == NULL) { - extensions = NCONF_get_string(extconf, "default", "extensions"); + extensions = NCONF_get_string(extfile_conf, "default", "extensions"); if (extensions == NULL) extensions = "default"; } @@ -728,28 +798,25 @@ end_of_options: } } - def_ret = EVP_PKEY_get_default_digest_nid(pkey, &def_nid); + def_ret = EVP_PKEY_get_default_digest_name(pkey, def_dgst, sizeof(def_dgst)); /* - * EVP_PKEY_get_default_digest_nid() returns 2 if the digest is + * EVP_PKEY_get_default_digest_name() returns 2 if the digest is * mandatory for this algorithm. */ - if (def_ret == 2 && def_nid == NID_undef) { + if (def_ret == 2 && strcmp(def_dgst, "UNDEF") == 0) { /* The signing algorithm requires there to be no digest */ - dgst = EVP_md_null(); - } else if (md == NULL - && (md = lookup_conf(conf, section, ENV_DEFAULT_MD)) == NULL) { + dgst = NULL; + } else if (dgst == NULL + && (dgst = lookup_conf(conf, section, ENV_DEFAULT_MD)) == NULL) { goto end; } else { - if (strcmp(md, "default") == 0) { + if (strcmp(dgst, "default") == 0) { if (def_ret <= 0) { BIO_puts(bio_err, "no default digest\n"); goto end; } - md = (char *)OBJ_nid2sn(def_nid); + dgst = def_dgst; } - - if (!opt_md(md, &dgst)) - goto end; } if (req) { @@ -761,8 +828,7 @@ end_of_options: email_dn = 0; } if (verbose) - BIO_printf(bio_err, "message digest is %s\n", - OBJ_nid2ln(EVP_MD_type(dgst))); + BIO_printf(bio_err, "message digest is %s\n", dgst); if (policy == NULL && (policy = lookup_conf(conf, section, ENV_POLICY)) == NULL) goto end; @@ -778,7 +844,20 @@ end_of_options: goto end; } - if (extconf == NULL) { + if (extfile_conf != NULL) { + /* Check syntax of extfile */ + X509V3_CTX ctx; + + X509V3_set_ctx_test(&ctx); + X509V3_set_nconf(&ctx, extfile_conf); + if (!X509V3_EXT_add_nconf(extfile_conf, &ctx, extensions, NULL)) { + BIO_printf(bio_err, + "Error checking certificate extensions from extfile section %s\n", + extensions); + ret = 1; + goto end; + } + } else { /* * no '-extfile' option, so we look for extensions in the main * configuration file @@ -789,13 +868,14 @@ end_of_options: ERR_clear_error(); } if (extensions != NULL) { - /* Check syntax of file */ + /* Check syntax of config file section */ X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); X509V3_set_nconf(&ctx, conf); if (!X509V3_EXT_add_nconf(conf, &ctx, extensions, NULL)) { BIO_printf(bio_err, - "Error Loading extension section %s\n", + "Error checking certificate extension config section %s\n", extensions); ret = 1; goto end; @@ -874,7 +954,7 @@ end_of_options: attribs, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, extensions, conf, verbose, certopt, get_nameopt(), default_op, - ext_copy); + ext_copy, dateopt); if (j < 0) goto end; if (j > 0) { @@ -890,12 +970,12 @@ end_of_options: } if (ss_cert_file != NULL) { total++; - j = certify_cert(&x, ss_cert_file, pkey, x509, dgst, sigopts, - attribs, + j = certify_cert(&x, ss_cert_file, certformat, passin, pkey, + x509, dgst, sigopts, vfyopts, attribs, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, extensions, conf, verbose, certopt, get_nameopt(), default_op, - ext_copy); + ext_copy, dateopt); if (j < 0) goto end; if (j > 0) { @@ -911,10 +991,11 @@ end_of_options: } if (infile != NULL) { total++; - j = certify(&x, infile, pkey, x509p, dgst, sigopts, attribs, db, + j = certify(&x, infile, informat, pkey, x509p, dgst, + sigopts, vfyopts, attribs, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, extensions, conf, verbose, - certopt, get_nameopt(), default_op, ext_copy, selfsign); + certopt, get_nameopt(), default_op, ext_copy, selfsign, dateopt); if (j < 0) goto end; if (j > 0) { @@ -930,10 +1011,12 @@ end_of_options: } for (i = 0; i < argc; i++) { total++; - j = certify(&x, argv[i], pkey, x509p, dgst, sigopts, attribs, db, + j = certify(&x, argv[i], informat, pkey, x509p, dgst, + sigopts, vfyopts, + attribs, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, extensions, conf, verbose, - certopt, get_nameopt(), default_op, ext_copy, selfsign); + certopt, get_nameopt(), default_op, ext_copy, selfsign, dateopt); if (j < 0) goto end; if (j > 0) { @@ -996,7 +1079,7 @@ end_of_options: for (i = 0; i < sk_X509_num(cert_sk); i++) { BIO *Cout = NULL; X509 *xi = sk_X509_value(cert_sk, i); - ASN1_INTEGER *serialNumber = X509_get_serialNumber(xi); + const ASN1_INTEGER *serialNumber = X509_get0_serialNumber(xi); const unsigned char *psn = ASN1_STRING_get0_data(serialNumber); const int snl = ASN1_STRING_length(serialNumber); const int filen_len = 2 * (snl > 0 ? snl : 1) + sizeof(".pem"); @@ -1067,11 +1150,12 @@ end_of_options: if (crl_ext != NULL) { /* Check syntax of file */ X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); X509V3_set_nconf(&ctx, conf); if (!X509V3_EXT_add_nconf(conf, &ctx, crl_ext, NULL)) { BIO_printf(bio_err, - "Error Loading CRL extension section %s\n", crl_ext); + "Error checking CRL extension section %s\n", crl_ext); ret = 1; goto end; } @@ -1094,7 +1178,8 @@ end_of_options: crlhours = 0; ERR_clear_error(); } - if ((crldays == 0) && (crlhours == 0) && (crlsec == 0)) { + if ((crl_nextupdate == NULL) && + (crldays == 0) && (crlhours == 0) && (crlsec == 0)) { BIO_printf(bio_err, "cannot lookup how long until the next CRL is issued\n"); goto end; @@ -1102,24 +1187,23 @@ end_of_options: if (verbose) BIO_printf(bio_err, "making CRL\n"); - if ((crl = X509_CRL_new()) == NULL) + if ((crl = X509_CRL_new_ex(app_get0_libctx(), app_get0_propq())) == NULL) goto end; if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509))) goto end; - tmptm = ASN1_TIME_new(); - if (tmptm == NULL - || X509_gmtime_adj(tmptm, 0) == NULL - || !X509_CRL_set1_lastUpdate(crl, tmptm) - || X509_time_adj_ex(tmptm, crldays, crlhours * 60 * 60 + crlsec, - NULL) == NULL) { - BIO_puts(bio_err, "error setting CRL nextUpdate\n"); - ASN1_TIME_free(tmptm); + if (!set_crl_lastupdate(crl, crl_lastupdate)) { + BIO_puts(bio_err, "error setting CRL lastUpdate\n"); + ret = 1; goto end; } - X509_CRL_set1_nextUpdate(crl, tmptm); - ASN1_TIME_free(tmptm); + if (!set_crl_nextupdate(crl, crl_nextupdate, + crldays, crlhours, crlsec)) { + BIO_puts(bio_err, "error setting CRL nextUpdate\n"); + ret = 1; + goto end; + } for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { pp = sk_OPENSSL_PSTRING_value(db->db->data, i); @@ -1157,12 +1241,16 @@ end_of_options: if (crl_ext != NULL || crlnumberfile != NULL) { X509V3_CTX crlctx; + X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0); X509V3_set_nconf(&crlctx, conf); if (crl_ext != NULL) - if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, crl_ext, crl)) + if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, crl_ext, crl)) { + BIO_printf(bio_err, + "Error adding CRL extensions from section %s\n", crl_ext); goto end; + } if (crlnumberfile != NULL) { tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL); if (!tmpser) @@ -1175,8 +1263,8 @@ end_of_options: } } if (crl_ext != NULL || crl_v2) { - if (!X509_CRL_set_version(crl, 1)) - goto end; /* version 2 CRL */ + if (!X509_CRL_set_version(crl, X509_CRL_VERSION_2)) + goto end; } /* we have a CRL number that need updating */ @@ -1210,7 +1298,9 @@ end_of_options: goto end; } else { X509 *revcert; - revcert = load_cert(infile, FORMAT_PEM, infile); + + revcert = load_cert_pass(infile, informat, 1, passin, + "certificate to be revoked"); if (revcert == NULL) goto end; if (dorevoke == 2) @@ -1239,17 +1329,19 @@ end_of_options: BIO_free_all(in); sk_X509_pop_free(cert_sk, X509_free); - if (free_key) - OPENSSL_free(key); + cleanse(passin); + if (free_passin) + OPENSSL_free(passin); BN_free(serial); BN_free(crlnumber); free_index(db); sk_OPENSSL_STRING_free(sigopts); + sk_OPENSSL_STRING_free(vfyopts); EVP_PKEY_free(pkey); X509_free(x509); X509_CRL_free(crl); NCONF_free(conf); - NCONF_free(extconf); + NCONF_free(extfile_conf); release_engine(e); return ret; } @@ -1262,101 +1354,94 @@ static char *lookup_conf(const CONF *conf, const char *section, const char *tag) return entry; } -static int certify(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, - const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, +static int certify(X509 **xret, const char *infile, int informat, + EVP_PKEY *pkey, X509 *x509, + const char *dgst, + STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(OPENSSL_STRING) *vfyopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, int batch, const char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, unsigned long nameopt, - int default_op, int ext_copy, int selfsign) + int default_op, int ext_copy, int selfsign, unsigned long dateopt) { X509_REQ *req = NULL; - BIO *in = NULL; EVP_PKEY *pktmp = NULL; int ok = -1, i; - in = BIO_new_file(infile, "r"); - if (in == NULL) { - ERR_print_errors(bio_err); + req = load_csr(infile, informat, "certificate request"); + if (req == NULL) goto end; - } - if ((req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL)) == NULL) { - BIO_printf(bio_err, "Error reading certificate request in %s\n", - infile); + if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL) { + BIO_printf(bio_err, "Error unpacking public key\n"); goto end; } if (verbose) X509_REQ_print_ex(bio_err, req, nameopt, X509_FLAG_COMPAT); BIO_printf(bio_err, "Check that the request matches the signature\n"); + ok = 0; if (selfsign && !X509_REQ_check_private_key(req, pkey)) { BIO_printf(bio_err, "Certificate request and CA private key do not match\n"); - ok = 0; - goto end; - } - if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL) { - BIO_printf(bio_err, "error unpacking public key\n"); goto end; } - i = X509_REQ_verify(req, pktmp); - pktmp = NULL; + i = do_X509_REQ_verify(req, pktmp, vfyopts); if (i < 0) { - ok = 0; - BIO_printf(bio_err, "Signature verification problems....\n"); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Signature verification problems...\n"); goto end; } if (i == 0) { - ok = 0; BIO_printf(bio_err, "Signature did not match the certificate request\n"); - ERR_print_errors(bio_err); goto end; - } else { - BIO_printf(bio_err, "Signature ok\n"); } + BIO_printf(bio_err, "Signature ok\n"); ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, verbose, req, ext_sect, lconf, certopt, nameopt, default_op, - ext_copy, selfsign); + ext_copy, selfsign, dateopt); end: + ERR_print_errors(bio_err); X509_REQ_free(req); - BIO_free(in); return ok; } -static int certify_cert(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x509, - const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, +static int certify_cert(X509 **xret, const char *infile, int certformat, + const char *passin, EVP_PKEY *pkey, X509 *x509, + const char *dgst, + STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(OPENSSL_STRING) *vfyopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, int batch, const char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, - unsigned long nameopt, int default_op, int ext_copy) + unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt) { - X509 *req = NULL; + X509 *template_cert = NULL; X509_REQ *rreq = NULL; EVP_PKEY *pktmp = NULL; int ok = -1, i; - if ((req = load_cert(infile, FORMAT_PEM, infile)) == NULL) + if ((template_cert = load_cert_pass(infile, certformat, 1, passin, + "template certificate")) == NULL) goto end; if (verbose) - X509_print(bio_err, req); + X509_print(bio_err, template_cert); BIO_printf(bio_err, "Check that the request matches the signature\n"); - if ((pktmp = X509_get0_pubkey(req)) == NULL) { + if ((pktmp = X509_get0_pubkey(template_cert)) == NULL) { BIO_printf(bio_err, "error unpacking public key\n"); goto end; } - i = X509_verify(req, pktmp); + i = do_X509_verify(template_cert, pktmp, vfyopts); if (i < 0) { ok = 0; BIO_printf(bio_err, "Signature verification problems....\n"); @@ -1370,30 +1455,31 @@ static int certify_cert(X509 **xret, const char *infile, EVP_PKEY *pkey, X509 *x BIO_printf(bio_err, "Signature ok\n"); } - if ((rreq = X509_to_X509_REQ(req, NULL, NULL)) == NULL) + if ((rreq = X509_to_X509_REQ(template_cert, NULL, NULL)) == NULL) goto end; ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, verbose, rreq, ext_sect, lconf, certopt, nameopt, default_op, - ext_copy, 0); + ext_copy, 0, dateopt); end: X509_REQ_free(rreq); - X509_free(req); + X509_free(template_cert); return ok; } static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, - const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, + const char *dgst, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, int batch, int verbose, X509_REQ *req, const char *ext_sect, CONF *lconf, unsigned long certopt, unsigned long nameopt, - int default_op, int ext_copy, int selfsign) + int default_op, int ext_copy, int selfsign, unsigned long dateopt) { - X509_NAME *name = NULL, *CAname = NULL, *subject = NULL; + const X509_NAME *name = NULL; + X509_NAME *CAname = NULL, *subject = NULL; const ASN1_TIME *tm; ASN1_STRING *str, *str2; ASN1_OBJECT *obj; @@ -1407,17 +1493,16 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, OPENSSL_STRING *irow = NULL; OPENSSL_STRING *rrow = NULL; char buf[25]; + X509V3_CTX ext_ctx; for (i = 0; i < DB_NUMBER; i++) row[i] = NULL; if (subj) { - X509_NAME *n = parse_name(subj, chtype, multirdn); + X509_NAME *n = parse_name(subj, chtype, multirdn, "subject"); - if (!n) { - ERR_print_errors(bio_err); + if (!n) goto end; - } X509_REQ_set_subject_name(req, n); X509_NAME_free(n); } @@ -1592,15 +1677,9 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, BIO_printf(bio_err, "Everything appears to be ok, creating and signing the certificate\n"); - if ((ret = X509_new()) == NULL) + if ((ret = X509_new_ex(app_get0_libctx(), app_get0_propq())) == NULL) goto end; -#ifdef X509_V3 - /* Make it an X509 v3 certificate. */ - if (!X509_set_version(ret, 2)) - goto end; -#endif - if (BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(ret)) == NULL) goto end; if (selfsign) { @@ -1630,32 +1709,24 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, if (!i) goto end; + /* Initialize the context structure */ + X509V3_set_ctx(&ext_ctx, selfsign ? ret : x509, + ret, req, NULL, X509V3_CTX_REPLACE); + /* Lets add the extensions, if there are any */ if (ext_sect) { - X509V3_CTX ctx; - - /* Initialize the context structure */ - if (selfsign) - X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0); - else - X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); - - if (extconf != NULL) { + if (extfile_conf != NULL) { if (verbose) BIO_printf(bio_err, "Extra configuration file found\n"); - /* Use the extconf configuration db LHASH */ - X509V3_set_nconf(&ctx, extconf); - - /* Test the structure (needed?) */ - /* X509V3_set_ctx_test(&ctx); */ + /* Use the extfile_conf configuration db LHASH */ + X509V3_set_nconf(&ext_ctx, extfile_conf); /* Adds exts contained in the configuration file */ - if (!X509V3_EXT_add_nconf(extconf, &ctx, ext_sect, ret)) { + if (!X509V3_EXT_add_nconf(extfile_conf, &ext_ctx, ext_sect, ret)) { BIO_printf(bio_err, - "ERROR: adding extensions in section %s\n", + "Error adding certificate extensions from extfile section %s\n", ext_sect); - ERR_print_errors(bio_err); goto end; } if (verbose) @@ -1663,13 +1734,12 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, "Successfully added extensions from file.\n"); } else if (ext_sect) { /* We found extensions to be set from config file */ - X509V3_set_nconf(&ctx, lconf); + X509V3_set_nconf(&ext_ctx, lconf); - if (!X509V3_EXT_add_nconf(lconf, &ctx, ext_sect, ret)) { + if (!X509V3_EXT_add_nconf(lconf, &ext_ctx, ext_sect, ret)) { BIO_printf(bio_err, - "ERROR: adding extensions in section %s\n", + "Error adding certificate extensions from config section %s\n", ext_sect); - ERR_print_errors(bio_err); goto end; } @@ -1683,19 +1753,9 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, if (!copy_extensions(ret, req, ext_copy)) { BIO_printf(bio_err, "ERROR: adding extensions from request\n"); - ERR_print_errors(bio_err); goto end; } - { - const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(ret); - - if (exts != NULL && sk_X509_EXTENSION_num(exts) > 0) - /* Make it an X509 v3 certificate. */ - if (!X509_set_version(ret, 2)) - goto end; - } - if (verbose) BIO_printf(bio_err, "The subject name appears to be ok, checking data base for clashes\n"); @@ -1825,7 +1885,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, } BIO_printf(bio_err, "Certificate is to be certified until "); - ASN1_TIME_print(bio_err, X509_get0_notAfter(ret)); + ASN1_TIME_print_ex(bio_err, X509_get0_notAfter(ret), dateopt); if (days) BIO_printf(bio_err, " (%ld days)", days); BIO_printf(bio_err, "\n"); @@ -1853,7 +1913,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, !EVP_PKEY_missing_parameters(pkey)) EVP_PKEY_copy_parameters(pktmp, pkey); - if (!do_X509_sign(ret, pkey, dgst, sigopts)) + if (!do_X509_sign(ret, pkey, dgst, sigopts, &ext_ctx)) goto end; /* We now just add it to the database as DB_TYPE_VAL('V') */ @@ -1911,14 +1971,14 @@ static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext) } static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, - X509 *x509, const EVP_MD *dgst, + X509 *x509, const char *dgst, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, const char *subj, unsigned long chtype, int multirdn, int email_dn, const char *startdate, const char *enddate, long days, const char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, - unsigned long nameopt, int default_op, int ext_copy) + unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt) { STACK_OF(CONF_VALUE) *sk = NULL; LHASH_OF(CONF_VALUE) *parms = NULL; @@ -1941,7 +2001,6 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, parms = CONF_load(NULL, infile, &errline); if (parms == NULL) { BIO_printf(bio_err, "error on line %ld of %s\n", errline, infile); - ERR_print_errors(bio_err); goto end; } @@ -1959,10 +2018,8 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, * and we can use the same code as if you had a real X509 request. */ req = X509_REQ_new(); - if (req == NULL) { - ERR_print_errors(bio_err); + if (req == NULL) goto end; - } /* * Build up the subject name set. @@ -1993,7 +2050,6 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, if (spki == NULL) { BIO_printf(bio_err, "unable to load Netscape SPKAC structure\n"); - ERR_print_errors(bio_err); goto end; } } @@ -2035,7 +2091,7 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey, ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj, chtype, multirdn, email_dn, startdate, enddate, days, 1, verbose, req, ext_sect, lconf, certopt, nameopt, default_op, - ext_copy, 0); + ext_copy, 0, dateopt); end: X509_REQ_free(req); CONF_free(parms); @@ -2062,7 +2118,7 @@ static int do_revoke(X509 *x509, CA_DB *db, REVINFO_TYPE rev_type, for (i = 0; i < DB_NUMBER; i++) row[i] = NULL; row[DB_name] = X509_NAME_oneline(X509_get_subject_name(x509), NULL, 0); - bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(x509), NULL); + bn = ASN1_INTEGER_to_BN(X509_get0_serialNumber(x509), NULL); if (!bn) goto end; if (BN_is_zero(bn)) @@ -2313,7 +2369,7 @@ static char *make_revocation_str(REVINFO_TYPE rev_type, const char *rev_arg) case REV_CRL_REASON: for (i = 0; i < 8; i++) { - if (strcasecmp(rev_arg, crl_reasons[i]) == 0) { + if (OPENSSL_strcasecmp(rev_arg, crl_reasons[i]) == 0) { reason = crl_reasons[i]; break; } @@ -2413,18 +2469,18 @@ static int make_revoked(X509_REVOKED *rev, const char *str) rtmp = ASN1_ENUMERATED_new(); if (rtmp == NULL || !ASN1_ENUMERATED_set(rtmp, reason_code)) goto end; - if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0)) + if (X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0) <= 0) goto end; } if (rev && comp_time) { - if (!X509_REVOKED_add1_ext_i2d - (rev, NID_invalidity_date, comp_time, 0, 0)) + if (X509_REVOKED_add1_ext_i2d + (rev, NID_invalidity_date, comp_time, 0, 0) <= 0) goto end; } if (rev && hold) { - if (!X509_REVOKED_add1_ext_i2d - (rev, NID_hold_instruction_code, hold, 0, 0)) + if (X509_REVOKED_add1_ext_i2d + (rev, NID_hold_instruction_code, hold, 0, 0) <= 0) goto end; } @@ -2530,7 +2586,7 @@ int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, } if (reason_str) { for (i = 0; i < NUM_REASONS; i++) { - if (strcasecmp(reason_str, crl_reasons[i]) == 0) { + if (OPENSSL_strcasecmp(reason_str, crl_reasons[i]) == 0) { reason_code = i; break; } diff --git a/apps/ciphers.c b/apps/ciphers.c index aade3fbf5671..42a0bb79f651 100644 --- a/apps/ciphers.c +++ b/apps/ciphers.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,9 +14,10 @@ #include "progs.h" #include <openssl/err.h> #include <openssl/ssl.h> +#include "s_apps.h" typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_STDNAME, OPT_CONVERT, OPT_SSL3, @@ -27,39 +28,50 @@ typedef enum OPTION_choice { OPT_PSK, OPT_SRP, OPT_CIPHERSUITES, - OPT_V, OPT_UPPER_V, OPT_S + OPT_V, OPT_UPPER_V, OPT_S, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS ciphers_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cipher]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_SECTION("Output"), {"v", OPT_V, '-', "Verbose listing of the SSL/TLS ciphers"}, {"V", OPT_UPPER_V, '-', "Even more verbose"}, + {"stdname", OPT_STDNAME, '-', "Show standard cipher names"}, + {"convert", OPT_CONVERT, 's', "Convert standard name into OpenSSL name"}, + + OPT_SECTION("Cipher specification"), {"s", OPT_S, '-', "Only supported ciphers"}, #ifndef OPENSSL_NO_SSL3 - {"ssl3", OPT_SSL3, '-', "SSL3 mode"}, + {"ssl3", OPT_SSL3, '-', "Ciphers compatible with SSL3"}, #endif #ifndef OPENSSL_NO_TLS1 - {"tls1", OPT_TLS1, '-', "TLS1 mode"}, + {"tls1", OPT_TLS1, '-', "Ciphers compatible with TLS1"}, #endif #ifndef OPENSSL_NO_TLS1_1 - {"tls1_1", OPT_TLS1_1, '-', "TLS1.1 mode"}, + {"tls1_1", OPT_TLS1_1, '-', "Ciphers compatible with TLS1.1"}, #endif #ifndef OPENSSL_NO_TLS1_2 - {"tls1_2", OPT_TLS1_2, '-', "TLS1.2 mode"}, + {"tls1_2", OPT_TLS1_2, '-', "Ciphers compatible with TLS1.2"}, #endif #ifndef OPENSSL_NO_TLS1_3 - {"tls1_3", OPT_TLS1_3, '-', "TLS1.3 mode"}, + {"tls1_3", OPT_TLS1_3, '-', "Ciphers compatible with TLS1.3"}, #endif - {"stdname", OPT_STDNAME, '-', "Show standard cipher names"}, #ifndef OPENSSL_NO_PSK - {"psk", OPT_PSK, '-', "include ciphersuites requiring PSK"}, + {"psk", OPT_PSK, '-', "Include ciphersuites requiring PSK"}, #endif #ifndef OPENSSL_NO_SRP - {"srp", OPT_SRP, '-', "include ciphersuites requiring SRP"}, + {"srp", OPT_SRP, '-', "(deprecated) Include ciphersuites requiring SRP"}, #endif - {"convert", OPT_CONVERT, 's', "Convert standard name into OpenSSL name"}, {"ciphersuites", OPT_CIPHERSUITES, 's', "Configure the TLSv1.3 ciphersuites to use"}, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"cipher", 0, 0, "Cipher string to decode (optional)"}, {NULL} }; @@ -72,12 +84,6 @@ static unsigned int dummy_psk(SSL *ssl, const char *hint, char *identity, return 0; } #endif -#ifndef OPENSSL_NO_SRP -static char *dummy_srp(SSL *ssl, void *arg) -{ - return ""; -} -#endif int ciphers_main(int argc, char **argv) { @@ -159,13 +165,18 @@ int ciphers_main(int argc, char **argv) case OPT_CIPHERSUITES: ciphersuites = opt_arg(); break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* Optional arg is cipher name. */ argv = opt_rest(); argc = opt_num_rest(); - if (argc == 1) - ciphers = *argv; + ciphers = argv[0]; else if (argc != 0) goto opthelp; @@ -176,7 +187,7 @@ int ciphers_main(int argc, char **argv) goto end; } - ctx = SSL_CTX_new(meth); + ctx = SSL_CTX_new_ex(app_get0_libctx(), app_get0_propq(), meth); if (ctx == NULL) goto err; if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) @@ -190,7 +201,7 @@ int ciphers_main(int argc, char **argv) #endif #ifndef OPENSSL_NO_SRP if (srp) - SSL_CTX_set_srp_client_pwd_callback(ctx, dummy_srp); + set_up_dummy_srp(ctx); #endif if (ciphersuites != NULL && !SSL_CTX_set_ciphersuites(ctx, ciphersuites)) { @@ -216,6 +227,10 @@ int ciphers_main(int argc, char **argv) if (!verbose) { for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i); + + if (!ossl_assert(c != NULL)) + continue; + p = SSL_CIPHER_get_name(c); if (p == NULL) break; @@ -231,6 +246,9 @@ int ciphers_main(int argc, char **argv) c = sk_SSL_CIPHER_value(sk, i); + if (!ossl_assert(c != NULL)) + continue; + if (Verbose) { unsigned long id = SSL_CIPHER_get_id(c); int id0 = (int)(id >> 24); @@ -248,7 +266,7 @@ int ciphers_main(int argc, char **argv) const char *nm = SSL_CIPHER_standard_name(c); if (nm == NULL) nm = "UNKNOWN"; - BIO_printf(bio_out, "%s - ", nm); + BIO_printf(bio_out, "%-45s - ", nm); } BIO_puts(bio_out, SSL_CIPHER_description(c, buf, sizeof(buf))); } diff --git a/apps/cmp.c b/apps/cmp.c new file mode 100644 index 000000000000..9b9e405bb248 --- /dev/null +++ b/apps/cmp.c @@ -0,0 +1,3023 @@ +/* + * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2019 + * Copyright Siemens AG 2015-2019 + * + * 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 + */ + +/* This app is disabled when OPENSSL_NO_CMP is defined. */ + +#include <string.h> +#include <ctype.h> + +#include "apps.h" +#include "http_server.h" +#include "s_apps.h" +#include "progs.h" + +#include "cmp_mock_srv.h" + +/* tweaks needed due to missing unistd.h on Windows */ +#if defined(_WIN32) && !defined(__BORLANDC__) +# define access _access +#endif +#ifndef F_OK +# define F_OK 0 +#endif + +#include <openssl/ui.h> +#include <openssl/pkcs12.h> +#include <openssl/ssl.h> + +/* explicit #includes not strictly needed since implied by the above: */ +#include <stdlib.h> +#include <openssl/cmp.h> +#include <openssl/cmp_util.h> +#include <openssl/crmf.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/store.h> +#include <openssl/objects.h> +#include <openssl/x509.h> + +static char *prog; +static char *opt_config = NULL; +#define CMP_SECTION "cmp" +#define SECTION_NAME_MAX 40 /* max length of section name */ +#define DEFAULT_SECTION "default" +static char *opt_section = CMP_SECTION; +static int opt_verbosity = OSSL_CMP_LOG_INFO; + +static int read_config(void); + +static CONF *conf = NULL; /* OpenSSL config file context structure */ +static OSSL_CMP_CTX *cmp_ctx = NULL; /* the client-side CMP context */ + +/* the type of cmp command we want to send */ +typedef enum { + CMP_IR, + CMP_KUR, + CMP_CR, + CMP_P10CR, + CMP_RR, + CMP_GENM +} cmp_cmd_t; + +/* message transfer */ +#ifndef OPENSSL_NO_SOCK +static char *opt_server = NULL; +static char *opt_proxy = NULL; +static char *opt_no_proxy = NULL; +#endif +static char *opt_recipient = NULL; +static char *opt_path = NULL; +static int opt_keep_alive = 1; +static int opt_msg_timeout = -1; +static int opt_total_timeout = -1; + +/* server authentication */ +static char *opt_trusted = NULL; +static char *opt_untrusted = NULL; +static char *opt_srvcert = NULL; +static char *opt_expect_sender = NULL; +static int opt_ignore_keyusage = 0; +static int opt_unprotected_errors = 0; +static char *opt_extracertsout = NULL; +static char *opt_cacertsout = NULL; + +/* client authentication */ +static char *opt_ref = NULL; +static char *opt_secret = NULL; +static char *opt_cert = NULL; +static char *opt_own_trusted = NULL; +static char *opt_key = NULL; +static char *opt_keypass = NULL; +static char *opt_digest = NULL; +static char *opt_mac = NULL; +static char *opt_extracerts = NULL; +static int opt_unprotected_requests = 0; + +/* generic message */ +static char *opt_cmd_s = NULL; +static int opt_cmd = -1; +static char *opt_geninfo = NULL; +static char *opt_infotype_s = NULL; +static int opt_infotype = NID_undef; + +/* certificate enrollment */ +static char *opt_newkey = NULL; +static char *opt_newkeypass = NULL; +static char *opt_subject = NULL; +static char *opt_issuer = NULL; +static int opt_days = 0; +static char *opt_reqexts = NULL; +static char *opt_sans = NULL; +static int opt_san_nodefault = 0; +static char *opt_policies = NULL; +static char *opt_policy_oids = NULL; +static int opt_policy_oids_critical = 0; +static int opt_popo = OSSL_CRMF_POPO_NONE - 1; +static char *opt_csr = NULL; +static char *opt_out_trusted = NULL; +static int opt_implicit_confirm = 0; +static int opt_disable_confirm = 0; +static char *opt_certout = NULL; +static char *opt_chainout = NULL; + +/* certificate enrollment and revocation */ +static char *opt_oldcert = NULL; +static int opt_revreason = CRL_REASON_NONE; + +/* credentials format */ +static char *opt_certform_s = "PEM"; +static int opt_certform = FORMAT_PEM; +static char *opt_keyform_s = NULL; +static int opt_keyform = FORMAT_UNDEF; +static char *opt_otherpass = NULL; +static char *opt_engine = NULL; + +#ifndef OPENSSL_NO_SOCK +/* TLS connection */ +static int opt_tls_used = 0; +static char *opt_tls_cert = NULL; +static char *opt_tls_key = NULL; +static char *opt_tls_keypass = NULL; +static char *opt_tls_extra = NULL; +static char *opt_tls_trusted = NULL; +static char *opt_tls_host = NULL; +#endif + +/* client-side debugging */ +static int opt_batch = 0; +static int opt_repeat = 1; +static char *opt_reqin = NULL; +static int opt_reqin_new_tid = 0; +static char *opt_reqout = NULL; +static char *opt_rspin = NULL; +static char *opt_rspout = NULL; +static int opt_use_mock_srv = 0; + +/* mock server */ +#ifndef OPENSSL_NO_SOCK +static char *opt_port = NULL; +static int opt_max_msgs = 0; +#endif +static char *opt_srv_ref = NULL; +static char *opt_srv_secret = NULL; +static char *opt_srv_cert = NULL; +static char *opt_srv_key = NULL; +static char *opt_srv_keypass = NULL; + +static char *opt_srv_trusted = NULL; +static char *opt_srv_untrusted = NULL; +static char *opt_rsp_cert = NULL; +static char *opt_rsp_extracerts = NULL; +static char *opt_rsp_capubs = NULL; +static int opt_poll_count = 0; +static int opt_check_after = 1; +static int opt_grant_implicitconf = 0; + +static int opt_pkistatus = OSSL_CMP_PKISTATUS_accepted; +static int opt_failure = INT_MIN; +static int opt_failurebits = 0; +static char *opt_statusstring = NULL; +static int opt_send_error = 0; +static int opt_send_unprotected = 0; +static int opt_send_unprot_err = 0; +static int opt_accept_unprotected = 0; +static int opt_accept_unprot_err = 0; +static int opt_accept_raverified = 0; + +static X509_VERIFY_PARAM *vpm = NULL; + +typedef enum OPTION_choice { + OPT_COMMON, + OPT_CONFIG, OPT_SECTION, OPT_VERBOSITY, + + OPT_CMD, OPT_INFOTYPE, OPT_GENINFO, + + OPT_NEWKEY, OPT_NEWKEYPASS, OPT_SUBJECT, OPT_ISSUER, + OPT_DAYS, OPT_REQEXTS, + OPT_SANS, OPT_SAN_NODEFAULT, + OPT_POLICIES, OPT_POLICY_OIDS, OPT_POLICY_OIDS_CRITICAL, + OPT_POPO, OPT_CSR, + OPT_OUT_TRUSTED, OPT_IMPLICIT_CONFIRM, OPT_DISABLE_CONFIRM, + OPT_CERTOUT, OPT_CHAINOUT, + + OPT_OLDCERT, OPT_REVREASON, + +#ifndef OPENSSL_NO_SOCK + OPT_SERVER, OPT_PROXY, OPT_NO_PROXY, +#endif + OPT_RECIPIENT, OPT_PATH, + OPT_KEEP_ALIVE, OPT_MSG_TIMEOUT, OPT_TOTAL_TIMEOUT, + + OPT_TRUSTED, OPT_UNTRUSTED, OPT_SRVCERT, + OPT_EXPECT_SENDER, + OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS, + OPT_EXTRACERTSOUT, OPT_CACERTSOUT, + + OPT_REF, OPT_SECRET, OPT_CERT, OPT_OWN_TRUSTED, OPT_KEY, OPT_KEYPASS, + OPT_DIGEST, OPT_MAC, OPT_EXTRACERTS, + OPT_UNPROTECTED_REQUESTS, + + OPT_CERTFORM, OPT_KEYFORM, + OPT_OTHERPASS, +#ifndef OPENSSL_NO_ENGINE + OPT_ENGINE, +#endif + OPT_PROV_ENUM, + OPT_R_ENUM, + +#ifndef OPENSSL_NO_SOCK + OPT_TLS_USED, OPT_TLS_CERT, OPT_TLS_KEY, + OPT_TLS_KEYPASS, + OPT_TLS_EXTRA, OPT_TLS_TRUSTED, OPT_TLS_HOST, +#endif + + OPT_BATCH, OPT_REPEAT, + OPT_REQIN, OPT_REQIN_NEW_TID, OPT_REQOUT, OPT_RSPIN, OPT_RSPOUT, + OPT_USE_MOCK_SRV, + +#ifndef OPENSSL_NO_SOCK + OPT_PORT, OPT_MAX_MSGS, +#endif + OPT_SRV_REF, OPT_SRV_SECRET, + OPT_SRV_CERT, OPT_SRV_KEY, OPT_SRV_KEYPASS, + OPT_SRV_TRUSTED, OPT_SRV_UNTRUSTED, + OPT_RSP_CERT, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS, + OPT_POLL_COUNT, OPT_CHECK_AFTER, + OPT_GRANT_IMPLICITCONF, + OPT_PKISTATUS, OPT_FAILURE, + OPT_FAILUREBITS, OPT_STATUSSTRING, + OPT_SEND_ERROR, OPT_SEND_UNPROTECTED, + OPT_SEND_UNPROT_ERR, OPT_ACCEPT_UNPROTECTED, + OPT_ACCEPT_UNPROT_ERR, OPT_ACCEPT_RAVERIFIED, + + OPT_V_ENUM +} OPTION_CHOICE; + +const OPTIONS cmp_options[] = { + /* entries must be in the same order as enumerated above!! */ + {"help", OPT_HELP, '-', "Display this summary"}, + {"config", OPT_CONFIG, 's', + "Configuration file to use. \"\" = none. Default from env variable OPENSSL_CONF"}, + {"section", OPT_SECTION, 's', + "Section(s) in config file to get options from. \"\" = 'default'. Default 'cmp'"}, + {"verbosity", OPT_VERBOSITY, 'N', + "Log level; 3=ERR, 4=WARN, 6=INFO, 7=DEBUG, 8=TRACE. Default 6 = INFO"}, + + OPT_SECTION("Generic message"), + {"cmd", OPT_CMD, 's', "CMP request to send: ir/cr/kur/p10cr/rr/genm"}, + {"infotype", OPT_INFOTYPE, 's', + "InfoType name for requesting specific info in genm, e.g. 'signKeyPairTypes'"}, + {"geninfo", OPT_GENINFO, 's', + "generalInfo integer values to place in request PKIHeader with given OID"}, + {OPT_MORE_STR, 0, 0, + "specified in the form <OID>:int:<n>, e.g. \"1.2.3.4:int:56789\""}, + + OPT_SECTION("Certificate enrollment"), + {"newkey", OPT_NEWKEY, 's', + "Private or public key for the requested cert. Default: CSR key or client key"}, + {"newkeypass", OPT_NEWKEYPASS, 's', "New private key pass phrase source"}, + {"subject", OPT_SUBJECT, 's', + "Distinguished Name (DN) of subject to use in the requested cert template"}, + {OPT_MORE_STR, 0, 0, + "For kur, default is subject of -csr arg or reference cert (see -oldcert)"}, + {OPT_MORE_STR, 0, 0, + "this default is used for ir and cr only if no Subject Alt Names are set"}, + {"issuer", OPT_ISSUER, 's', + "DN of the issuer to place in the requested certificate template"}, + {OPT_MORE_STR, 0, 0, + "also used as recipient if neither -recipient nor -srvcert are given"}, + {"days", OPT_DAYS, 'N', + "Requested validity time of the new certificate in number of days"}, + {"reqexts", OPT_REQEXTS, 's', + "Name of config file section defining certificate request extensions."}, + {OPT_MORE_STR, 0, 0, + "Augments or replaces any extensions contained CSR given with -csr"}, + {"sans", OPT_SANS, 's', + "Subject Alt Names (IPADDR/DNS/URI) to add as (critical) cert req extension"}, + {"san_nodefault", OPT_SAN_NODEFAULT, '-', + "Do not take default SANs from reference certificate (see -oldcert)"}, + {"policies", OPT_POLICIES, 's', + "Name of config file section defining policies certificate request extension"}, + {"policy_oids", OPT_POLICY_OIDS, 's', + "Policy OID(s) to add as policies certificate request extension"}, + {"policy_oids_critical", OPT_POLICY_OIDS_CRITICAL, '-', + "Flag the policy OID(s) given with -policy_oids as critical"}, + {"popo", OPT_POPO, 'n', + "Proof-of-Possession (POPO) method to use for ir/cr/kur where"}, + {OPT_MORE_STR, 0, 0, + "-1 = NONE, 0 = RAVERIFIED, 1 = SIGNATURE (default), 2 = KEYENC"}, + {"csr", OPT_CSR, 's', + "PKCS#10 CSR file in PEM or DER format to convert or to use in p10cr"}, + {"out_trusted", OPT_OUT_TRUSTED, 's', + "Certificates to trust when verifying newly enrolled certificates"}, + {"implicit_confirm", OPT_IMPLICIT_CONFIRM, '-', + "Request implicit confirmation of newly enrolled certificates"}, + {"disable_confirm", OPT_DISABLE_CONFIRM, '-', + "Do not confirm newly enrolled certificate w/o requesting implicit"}, + {OPT_MORE_STR, 0, 0, + "confirmation. WARNING: This leads to behavior violating RFC 4210"}, + {"certout", OPT_CERTOUT, 's', + "File to save newly enrolled certificate"}, + {"chainout", OPT_CHAINOUT, 's', + "File to save the chain of newly enrolled certificate"}, + + OPT_SECTION("Certificate enrollment and revocation"), + + {"oldcert", OPT_OLDCERT, 's', + "Certificate to be updated (defaulting to -cert) or to be revoked in rr;"}, + {OPT_MORE_STR, 0, 0, + "also used as reference (defaulting to -cert) for subject DN and SANs."}, + {OPT_MORE_STR, 0, 0, + "Issuer is used as recipient unless -recipient, -srvcert, or -issuer given"}, + {"revreason", OPT_REVREASON, 'n', + "Reason code to include in revocation request (rr); possible values:"}, + {OPT_MORE_STR, 0, 0, + "0..6, 8..10 (see RFC5280, 5.3.1) or -1. Default -1 = none included"}, + + OPT_SECTION("Message transfer"), +#ifdef OPENSSL_NO_SOCK + {OPT_MORE_STR, 0, 0, + "NOTE: -server, -proxy, and -no_proxy not supported due to no-sock build"}, +#else + {"server", OPT_SERVER, 's', + "[http[s]://]address[:port][/path] of CMP server. Default port 80 or 443."}, + {OPT_MORE_STR, 0, 0, + "address may be a DNS name or an IP address; path can be overridden by -path"}, + {"proxy", OPT_PROXY, 's', + "[http[s]://]address[:port][/path] of HTTP(S) proxy to use; path is ignored"}, + {"no_proxy", OPT_NO_PROXY, 's', + "List of addresses of servers not to use HTTP(S) proxy for"}, + {OPT_MORE_STR, 0, 0, + "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, +#endif + {"recipient", OPT_RECIPIENT, 's', + "DN of CA. Default: subject of -srvcert, -issuer, issuer of -oldcert or -cert"}, + {"path", OPT_PATH, 's', + "HTTP path (aka CMP alias) at the CMP server. Default from -server, else \"/\""}, + {"keep_alive", OPT_KEEP_ALIVE, 'N', + "Persistent HTTP connections. 0: no, 1 (the default): request, 2: require"}, + {"msg_timeout", OPT_MSG_TIMEOUT, 'N', + "Number of seconds allowed per CMP message round trip, or 0 for infinite"}, + {"total_timeout", OPT_TOTAL_TIMEOUT, 'N', + "Overall time an enrollment incl. polling may take. Default 0 = infinite"}, + + OPT_SECTION("Server authentication"), + {"trusted", OPT_TRUSTED, 's', + "Certificates to trust as chain roots when verifying signed CMP responses"}, + {OPT_MORE_STR, 0, 0, "unless -srvcert is given"}, + {"untrusted", OPT_UNTRUSTED, 's', + "Intermediate CA certs for chain construction for CMP/TLS/enrolled certs"}, + {"srvcert", OPT_SRVCERT, 's', + "Server cert to pin and trust directly when verifying signed CMP responses"}, + {"expect_sender", OPT_EXPECT_SENDER, 's', + "DN of expected sender of responses. Defaults to subject of -srvcert, if any"}, + {"ignore_keyusage", OPT_IGNORE_KEYUSAGE, '-', + "Ignore CMP signer cert key usage, else 'digitalSignature' must be allowed"}, + {"unprotected_errors", OPT_UNPROTECTED_ERRORS, '-', + "Accept missing or invalid protection of regular error messages and negative"}, + {OPT_MORE_STR, 0, 0, + "certificate responses (ip/cp/kup), revocation responses (rp), and PKIConf"}, + {OPT_MORE_STR, 0, 0, + "WARNING: This setting leads to behavior allowing violation of RFC 4210"}, + {"extracertsout", OPT_EXTRACERTSOUT, 's', + "File to save extra certificates received in the extraCerts field"}, + {"cacertsout", OPT_CACERTSOUT, 's', + "File to save CA certificates received in the caPubs field of 'ip' messages"}, + + OPT_SECTION("Client authentication"), + {"ref", OPT_REF, 's', + "Reference value to use as senderKID in case no -cert is given"}, + {"secret", OPT_SECRET, 's', + "Prefer PBM (over signatures) for protecting msgs with given password source"}, + {"cert", OPT_CERT, 's', + "Client's CMP signer certificate; its public key must match the -key argument"}, + {OPT_MORE_STR, 0, 0, + "This also used as default reference for subject DN and SANs."}, + {OPT_MORE_STR, 0, 0, + "Any further certs included are appended to the untrusted certs"}, + {"own_trusted", OPT_OWN_TRUSTED, 's', + "Optional certs to verify chain building for own CMP signer cert"}, + {"key", OPT_KEY, 's', "CMP signer private key, not used when -secret given"}, + {"keypass", OPT_KEYPASS, 's', + "Client private key (and cert and old cert) pass phrase source"}, + {"digest", OPT_DIGEST, 's', + "Digest to use in message protection and POPO signatures. Default \"sha256\""}, + {"mac", OPT_MAC, 's', + "MAC algorithm to use in PBM-based message protection. Default \"hmac-sha1\""}, + {"extracerts", OPT_EXTRACERTS, 's', + "Certificates to append in extraCerts field of outgoing messages."}, + {OPT_MORE_STR, 0, 0, + "This can be used as the default CMP signer cert chain to include"}, + {"unprotected_requests", OPT_UNPROTECTED_REQUESTS, '-', + "Send messages without CMP-level protection"}, + + OPT_SECTION("Credentials format"), + {"certform", OPT_CERTFORM, 's', + "Format (PEM or DER) to use when saving a certificate to a file. Default PEM"}, + {"keyform", OPT_KEYFORM, 's', + "Format of the key input (ENGINE, other values ignored)"}, + {"otherpass", OPT_OTHERPASS, 's', + "Pass phrase source potentially needed for loading certificates of others"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', + "Use crypto engine with given identifier, possibly a hardware device."}, + {OPT_MORE_STR, 0, 0, + "Engines may also be defined in OpenSSL config file engine section."}, +#endif + OPT_PROV_OPTIONS, + OPT_R_OPTIONS, + + OPT_SECTION("TLS connection"), +#ifdef OPENSSL_NO_SOCK + {OPT_MORE_STR, 0, 0, + "NOTE: -tls_used and all other TLS options not supported due to no-sock build"}, +#else + {"tls_used", OPT_TLS_USED, '-', + "Enable using TLS (also when other TLS options are not set)"}, + {"tls_cert", OPT_TLS_CERT, 's', + "Client's TLS certificate. May include chain to be provided to TLS server"}, + {"tls_key", OPT_TLS_KEY, 's', + "Private key for the client's TLS certificate"}, + {"tls_keypass", OPT_TLS_KEYPASS, 's', + "Pass phrase source for the client's private TLS key (and TLS cert)"}, + {"tls_extra", OPT_TLS_EXTRA, 's', + "Extra certificates to provide to TLS server during TLS handshake"}, + {"tls_trusted", OPT_TLS_TRUSTED, 's', + "Trusted certificates to use for verifying the TLS server certificate;"}, + {OPT_MORE_STR, 0, 0, "this implies host name validation"}, + {"tls_host", OPT_TLS_HOST, 's', + "Address to be checked (rather than -server) during TLS host name validation"}, +#endif + + OPT_SECTION("Client-side debugging"), + {"batch", OPT_BATCH, '-', + "Do not interactively prompt for input when a password is required etc."}, + {"repeat", OPT_REPEAT, 'p', + "Invoke the transaction the given positive number of times. Default 1"}, + {"reqin", OPT_REQIN, 's', "Take sequence of CMP requests from file(s)"}, + {"reqin_new_tid", OPT_REQIN_NEW_TID, '-', + "Use fresh transactionID for CMP requests read from -reqin"}, + {"reqout", OPT_REQOUT, 's', "Save sequence of CMP requests to file(s)"}, + {"rspin", OPT_RSPIN, 's', + "Process sequence of CMP responses provided in file(s), skipping server"}, + {"rspout", OPT_RSPOUT, 's', "Save sequence of CMP responses to file(s)"}, + + {"use_mock_srv", OPT_USE_MOCK_SRV, '-', + "Use internal mock server at API level, bypassing socket-based HTTP"}, + + OPT_SECTION("Mock server"), +#ifdef OPENSSL_NO_SOCK + {OPT_MORE_STR, 0, 0, + "NOTE: -port and -max_msgs not supported due to no-sock build"}, +#else + {"port", OPT_PORT, 's', + "Act as HTTP-based mock server listening on given port"}, + {"max_msgs", OPT_MAX_MSGS, 'N', + "max number of messages handled by HTTP mock server. Default: 0 = unlimited"}, +#endif + + {"srv_ref", OPT_SRV_REF, 's', + "Reference value to use as senderKID of server in case no -srv_cert is given"}, + {"srv_secret", OPT_SRV_SECRET, 's', + "Password source for server authentication with a pre-shared key (secret)"}, + {"srv_cert", OPT_SRV_CERT, 's', "Certificate of the server"}, + {"srv_key", OPT_SRV_KEY, 's', + "Private key used by the server for signing messages"}, + {"srv_keypass", OPT_SRV_KEYPASS, 's', + "Server private key (and cert) pass phrase source"}, + + {"srv_trusted", OPT_SRV_TRUSTED, 's', + "Trusted certificates for client authentication"}, + {"srv_untrusted", OPT_SRV_UNTRUSTED, 's', + "Intermediate certs that may be useful for verifying CMP protection"}, + {"rsp_cert", OPT_RSP_CERT, 's', + "Certificate to be returned as mock enrollment result"}, + {"rsp_extracerts", OPT_RSP_EXTRACERTS, 's', + "Extra certificates to be included in mock certification responses"}, + {"rsp_capubs", OPT_RSP_CAPUBS, 's', + "CA certificates to be included in mock ip response"}, + {"poll_count", OPT_POLL_COUNT, 'N', + "Number of times the client must poll before receiving a certificate"}, + {"check_after", OPT_CHECK_AFTER, 'N', + "The check_after value (time to wait) to include in poll response"}, + {"grant_implicitconf", OPT_GRANT_IMPLICITCONF, '-', + "Grant implicit confirmation of newly enrolled certificate"}, + + {"pkistatus", OPT_PKISTATUS, 'N', + "PKIStatus to be included in server response. Possible values: 0..6"}, + {"failure", OPT_FAILURE, 'N', + "A single failure info bit number to include in server response, 0..26"}, + {"failurebits", OPT_FAILUREBITS, 'N', + "Number representing failure bits to include in server response, 0..2^27 - 1"}, + {"statusstring", OPT_STATUSSTRING, 's', + "Status string to be included in server response"}, + {"send_error", OPT_SEND_ERROR, '-', + "Force server to reply with error message"}, + {"send_unprotected", OPT_SEND_UNPROTECTED, '-', + "Send response messages without CMP-level protection"}, + {"send_unprot_err", OPT_SEND_UNPROT_ERR, '-', + "In case of negative responses, server shall send unprotected error messages,"}, + {OPT_MORE_STR, 0, 0, + "certificate responses (ip/cp/kup), and revocation responses (rp)."}, + {OPT_MORE_STR, 0, 0, + "WARNING: This setting leads to behavior violating RFC 4210"}, + {"accept_unprotected", OPT_ACCEPT_UNPROTECTED, '-', + "Accept missing or invalid protection of requests"}, + {"accept_unprot_err", OPT_ACCEPT_UNPROT_ERR, '-', + "Accept unprotected error messages from client"}, + {"accept_raverified", OPT_ACCEPT_RAVERIFIED, '-', + "Accept RAVERIFIED as proof-of-possession (POPO)"}, + + OPT_V_OPTIONS, + {NULL} +}; + +typedef union { + char **txt; + int *num; + long *num_long; +} varref; +static varref cmp_vars[] = { /* must be in same order as enumerated above! */ + {&opt_config}, {&opt_section}, {(char **)&opt_verbosity}, + + {&opt_cmd_s}, {&opt_infotype_s}, {&opt_geninfo}, + + {&opt_newkey}, {&opt_newkeypass}, {&opt_subject}, {&opt_issuer}, + {(char **)&opt_days}, {&opt_reqexts}, + {&opt_sans}, {(char **)&opt_san_nodefault}, + {&opt_policies}, {&opt_policy_oids}, {(char **)&opt_policy_oids_critical}, + {(char **)&opt_popo}, {&opt_csr}, + {&opt_out_trusted}, + {(char **)&opt_implicit_confirm}, {(char **)&opt_disable_confirm}, + {&opt_certout}, {&opt_chainout}, + + {&opt_oldcert}, {(char **)&opt_revreason}, + +#ifndef OPENSSL_NO_SOCK + {&opt_server}, {&opt_proxy}, {&opt_no_proxy}, +#endif + {&opt_recipient}, {&opt_path}, {(char **)&opt_keep_alive}, + {(char **)&opt_msg_timeout}, {(char **)&opt_total_timeout}, + + {&opt_trusted}, {&opt_untrusted}, {&opt_srvcert}, + {&opt_expect_sender}, + {(char **)&opt_ignore_keyusage}, {(char **)&opt_unprotected_errors}, + {&opt_extracertsout}, {&opt_cacertsout}, + + {&opt_ref}, {&opt_secret}, + {&opt_cert}, {&opt_own_trusted}, {&opt_key}, {&opt_keypass}, + {&opt_digest}, {&opt_mac}, {&opt_extracerts}, + {(char **)&opt_unprotected_requests}, + + {&opt_certform_s}, {&opt_keyform_s}, + {&opt_otherpass}, +#ifndef OPENSSL_NO_ENGINE + {&opt_engine}, +#endif + +#ifndef OPENSSL_NO_SOCK + {(char **)&opt_tls_used}, {&opt_tls_cert}, {&opt_tls_key}, + {&opt_tls_keypass}, + {&opt_tls_extra}, {&opt_tls_trusted}, {&opt_tls_host}, +#endif + + {(char **)&opt_batch}, {(char **)&opt_repeat}, + {&opt_reqin}, {(char **)&opt_reqin_new_tid}, + {&opt_reqout}, {&opt_rspin}, {&opt_rspout}, + + {(char **)&opt_use_mock_srv}, +#ifndef OPENSSL_NO_SOCK + {&opt_port}, {(char **)&opt_max_msgs}, +#endif + {&opt_srv_ref}, {&opt_srv_secret}, + {&opt_srv_cert}, {&opt_srv_key}, {&opt_srv_keypass}, + {&opt_srv_trusted}, {&opt_srv_untrusted}, + {&opt_rsp_cert}, {&opt_rsp_extracerts}, {&opt_rsp_capubs}, + {(char **)&opt_poll_count}, {(char **)&opt_check_after}, + {(char **)&opt_grant_implicitconf}, + {(char **)&opt_pkistatus}, {(char **)&opt_failure}, + {(char **)&opt_failurebits}, {&opt_statusstring}, + {(char **)&opt_send_error}, {(char **)&opt_send_unprotected}, + {(char **)&opt_send_unprot_err}, {(char **)&opt_accept_unprotected}, + {(char **)&opt_accept_unprot_err}, {(char **)&opt_accept_raverified}, + + {NULL} +}; + +#define FUNC (strcmp(OPENSSL_FUNC, "(unknown function)") == 0 \ + ? "CMP" : OPENSSL_FUNC) +#define CMP_print(bio, level, prefix, msg, a1, a2, a3) \ + ((void)(level > opt_verbosity ? 0 : \ + (BIO_printf(bio, "%s:%s:%d:CMP %s: " msg "\n", \ + FUNC, OPENSSL_FILE, OPENSSL_LINE, prefix, a1, a2, a3)))) +#define CMP_DEBUG(m, a1, a2, a3) \ + CMP_print(bio_out, OSSL_CMP_LOG_DEBUG, "debug", m, a1, a2, a3) +#define CMP_debug(msg) CMP_DEBUG(msg"%s%s%s", "", "", "") +#define CMP_debug1(msg, a1) CMP_DEBUG(msg"%s%s", a1, "", "") +#define CMP_debug2(msg, a1, a2) CMP_DEBUG(msg"%s", a1, a2, "") +#define CMP_debug3(msg, a1, a2, a3) CMP_DEBUG(msg, a1, a2, a3) +#define CMP_INFO(msg, a1, a2, a3) \ + CMP_print(bio_out, OSSL_CMP_LOG_INFO, "info", msg, a1, a2, a3) +#define CMP_info(msg) CMP_INFO(msg"%s%s%s", "", "", "") +#define CMP_info1(msg, a1) CMP_INFO(msg"%s%s", a1, "", "") +#define CMP_info2(msg, a1, a2) CMP_INFO(msg"%s", a1, a2, "") +#define CMP_info3(msg, a1, a2, a3) CMP_INFO(msg, a1, a2, a3) +#define CMP_WARN(m, a1, a2, a3) \ + CMP_print(bio_out, OSSL_CMP_LOG_WARNING, "warning", m, a1, a2, a3) +#define CMP_warn(msg) CMP_WARN(msg"%s%s%s", "", "", "") +#define CMP_warn1(msg, a1) CMP_WARN(msg"%s%s", a1, "", "") +#define CMP_warn2(msg, a1, a2) CMP_WARN(msg"%s", a1, a2, "") +#define CMP_warn3(msg, a1, a2, a3) CMP_WARN(msg, a1, a2, a3) +#define CMP_ERR(msg, a1, a2, a3) \ + CMP_print(bio_err, OSSL_CMP_LOG_ERR, "error", msg, a1, a2, a3) +#define CMP_err(msg) CMP_ERR(msg"%s%s%s", "", "", "") +#define CMP_err1(msg, a1) CMP_ERR(msg"%s%s", a1, "", "") +#define CMP_err2(msg, a1, a2) CMP_ERR(msg"%s", a1, a2, "") +#define CMP_err3(msg, a1, a2, a3) CMP_ERR(msg, a1, a2, a3) + +static int print_to_bio_out(const char *func, const char *file, int line, + OSSL_CMP_severity level, const char *msg) +{ + return OSSL_CMP_print_to_bio(bio_out, func, file, line, level, msg); +} + +static int print_to_bio_err(const char *func, const char *file, int line, + OSSL_CMP_severity level, const char *msg) +{ + return OSSL_CMP_print_to_bio(bio_err, func, file, line, level, msg); +} + +static int set_verbosity(int level) +{ + if (level < OSSL_CMP_LOG_EMERG || level > OSSL_CMP_LOG_MAX) { + CMP_err1("Logging verbosity level %d out of range (0 .. 8)", level); + return 0; + } + opt_verbosity = level; + return 1; +} + +static EVP_PKEY *load_key_pwd(const char *uri, int format, + const char *pass, ENGINE *eng, const char *desc) +{ + char *pass_string = get_passwd(pass, desc); + EVP_PKEY *pkey = load_key(uri, format, 0, pass_string, eng, desc); + + clear_free(pass_string); + return pkey; +} + +static X509 *load_cert_pwd(const char *uri, const char *pass, const char *desc) +{ + X509 *cert; + char *pass_string = get_passwd(pass, desc); + + cert = load_cert_pass(uri, FORMAT_UNDEF, 0, pass_string, desc); + clear_free(pass_string); + return cert; +} + +static X509_REQ *load_csr_autofmt(const char *infile, const char *desc) +{ + X509_REQ *csr; + BIO *bio_bak = bio_err; + + bio_err = NULL; /* do not show errors on more than one try */ + csr = load_csr(infile, FORMAT_PEM, desc); + bio_err = bio_bak; + if (csr == NULL) { + ERR_clear_error(); + csr = load_csr(infile, FORMAT_ASN1, desc); + } + if (csr == NULL) { + ERR_print_errors(bio_err); + BIO_printf(bio_err, "error: unable to load %s from file '%s'\n", desc, + infile); + } else { + EVP_PKEY *pkey = X509_REQ_get0_pubkey(csr); + int ret = do_X509_REQ_verify(csr, pkey, NULL /* vfyopts */); + + if (pkey == NULL || ret < 0) + CMP_warn("error while verifying CSR self-signature"); + else if (ret == 0) + CMP_warn("CSR self-signature does not match the contents"); + } + return csr; +} + +/* set expected host name/IP addr and clears the email addr in the given ts */ +static int truststore_set_host_etc(X509_STORE *ts, const char *host) +{ + X509_VERIFY_PARAM *ts_vpm = X509_STORE_get0_param(ts); + + /* first clear any host names, IP, and email addresses */ + if (!X509_VERIFY_PARAM_set1_host(ts_vpm, NULL, 0) + || !X509_VERIFY_PARAM_set1_ip(ts_vpm, NULL, 0) + || !X509_VERIFY_PARAM_set1_email(ts_vpm, NULL, 0)) + return 0; + X509_VERIFY_PARAM_set_hostflags(ts_vpm, + X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT | + X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + return (host != NULL && X509_VERIFY_PARAM_set1_ip_asc(ts_vpm, host)) + || X509_VERIFY_PARAM_set1_host(ts_vpm, host, 0); +} + +/* write OSSL_CMP_MSG DER-encoded to the specified file name item */ +static int write_PKIMESSAGE(const OSSL_CMP_MSG *msg, char **filenames) +{ + char *file; + + if (msg == NULL || filenames == NULL) { + CMP_err("NULL arg to write_PKIMESSAGE"); + return 0; + } + if (*filenames == NULL) { + CMP_err("not enough file names provided for writing PKIMessage"); + return 0; + } + + file = *filenames; + *filenames = next_item(file); + if (OSSL_CMP_MSG_write(file, msg) < 0) { + CMP_err1("cannot write PKIMessage to file '%s'", file); + return 0; + } + return 1; +} + +/* read DER-encoded OSSL_CMP_MSG from the specified file name item */ +static OSSL_CMP_MSG *read_PKIMESSAGE(char **filenames) +{ + char *file; + OSSL_CMP_MSG *ret; + + if (filenames == NULL) { + CMP_err("NULL arg to read_PKIMESSAGE"); + return NULL; + } + if (*filenames == NULL) { + CMP_err("not enough file names provided for reading PKIMessage"); + return NULL; + } + + file = *filenames; + *filenames = next_item(file); + + ret = OSSL_CMP_MSG_read(file, app_get0_libctx(), app_get0_propq()); + if (ret == NULL) + CMP_err1("cannot read PKIMessage from file '%s'", file); + return ret; +} + +/*- + * Sends the PKIMessage req and on success place the response in *res + * basically like OSSL_CMP_MSG_http_perform(), but in addition allows + * to dump the sequence of requests and responses to files and/or + * to take the sequence of requests and responses from files. + */ +static OSSL_CMP_MSG *read_write_req_resp(OSSL_CMP_CTX *ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_MSG *req_new = NULL; + OSSL_CMP_MSG *res = NULL; + OSSL_CMP_PKIHEADER *hdr; + const char *prev_opt_rspin = opt_rspin; + + if (req != NULL && opt_reqout != NULL + && !write_PKIMESSAGE(req, &opt_reqout)) + goto err; + if (opt_reqin != NULL && opt_rspin == NULL) { + if ((req_new = read_PKIMESSAGE(&opt_reqin)) == NULL) + goto err; + /*- + * The transaction ID in req_new read from opt_reqin may not be fresh. + * In this case the server may complain "Transaction id already in use." + * The following workaround unfortunately requires re-protection. + */ + if (opt_reqin_new_tid + && !OSSL_CMP_MSG_update_transactionID(ctx, req_new)) + goto err; + } + + if (opt_rspin != NULL) { + res = read_PKIMESSAGE(&opt_rspin); + } else { + const OSSL_CMP_MSG *actual_req = opt_reqin != NULL ? req_new : req; + + res = opt_use_mock_srv + ? OSSL_CMP_CTX_server_perform(ctx, actual_req) + : OSSL_CMP_MSG_http_perform(ctx, actual_req); + } + if (res == NULL) + goto err; + + if (opt_reqin != NULL || prev_opt_rspin != NULL) { + /* need to satisfy nonce and transactionID checks */ + ASN1_OCTET_STRING *nonce; + ASN1_OCTET_STRING *tid; + + hdr = OSSL_CMP_MSG_get0_header(res); + nonce = OSSL_CMP_HDR_get0_recipNonce(hdr); + tid = OSSL_CMP_HDR_get0_transactionID(hdr); + if (!OSSL_CMP_CTX_set1_senderNonce(ctx, nonce) + || !OSSL_CMP_CTX_set1_transactionID(ctx, tid)) { + OSSL_CMP_MSG_free(res); + res = NULL; + goto err; + } + } + + if (opt_rspout != NULL && !write_PKIMESSAGE(res, &opt_rspout)) { + OSSL_CMP_MSG_free(res); + res = NULL; + } + + err: + OSSL_CMP_MSG_free(req_new); + return res; +} + +static int set_name(const char *str, + int (*set_fn) (OSSL_CMP_CTX *ctx, const X509_NAME *name), + OSSL_CMP_CTX *ctx, const char *desc) +{ + if (str != NULL) { + X509_NAME *n = parse_name(str, MBSTRING_ASC, 1, desc); + + if (n == NULL) + return 0; + if (!(*set_fn) (ctx, n)) { + X509_NAME_free(n); + CMP_err("out of memory"); + return 0; + } + X509_NAME_free(n); + } + return 1; +} + +static int set_gennames(OSSL_CMP_CTX *ctx, char *names, const char *desc) +{ + char *next; + + for (; names != NULL; names = next) { + GENERAL_NAME *n; + + next = next_item(names); + if (strcmp(names, "critical") == 0) { + (void)OSSL_CMP_CTX_set_option(ctx, + OSSL_CMP_OPT_SUBJECTALTNAME_CRITICAL, + 1); + continue; + } + + /* try IP address first, then URI or domain name */ + (void)ERR_set_mark(); + n = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_IPADD, names, 0); + if (n == NULL) + n = a2i_GENERAL_NAME(NULL, NULL, NULL, + strchr(names, ':') != NULL ? GEN_URI : GEN_DNS, + names, 0); + (void)ERR_pop_to_mark(); + + if (n == NULL) { + CMP_err2("bad syntax of %s '%s'", desc, names); + return 0; + } + if (!OSSL_CMP_CTX_push1_subjectAltName(ctx, n)) { + GENERAL_NAME_free(n); + CMP_err("out of memory"); + return 0; + } + GENERAL_NAME_free(n); + } + return 1; +} + +static X509_STORE *load_trusted(char *input, int for_new_cert, const char *desc) +{ + X509_STORE *ts = load_certstore(input, opt_otherpass, desc, vpm); + + if (ts == NULL) + return NULL; + X509_STORE_set_verify_cb(ts, X509_STORE_CTX_print_verify_cb); + + /* copy vpm to store */ + if (X509_STORE_set1_param(ts, vpm /* may be NULL */) + && (for_new_cert || truststore_set_host_etc(ts, NULL))) + return ts; + BIO_printf(bio_err, "error setting verification parameters for %s\n", desc); + OSSL_CMP_CTX_print_errors(cmp_ctx); + X509_STORE_free(ts); + return NULL; +} + +typedef int (*add_X509_stack_fn_t)(void *ctx, const STACK_OF(X509) *certs); + +static int setup_certs(char *files, const char *desc, void *ctx, + add_X509_stack_fn_t set1_fn) +{ + STACK_OF(X509) *certs; + int ok; + + if (files == NULL) + return 1; + if ((certs = load_certs_multifile(files, opt_otherpass, desc, vpm)) == NULL) + return 0; + ok = (*set1_fn)(ctx, certs); + sk_X509_pop_free(certs, X509_free); + return ok; +} + + +/* + * parse and transform some options, checking their syntax. + * Returns 1 on success, 0 on error + */ +static int transform_opts(void) +{ + if (opt_cmd_s != NULL) { + if (!strcmp(opt_cmd_s, "ir")) { + opt_cmd = CMP_IR; + } else if (!strcmp(opt_cmd_s, "kur")) { + opt_cmd = CMP_KUR; + } else if (!strcmp(opt_cmd_s, "cr")) { + opt_cmd = CMP_CR; + } else if (!strcmp(opt_cmd_s, "p10cr")) { + opt_cmd = CMP_P10CR; + } else if (!strcmp(opt_cmd_s, "rr")) { + opt_cmd = CMP_RR; + } else if (!strcmp(opt_cmd_s, "genm")) { + opt_cmd = CMP_GENM; + } else { + CMP_err1("unknown cmp command '%s'", opt_cmd_s); + return 0; + } + } else { + CMP_err("no cmp command to execute"); + return 0; + } + +#ifndef OPENSSL_NO_ENGINE +# define FORMAT_OPTIONS (OPT_FMT_PEMDER | OPT_FMT_PKCS12 | OPT_FMT_ENGINE) +#else +# define FORMAT_OPTIONS (OPT_FMT_PEMDER | OPT_FMT_PKCS12) +#endif + + if (opt_keyform_s != NULL + && !opt_format(opt_keyform_s, FORMAT_OPTIONS, &opt_keyform)) { + CMP_err("unknown option given for key loading format"); + return 0; + } + +#undef FORMAT_OPTIONS + + if (opt_certform_s != NULL + && !opt_format(opt_certform_s, OPT_FMT_PEMDER, &opt_certform)) { + CMP_err("unknown option given for certificate storing format"); + return 0; + } + + return 1; +} + +static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine) +{ + OSSL_CMP_CTX *ctx; /* extra CMP (client) ctx partly used by server */ + OSSL_CMP_SRV_CTX *srv_ctx = ossl_cmp_mock_srv_new(app_get0_libctx(), + app_get0_propq()); + + if (srv_ctx == NULL) + return NULL; + ctx = OSSL_CMP_SRV_CTX_get0_cmp_ctx(srv_ctx); + + if (opt_srv_ref == NULL) { + if (opt_srv_cert == NULL) { + /* opt_srv_cert should determine the sender */ + CMP_err("must give -srv_ref for mock server if no -srv_cert given"); + goto err; + } + } else { + if (!OSSL_CMP_CTX_set1_referenceValue(ctx, (unsigned char *)opt_srv_ref, + strlen(opt_srv_ref))) + goto err; + } + + if (opt_srv_secret != NULL) { + int res; + char *pass_str = get_passwd(opt_srv_secret, "PBMAC secret of mock server"); + + if (pass_str != NULL) { + cleanse(opt_srv_secret); + res = OSSL_CMP_CTX_set1_secretValue(ctx, (unsigned char *)pass_str, + strlen(pass_str)); + clear_free(pass_str); + if (res == 0) + goto err; + } + } else if (opt_srv_cert == NULL) { + CMP_err("mock server credentials must be given if -use_mock_srv or -port is used"); + goto err; + } else { + CMP_warn("mock server will not be able to handle PBM-protected requests since -srv_secret is not given"); + } + + if (opt_srv_secret == NULL + && ((opt_srv_cert == NULL) != (opt_srv_key == NULL))) { + CMP_err("must give both -srv_cert and -srv_key options or neither"); + goto err; + } + if (opt_srv_cert != NULL) { + X509 *srv_cert = load_cert_pwd(opt_srv_cert, opt_srv_keypass, + "certificate of the mock server"); + + if (srv_cert == NULL || !OSSL_CMP_CTX_set1_cert(ctx, srv_cert)) { + X509_free(srv_cert); + goto err; + } + X509_free(srv_cert); + } + if (opt_srv_key != NULL) { + EVP_PKEY *pkey = load_key_pwd(opt_srv_key, opt_keyform, + opt_srv_keypass, + engine, "private key for mock server cert"); + + if (pkey == NULL || !OSSL_CMP_CTX_set1_pkey(ctx, pkey)) { + EVP_PKEY_free(pkey); + goto err; + } + EVP_PKEY_free(pkey); + } + cleanse(opt_srv_keypass); + + if (opt_srv_trusted != NULL) { + X509_STORE *ts = + load_trusted(opt_srv_trusted, 0, "certs trusted by mock server"); + + if (ts == NULL || !OSSL_CMP_CTX_set0_trustedStore(ctx, ts)) { + X509_STORE_free(ts); + goto err; + } + } else { + CMP_warn("mock server will not be able to handle signature-protected requests since -srv_trusted is not given"); + } + if (!setup_certs(opt_srv_untrusted, + "untrusted certificates for mock server", ctx, + (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted)) + goto err; + + if (opt_rsp_cert == NULL) { + CMP_warn("no -rsp_cert given for mock server"); + } else { + X509 *cert = load_cert_pwd(opt_rsp_cert, opt_keypass, + "cert to be returned by the mock server"); + + if (cert == NULL) + goto err; + /* from server perspective the server is the client */ + if (!ossl_cmp_mock_srv_set1_certOut(srv_ctx, cert)) { + X509_free(cert); + goto err; + } + X509_free(cert); + } + if (!setup_certs(opt_rsp_extracerts, + "CMP extra certificates for mock server", srv_ctx, + (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_chainOut)) + goto err; + if (!setup_certs(opt_rsp_capubs, "caPubs for mock server", srv_ctx, + (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_caPubsOut)) + goto err; + (void)ossl_cmp_mock_srv_set_pollCount(srv_ctx, opt_poll_count); + (void)ossl_cmp_mock_srv_set_checkAfterTime(srv_ctx, opt_check_after); + if (opt_grant_implicitconf) + (void)OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(srv_ctx, 1); + + if (opt_failure != INT_MIN) { /* option has been set explicity */ + if (opt_failure < 0 || OSSL_CMP_PKIFAILUREINFO_MAX < opt_failure) { + CMP_err1("-failure out of range, should be >= 0 and <= %d", + OSSL_CMP_PKIFAILUREINFO_MAX); + goto err; + } + if (opt_failurebits != 0) + CMP_warn("-failurebits overrides -failure"); + else + opt_failurebits = 1 << opt_failure; + } + if ((unsigned)opt_failurebits > OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN) { + CMP_err("-failurebits out of range"); + goto err; + } + if (!ossl_cmp_mock_srv_set_statusInfo(srv_ctx, opt_pkistatus, + opt_failurebits, opt_statusstring)) + goto err; + + if (opt_send_error) + (void)ossl_cmp_mock_srv_set_send_error(srv_ctx, 1); + + if (opt_send_unprotected) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_UNPROTECTED_SEND, 1); + if (opt_send_unprot_err) + (void)OSSL_CMP_SRV_CTX_set_send_unprotected_errors(srv_ctx, 1); + if (opt_accept_unprotected) + (void)OSSL_CMP_SRV_CTX_set_accept_unprotected(srv_ctx, 1); + if (opt_accept_unprot_err) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_UNPROTECTED_ERRORS, 1); + if (opt_accept_raverified) + (void)OSSL_CMP_SRV_CTX_set_accept_raverified(srv_ctx, 1); + + return srv_ctx; + + err: + ossl_cmp_mock_srv_free(srv_ctx); + return NULL; +} + +/* + * set up verification aspects of OSSL_CMP_CTX w.r.t. opts from config file/CLI. + * Returns pointer on success, NULL on error + */ +static int setup_verification_ctx(OSSL_CMP_CTX *ctx) +{ + if (!setup_certs(opt_untrusted, "untrusted certificates", ctx, + (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted)) + return 0; + + if (opt_srvcert != NULL || opt_trusted != NULL) { + X509 *srvcert; + X509_STORE *ts; + int ok; + + if (opt_srvcert != NULL) { + if (opt_trusted != NULL) { + CMP_warn("-trusted option is ignored since -srvcert option is present"); + opt_trusted = NULL; + } + if (opt_recipient != NULL) { + CMP_warn("-recipient option is ignored since -srvcert option is present"); + opt_recipient = NULL; + } + srvcert = load_cert_pwd(opt_srvcert, opt_otherpass, + "directly trusted CMP server certificate"); + ok = srvcert != NULL && OSSL_CMP_CTX_set1_srvCert(ctx, srvcert); + X509_free(srvcert); + if (!ok) + return 0; + } + if (opt_trusted != NULL) { + /* + * the 0 arg below clears any expected host/ip/email address; + * opt_expect_sender is used instead + */ + ts = load_trusted(opt_trusted, 0, "certs trusted by client"); + + if (ts == NULL || !OSSL_CMP_CTX_set0_trustedStore(ctx, ts)) { + X509_STORE_free(ts); + return 0; + } + } + } + + if (opt_ignore_keyusage) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_IGNORE_KEYUSAGE, 1); + + if (opt_unprotected_errors) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_UNPROTECTED_ERRORS, 1); + + if (opt_out_trusted != NULL) { /* for use in OSSL_CMP_certConf_cb() */ + X509_VERIFY_PARAM *out_vpm = NULL; + X509_STORE *out_trusted = + load_trusted(opt_out_trusted, 1, + "trusted certs for verifying newly enrolled cert"); + + if (out_trusted == NULL) + return 0; + /* ignore any -attime here, new certs are current anyway */ + out_vpm = X509_STORE_get0_param(out_trusted); + X509_VERIFY_PARAM_clear_flags(out_vpm, X509_V_FLAG_USE_CHECK_TIME); + + (void)OSSL_CMP_CTX_set_certConf_cb_arg(ctx, out_trusted); + } + + if (opt_disable_confirm) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_DISABLE_CONFIRM, 1); + + if (opt_implicit_confirm) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM, 1); + + return 1; +} + +#ifndef OPENSSL_NO_SOCK +/* + * set up ssl_ctx for the OSSL_CMP_CTX based on options from config file/CLI. + * Returns pointer on success, NULL on error + */ +static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, const char *host, + ENGINE *engine) +{ + STACK_OF(X509) *untrusted = OSSL_CMP_CTX_get0_untrusted(ctx); + EVP_PKEY *pkey = NULL; + X509_STORE *trust_store = NULL; + SSL_CTX *ssl_ctx; + int i; + + ssl_ctx = SSL_CTX_new(TLS_client_method()); + if (ssl_ctx == NULL) + return NULL; + + if (opt_tls_trusted != NULL) { + trust_store = load_trusted(opt_tls_trusted, 0, "trusted TLS certs"); + if (trust_store == NULL) + goto err; + SSL_CTX_set_cert_store(ssl_ctx, trust_store); + } + + if (opt_tls_cert != NULL && opt_tls_key != NULL) { + X509 *cert; + STACK_OF(X509) *certs = NULL; + int ok; + + if (!load_cert_certs(opt_tls_cert, &cert, &certs, 0, opt_tls_keypass, + "TLS client certificate (optionally with chain)", + vpm)) + /* need opt_tls_keypass if opt_tls_cert is encrypted PKCS#12 file */ + goto err; + + ok = SSL_CTX_use_certificate(ssl_ctx, cert) > 0; + X509_free(cert); + + /* + * Any further certs and any untrusted certs are used for constructing + * the chain to be provided with the TLS client cert to the TLS server. + */ + if (!ok || !SSL_CTX_set0_chain(ssl_ctx, certs)) { + CMP_err1("unable to use client TLS certificate file '%s'", + opt_tls_cert); + sk_X509_pop_free(certs, X509_free); + goto err; + } + for (i = 0; i < sk_X509_num(untrusted); i++) { + cert = sk_X509_value(untrusted, i); + if (!SSL_CTX_add1_chain_cert(ssl_ctx, cert)) { + CMP_err("could not add untrusted cert to TLS client cert chain"); + goto err; + } + } + + { + X509_VERIFY_PARAM *tls_vpm = NULL; + unsigned long bak_flags = 0; /* compiler warns without init */ + + if (trust_store != NULL) { + tls_vpm = X509_STORE_get0_param(trust_store); + bak_flags = X509_VERIFY_PARAM_get_flags(tls_vpm); + /* disable any cert status/revocation checking etc. */ + X509_VERIFY_PARAM_clear_flags(tls_vpm, + ~(X509_V_FLAG_USE_CHECK_TIME + | X509_V_FLAG_NO_CHECK_TIME)); + } + CMP_debug("trying to build cert chain for own TLS cert"); + if (SSL_CTX_build_cert_chain(ssl_ctx, + SSL_BUILD_CHAIN_FLAG_UNTRUSTED | + SSL_BUILD_CHAIN_FLAG_NO_ROOT)) { + CMP_debug("success building cert chain for own TLS cert"); + } else { + OSSL_CMP_CTX_print_errors(ctx); + CMP_warn("could not build cert chain for own TLS cert"); + } + if (trust_store != NULL) + X509_VERIFY_PARAM_set_flags(tls_vpm, bak_flags); + } + + /* If present we append to the list also the certs from opt_tls_extra */ + if (opt_tls_extra != NULL) { + STACK_OF(X509) *tls_extra = load_certs_multifile(opt_tls_extra, + opt_otherpass, + "extra certificates for TLS", + vpm); + int res = 1; + + if (tls_extra == NULL) + goto err; + for (i = 0; i < sk_X509_num(tls_extra); i++) { + cert = sk_X509_value(tls_extra, i); + if (res != 0) + res = SSL_CTX_add_extra_chain_cert(ssl_ctx, cert); + if (res == 0) + X509_free(cert); + } + sk_X509_free(tls_extra); + if (res == 0) { + BIO_printf(bio_err, "error: unable to add TLS extra certs\n"); + goto err; + } + } + + pkey = load_key_pwd(opt_tls_key, opt_keyform, opt_tls_keypass, + engine, "TLS client private key"); + cleanse(opt_tls_keypass); + if (pkey == NULL) + goto err; + /* + * verify the key matches the cert, + * not using SSL_CTX_check_private_key(ssl_ctx) + * because it gives poor and sometimes misleading diagnostics + */ + if (!X509_check_private_key(SSL_CTX_get0_certificate(ssl_ctx), + pkey)) { + CMP_err2("TLS private key '%s' does not match the TLS certificate '%s'\n", + opt_tls_key, opt_tls_cert); + EVP_PKEY_free(pkey); + pkey = NULL; /* otherwise, for some reason double free! */ + goto err; + } + if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) <= 0) { + CMP_err1("unable to use TLS client private key '%s'", opt_tls_key); + EVP_PKEY_free(pkey); + pkey = NULL; /* otherwise, for some reason double free! */ + goto err; + } + EVP_PKEY_free(pkey); /* we do not need the handle any more */ + } + if (opt_tls_trusted != NULL) { + /* enable and parameterize server hostname/IP address check */ + if (!truststore_set_host_etc(trust_store, + opt_tls_host != NULL ? opt_tls_host : host)) + goto err; + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + } + return ssl_ctx; + err: + SSL_CTX_free(ssl_ctx); + return NULL; +} +#endif /* OPENSSL_NO_SOCK */ + +/* + * set up protection aspects of OSSL_CMP_CTX based on options from config + * file/CLI while parsing options and checking their consistency. + * Returns 1 on success, 0 on error + */ +static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) +{ + if (!opt_unprotected_requests && opt_secret == NULL && opt_key == NULL) { + CMP_err("must give -key or -secret unless -unprotected_requests is used"); + return 0; + } + + if (opt_ref == NULL && opt_cert == NULL && opt_subject == NULL) { + /* cert or subject should determine the sender */ + CMP_err("must give -ref if no -cert and no -subject given"); + return 0; + } + if (!opt_secret && ((opt_cert == NULL) != (opt_key == NULL))) { + CMP_err("must give both -cert and -key options or neither"); + return 0; + } + if (opt_secret != NULL) { + char *pass_string = get_passwd(opt_secret, "PBMAC"); + int res; + + if (pass_string != NULL) { + cleanse(opt_secret); + res = OSSL_CMP_CTX_set1_secretValue(ctx, + (unsigned char *)pass_string, + strlen(pass_string)); + clear_free(pass_string); + if (res == 0) + return 0; + } + if (opt_cert != NULL || opt_key != NULL) + CMP_warn("-cert and -key not used for protection since -secret is given"); + } + if (opt_ref != NULL + && !OSSL_CMP_CTX_set1_referenceValue(ctx, (unsigned char *)opt_ref, + strlen(opt_ref))) + return 0; + + if (opt_key != NULL) { + EVP_PKEY *pkey = load_key_pwd(opt_key, opt_keyform, opt_keypass, engine, + "private key for CMP client certificate"); + + if (pkey == NULL || !OSSL_CMP_CTX_set1_pkey(ctx, pkey)) { + EVP_PKEY_free(pkey); + return 0; + } + EVP_PKEY_free(pkey); + } + if (opt_secret == NULL && opt_srvcert == NULL && opt_trusted == NULL) + CMP_warn("will not authenticate server due to missing -secret, -trusted, or -srvcert"); + + if (opt_cert != NULL) { + X509 *cert; + STACK_OF(X509) *certs = NULL; + X509_STORE *own_trusted = NULL; + int ok; + + if (!load_cert_certs(opt_cert, &cert, &certs, 0, opt_keypass, + "CMP client certificate (optionally with chain)", + vpm)) + /* opt_keypass is needed if opt_cert is an encrypted PKCS#12 file */ + return 0; + ok = OSSL_CMP_CTX_set1_cert(ctx, cert); + X509_free(cert); + if (!ok) { + CMP_err("out of memory"); + } else { + if (opt_own_trusted != NULL) { + own_trusted = load_trusted(opt_own_trusted, 0, + "trusted certs for verifying own CMP signer cert"); + ok = own_trusted != NULL; + } + ok = ok && OSSL_CMP_CTX_build_cert_chain(ctx, own_trusted, certs); + } + X509_STORE_free(own_trusted); + sk_X509_pop_free(certs, X509_free); + if (!ok) + return 0; + } else if (opt_own_trusted != NULL) { + CMP_warn("-own_trusted option is ignored without -cert"); + } + + if (!setup_certs(opt_extracerts, "extra certificates for CMP", ctx, + (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_extraCertsOut)) + return 0; + cleanse(opt_otherpass); + + if (opt_unprotected_requests) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_UNPROTECTED_SEND, 1); + + if (opt_digest != NULL) { + int digest = OBJ_ln2nid(opt_digest); + + if (digest == NID_undef) { + CMP_err1("digest algorithm name not recognized: '%s'", opt_digest); + return 0; + } + if (!OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_DIGEST_ALGNID, digest) + || !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_OWF_ALGNID, digest)) { + CMP_err1("digest algorithm name not supported: '%s'", opt_digest); + return 0; + } + } + + if (opt_mac != NULL) { + int mac = OBJ_ln2nid(opt_mac); + if (mac == NID_undef) { + CMP_err1("MAC algorithm name not recognized: '%s'", opt_mac); + return 0; + } + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_MAC_ALGNID, mac); + } + return 1; +} + +/* + * set up IR/CR/KUR/CertConf/RR specific parts of the OSSL_CMP_CTX + * based on options from config file/CLI. + * Returns pointer on success, NULL on error + */ +static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) +{ + X509_REQ *csr = NULL; + X509_EXTENSIONS *exts = NULL; + X509V3_CTX ext_ctx; + + if (opt_subject == NULL + && opt_csr == NULL && opt_oldcert == NULL && opt_cert == NULL + && opt_cmd != CMP_RR && opt_cmd != CMP_GENM) + CMP_warn("no -subject given; no -csr or -oldcert or -cert available for fallback"); + + if (opt_cmd == CMP_IR || opt_cmd == CMP_CR || opt_cmd == CMP_KUR) { + if (opt_newkey == NULL && opt_key == NULL && opt_csr == NULL) { + CMP_err("missing -newkey (or -key) to be certified and no -csr given"); + return 0; + } + if (opt_certout == NULL) { + CMP_err("-certout not given, nowhere to save newly enrolled certificate"); + return 0; + } + if (!set_name(opt_subject, OSSL_CMP_CTX_set1_subjectName, ctx, "subject") + || !set_name(opt_issuer, OSSL_CMP_CTX_set1_issuer, ctx, "issuer")) + return 0; + } else { + const char *msg = "option is ignored for commands other than 'ir', 'cr', and 'kur'"; + + if (opt_subject != NULL) { + if (opt_ref == NULL && opt_cert == NULL) { + /* use subject as default sender unless oldcert subject is used */ + if (!set_name(opt_subject, OSSL_CMP_CTX_set1_subjectName, ctx, "subject")) + return 0; + } else { + CMP_warn1("-subject %s since -ref or -cert is given", msg); + } + } + if (opt_issuer != NULL) + CMP_warn1("-issuer %s", msg); + if (opt_reqexts != NULL) + CMP_warn1("-reqexts %s", msg); + if (opt_san_nodefault) + CMP_warn1("-san_nodefault %s", msg); + if (opt_sans != NULL) + CMP_warn1("-sans %s", msg); + if (opt_policies != NULL) + CMP_warn1("-policies %s", msg); + if (opt_policy_oids != NULL) + CMP_warn1("-policy_oids %s", msg); + } + if (opt_cmd == CMP_KUR) { + char *ref_cert = opt_oldcert != NULL ? opt_oldcert : opt_cert; + + if (ref_cert == NULL && opt_csr == NULL) { + CMP_err("missing -oldcert for certificate to be updated and no -csr given"); + return 0; + } + if (opt_subject != NULL) + CMP_warn2("given -subject '%s' overrides the subject of '%s' for KUR", + opt_subject, ref_cert != NULL ? ref_cert : opt_csr); + } + if (opt_cmd == CMP_RR) { + if (opt_oldcert == NULL && opt_csr == NULL) { + CMP_err("missing -oldcert for certificate to be revoked and no -csr given"); + return 0; + } + if (opt_oldcert != NULL && opt_csr != NULL) + CMP_warn("ignoring -csr since certificate to be revoked is given"); + } + if (opt_cmd == CMP_P10CR && opt_csr == NULL) { + CMP_err("missing PKCS#10 CSR for p10cr"); + return 0; + } + + if (opt_recipient == NULL && opt_srvcert == NULL && opt_issuer == NULL + && opt_oldcert == NULL && opt_cert == NULL) + CMP_warn("missing -recipient, -srvcert, -issuer, -oldcert or -cert; recipient will be set to \"NULL-DN\""); + + if (opt_cmd == CMP_P10CR || opt_cmd == CMP_RR) { + const char *msg = "option is ignored for 'p10cr' and 'rr' commands"; + + if (opt_newkeypass != NULL) + CMP_warn1("-newkeytype %s", msg); + if (opt_newkey != NULL) + CMP_warn1("-newkey %s", msg); + if (opt_days != 0) + CMP_warn1("-days %s", msg); + if (opt_popo != OSSL_CRMF_POPO_NONE - 1) + CMP_warn1("-popo %s", msg); + } else if (opt_newkey != NULL) { + const char *file = opt_newkey; + const int format = opt_keyform; + const char *pass = opt_newkeypass; + const char *desc = "new private key for cert to be enrolled"; + EVP_PKEY *pkey; + int priv = 1; + BIO *bio_bak = bio_err; + + bio_err = NULL; /* suppress diagnostics on first try loading key */ + pkey = load_key_pwd(file, format, pass, engine, desc); + bio_err = bio_bak; + if (pkey == NULL) { + ERR_clear_error(); + desc = opt_csr == NULL + ? "fallback public key for cert to be enrolled" + : "public key for checking cert resulting from p10cr"; + pkey = load_pubkey(file, format, 0, pass, engine, desc); + priv = 0; + } + cleanse(opt_newkeypass); + if (pkey == NULL || !OSSL_CMP_CTX_set0_newPkey(ctx, priv, pkey)) { + EVP_PKEY_free(pkey); + return 0; + } + } + + if (opt_days > 0 + && !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_VALIDITY_DAYS, + opt_days)) { + CMP_err("could not set requested cert validity period"); + return 0; + } + + if (opt_policies != NULL && opt_policy_oids != NULL) { + CMP_err("cannot have policies both via -policies and via -policy_oids"); + return 0; + } + + if (opt_csr != NULL) { + if (opt_cmd == CMP_GENM) { + CMP_warn("-csr option is ignored for command 'genm'"); + } else { + if ((csr = load_csr_autofmt(opt_csr, "PKCS#10 CSR")) == NULL) + return 0; + if (!OSSL_CMP_CTX_set1_p10CSR(ctx, csr)) + goto oom; + } + } + if (opt_reqexts != NULL || opt_policies != NULL) { + if ((exts = sk_X509_EXTENSION_new_null()) == NULL) + goto oom; + X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, X509V3_CTX_REPLACE); + X509V3_set_nconf(&ext_ctx, conf); + if (opt_reqexts != NULL + && !X509V3_EXT_add_nconf_sk(conf, &ext_ctx, opt_reqexts, &exts)) { + CMP_err1("cannot load certificate request extension section '%s'", + opt_reqexts); + goto exts_err; + } + if (opt_policies != NULL + && !X509V3_EXT_add_nconf_sk(conf, &ext_ctx, opt_policies, &exts)) { + CMP_err1("cannot load policy cert request extension section '%s'", + opt_policies); + goto exts_err; + } + OSSL_CMP_CTX_set0_reqExtensions(ctx, exts); + } + X509_REQ_free(csr); + /* After here, must not goto oom/exts_err */ + + if (OSSL_CMP_CTX_reqExtensions_have_SAN(ctx) && opt_sans != NULL) { + CMP_err("cannot have Subject Alternative Names both via -reqexts and via -sans"); + return 0; + } + if (!set_gennames(ctx, opt_sans, "Subject Alternative Name")) + return 0; + + if (opt_san_nodefault) { + if (opt_sans != NULL) + CMP_warn("-opt_san_nodefault has no effect when -sans is used"); + (void)OSSL_CMP_CTX_set_option(ctx, + OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT, 1); + } + + if (opt_policy_oids_critical) { + if (opt_policy_oids == NULL) + CMP_warn("-opt_policy_oids_critical has no effect unless -policy_oids is given"); + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_POLICIES_CRITICAL, 1); + } + + while (opt_policy_oids != NULL) { + ASN1_OBJECT *policy; + POLICYINFO *pinfo; + char *next = next_item(opt_policy_oids); + + if ((policy = OBJ_txt2obj(opt_policy_oids, 1)) == 0) { + CMP_err1("unknown policy OID '%s'", opt_policy_oids); + return 0; + } + + if ((pinfo = POLICYINFO_new()) == NULL) { + ASN1_OBJECT_free(policy); + return 0; + } + pinfo->policyid = policy; + + if (!OSSL_CMP_CTX_push0_policy(ctx, pinfo)) { + CMP_err1("cannot add policy with OID '%s'", opt_policy_oids); + POLICYINFO_free(pinfo); + return 0; + } + opt_policy_oids = next; + } + + if (opt_popo >= OSSL_CRMF_POPO_NONE) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_POPO_METHOD, opt_popo); + + if (opt_oldcert != NULL) { + if (opt_cmd == CMP_GENM) { + CMP_warn("-oldcert option is ignored for command 'genm'"); + } else { + X509 *oldcert = load_cert_pwd(opt_oldcert, opt_keypass, + opt_cmd == CMP_KUR ? + "certificate to be updated" : + opt_cmd == CMP_RR ? + "certificate to be revoked" : + "reference certificate (oldcert)"); + /* opt_keypass needed if opt_oldcert is an encrypted PKCS#12 file */ + + if (oldcert == NULL) + return 0; + if (!OSSL_CMP_CTX_set1_oldCert(ctx, oldcert)) { + X509_free(oldcert); + CMP_err("out of memory"); + return 0; + } + X509_free(oldcert); + } + } + cleanse(opt_keypass); + if (opt_revreason > CRL_REASON_NONE) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_REVOCATION_REASON, + opt_revreason); + + return 1; + + oom: + CMP_err("out of memory"); + exts_err: + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + X509_REQ_free(csr); + return 0; +} + +static int handle_opt_geninfo(OSSL_CMP_CTX *ctx) +{ + long value; + ASN1_OBJECT *type; + ASN1_INTEGER *aint; + ASN1_TYPE *val; + OSSL_CMP_ITAV *itav; + char *endstr; + char *valptr = strchr(opt_geninfo, ':'); + + if (valptr == NULL) { + CMP_err("missing ':' in -geninfo option"); + return 0; + } + valptr[0] = '\0'; + valptr++; + + if (OPENSSL_strncasecmp(valptr, "int:", 4) != 0) { + CMP_err("missing 'int:' in -geninfo option"); + return 0; + } + valptr += 4; + + value = strtol(valptr, &endstr, 10); + if (endstr == valptr || *endstr != '\0') { + CMP_err("cannot parse int in -geninfo option"); + return 0; + } + + type = OBJ_txt2obj(opt_geninfo, 1); + if (type == NULL) { + CMP_err("cannot parse OID in -geninfo option"); + return 0; + } + + if ((aint = ASN1_INTEGER_new()) == NULL) + goto oom; + + val = ASN1_TYPE_new(); + if (!ASN1_INTEGER_set(aint, value) || val == NULL) { + ASN1_INTEGER_free(aint); + goto oom; + } + ASN1_TYPE_set(val, V_ASN1_INTEGER, aint); + itav = OSSL_CMP_ITAV_create(type, val); + if (itav == NULL) { + ASN1_TYPE_free(val); + goto oom; + } + + if (!OSSL_CMP_CTX_push0_geninfo_ITAV(ctx, itav)) { + OSSL_CMP_ITAV_free(itav); + return 0; + } + return 1; + + oom: + ASN1_OBJECT_free(type); + CMP_err("out of memory"); + return 0; +} + + +/* + * set up the client-side OSSL_CMP_CTX based on options from config file/CLI + * while parsing options and checking their consistency. + * Prints reason for error to bio_err. + * Returns 1 on success, 0 on error + */ +static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) +{ + int ret = 0; + char *host = NULL, *port = NULL, *path = NULL, *used_path = opt_path; +#ifndef OPENSSL_NO_SOCK + int portnum, ssl; + static char server_port[32] = { '\0' }; + const char *proxy_host = NULL; +#endif + char server_buf[200] = "mock server"; + char proxy_buf[200] = ""; + + if (!opt_use_mock_srv && opt_rspin == NULL) { /* note: -port is not given */ +#ifndef OPENSSL_NO_SOCK + if (opt_server == NULL) { + CMP_err("missing -server or -use_mock_srv or -rspin option"); + goto err; + } +#else + CMP_err("missing -use_mock_srv or -rspin option; -server option is not supported due to no-sock build"); + goto err; +#endif + } +#ifndef OPENSSL_NO_SOCK + if (opt_server == NULL) { + if (opt_proxy != NULL) + CMP_warn("ignoring -proxy option since -server is not given"); + if (opt_no_proxy != NULL) + CMP_warn("ignoring -no_proxy option since -server is not given"); + if (opt_tls_used) { + CMP_warn("ignoring -tls_used option since -server is not given"); + opt_tls_used = 0; + } + goto set_path; + } + if (!OSSL_HTTP_parse_url(opt_server, &ssl, NULL /* user */, &host, &port, + &portnum, &path, NULL /* q */, NULL /* frag */)) { + CMP_err1("cannot parse -server URL: %s", opt_server); + goto err; + } + if (ssl && !opt_tls_used) { + CMP_err("missing -tls_used option since -server URL indicates https"); + goto err; + } + + BIO_snprintf(server_port, sizeof(server_port), "%s", port); + if (opt_path == NULL) + used_path = path; + if (!OSSL_CMP_CTX_set1_server(ctx, host) + || !OSSL_CMP_CTX_set_serverPort(ctx, portnum)) + goto oom; + if (opt_proxy != NULL && !OSSL_CMP_CTX_set1_proxy(ctx, opt_proxy)) + goto oom; + if (opt_no_proxy != NULL && !OSSL_CMP_CTX_set1_no_proxy(ctx, opt_no_proxy)) + goto oom; + (void)BIO_snprintf(server_buf, sizeof(server_buf), "http%s://%s:%s/%s", + opt_tls_used ? "s" : "", host, port, + *used_path == '/' ? used_path + 1 : used_path); + + proxy_host = OSSL_HTTP_adapt_proxy(opt_proxy, opt_no_proxy, host, ssl); + if (proxy_host != NULL) + (void)BIO_snprintf(proxy_buf, sizeof(proxy_buf), " via %s", proxy_host); + + set_path: +#endif + + if (!OSSL_CMP_CTX_set1_serverPath(ctx, used_path)) + goto oom; + if (!transform_opts()) + goto err; + + if (opt_infotype_s != NULL) { + char id_buf[100] = "id-it-"; + + strncat(id_buf, opt_infotype_s, sizeof(id_buf) - strlen(id_buf) - 1); + if ((opt_infotype = OBJ_sn2nid(id_buf)) == NID_undef) { + CMP_err("unknown OID name in -infotype option"); + goto err; + } + } + + if (!setup_verification_ctx(ctx)) + goto err; + + if (opt_keep_alive != 1) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_KEEP_ALIVE, + opt_keep_alive); + if (opt_total_timeout > 0 && opt_msg_timeout > 0 + && opt_total_timeout < opt_msg_timeout) { + CMP_err2("-total_timeout argument = %d must not be < %d (-msg_timeout)", + opt_total_timeout, opt_msg_timeout); + goto err; + } + if (opt_msg_timeout >= 0) /* must do this before setup_ssl_ctx() */ + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_MSG_TIMEOUT, + opt_msg_timeout); + if (opt_total_timeout >= 0) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_TOTAL_TIMEOUT, + opt_total_timeout); + + if (opt_reqin != NULL && opt_rspin != NULL) + CMP_warn("-reqin is ignored since -rspin is present"); + if (opt_reqin_new_tid && opt_reqin == NULL) + CMP_warn("-reqin_new_tid is ignored since -reqin is not present"); + if (opt_reqin != NULL || opt_reqout != NULL + || opt_rspin != NULL || opt_rspout != NULL || opt_use_mock_srv) + (void)OSSL_CMP_CTX_set_transfer_cb(ctx, read_write_req_resp); + +#ifndef OPENSSL_NO_SOCK + if (opt_tls_used) { + APP_HTTP_TLS_INFO *info; + + if (opt_tls_cert != NULL + || opt_tls_key != NULL || opt_tls_keypass != NULL) { + if (opt_tls_key == NULL) { + CMP_err("missing -tls_key option"); + goto err; + } else if (opt_tls_cert == NULL) { + CMP_err("missing -tls_cert option"); + goto err; + } + } + + if ((info = OPENSSL_zalloc(sizeof(*info))) == NULL) + goto err; + (void)OSSL_CMP_CTX_set_http_cb_arg(ctx, info); + info->server = opt_server; + info->port = server_port; + /* workaround for callback design flaw, see #17088: */ + info->use_proxy = proxy_host != NULL; + info->timeout = OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_MSG_TIMEOUT); + info->ssl_ctx = setup_ssl_ctx(ctx, host, engine); + + if (info->ssl_ctx == NULL) + goto err; + (void)OSSL_CMP_CTX_set_http_cb(ctx, app_http_tls_cb); + } +#endif + + if (!setup_protection_ctx(ctx, engine)) + goto err; + + if (!setup_request_ctx(ctx, engine)) + goto err; + + if (!set_name(opt_recipient, OSSL_CMP_CTX_set1_recipient, ctx, "recipient") + || !set_name(opt_expect_sender, OSSL_CMP_CTX_set1_expected_sender, + ctx, "expected sender")) + goto err; + + if (opt_geninfo != NULL && !handle_opt_geninfo(ctx)) + goto err; + + /* not printing earlier, to minimize confusion in case setup fails before */ + if (opt_rspin != NULL) + CMP_info("will not contact any server since -rspin is given"); + else + CMP_info2("will contact %s%s", server_buf, proxy_buf); + + ret = 1; + + err: + OPENSSL_free(host); + OPENSSL_free(port); + OPENSSL_free(path); + return ret; + oom: + CMP_err("out of memory"); + goto err; +} + +/* + * write out the given certificate to the output specified by bio. + * Depending on options use either PEM or DER format. + * Returns 1 on success, 0 on error + */ +static int write_cert(BIO *bio, X509 *cert) +{ + if ((opt_certform == FORMAT_PEM && PEM_write_bio_X509(bio, cert)) + || (opt_certform == FORMAT_ASN1 && i2d_X509_bio(bio, cert))) + return 1; + if (opt_certform != FORMAT_PEM && opt_certform != FORMAT_ASN1) + BIO_printf(bio_err, + "error: unsupported type '%s' for writing certificates\n", + opt_certform_s); + return 0; +} + +/* + * If destFile != NULL writes out a stack of certs to the given file. + * In any case frees the certs. + * Depending on options use either PEM or DER format, + * where DER does not make much sense for writing more than one cert! + * Returns number of written certificates on success, -1 on error. + */ +static int save_free_certs(OSSL_CMP_CTX *ctx, + STACK_OF(X509) *certs, char *destFile, char *desc) +{ + BIO *bio = NULL; + int i; + int n = sk_X509_num(certs); + + if (destFile == NULL) + goto end; + CMP_info3("received %d %s certificate(s), saving to file '%s'", + n, desc, destFile); + if (n > 1 && opt_certform != FORMAT_PEM) + CMP_warn("saving more than one certificate in non-PEM format"); + + if (destFile == NULL || (bio = BIO_new(BIO_s_file())) == NULL + || !BIO_write_filename(bio, (char *)destFile)) { + CMP_err1("could not open file '%s' for writing", destFile); + n = -1; + goto end; + } + + for (i = 0; i < n; i++) { + if (!write_cert(bio, sk_X509_value(certs, i))) { + CMP_err1("cannot write certificate to file '%s'", destFile); + n = -1; + goto end; + } + } + + end: + BIO_free(bio); + sk_X509_pop_free(certs, X509_free); + return n; +} + +static void print_itavs(STACK_OF(OSSL_CMP_ITAV) *itavs) +{ + OSSL_CMP_ITAV *itav = NULL; + char buf[128]; + int i, r; + int n = sk_OSSL_CMP_ITAV_num(itavs); /* itavs == NULL leads to 0 */ + + if (n == 0) { + CMP_info("genp contains no ITAV"); + return; + } + + for (i = 0; i < n; i++) { + itav = sk_OSSL_CMP_ITAV_value(itavs, i); + r = OBJ_obj2txt(buf, 128, OSSL_CMP_ITAV_get0_type(itav), 0); + if (r < 0) + CMP_err("could not get ITAV details"); + else if (r == 0) + CMP_info("genp contains empty ITAV"); + else + CMP_info1("genp contains ITAV of type: %s", buf); + } +} + +static char opt_item[SECTION_NAME_MAX + 1]; +/* get previous name from a comma or space-separated list of names */ +static const char *prev_item(const char *opt, const char *end) +{ + const char *beg; + size_t len; + + if (end == opt) + return NULL; + beg = end; + while (beg > opt) { + --beg; + if (beg[0] == ',' || isspace(beg[0])) { + ++beg; + break; + } + } + len = end - beg; + if (len > SECTION_NAME_MAX) { + CMP_warn3("using only first %d characters of section name starting with \"%.*s\"", + SECTION_NAME_MAX, SECTION_NAME_MAX, beg); + len = SECTION_NAME_MAX; + } + memcpy(opt_item, beg, len); + opt_item[len] = '\0'; + while (beg > opt) { + --beg; + if (beg[0] != ',' && !isspace(beg[0])) { + ++beg; + break; + } + } + return beg; +} + +/* get str value for name from a comma-separated hierarchy of config sections */ +static char *conf_get_string(const CONF *src_conf, const char *groups, + const char *name) +{ + char *res = NULL; + const char *end = groups + strlen(groups); + + while ((end = prev_item(groups, end)) != NULL) { + if ((res = NCONF_get_string(src_conf, opt_item, name)) != NULL) + return res; + } + return res; +} + +/* get long val for name from a comma-separated hierarchy of config sections */ +static int conf_get_number_e(const CONF *conf_, const char *groups, + const char *name, long *result) +{ + char *str = conf_get_string(conf_, groups, name); + char *tailptr; + long res; + + if (str == NULL || *str == '\0') + return 0; + + res = strtol(str, &tailptr, 10); + if (res == LONG_MIN || res == LONG_MAX || *tailptr != '\0') + return 0; + + *result = res; + return 1; +} + +/* + * use the command line option table to read values from the CMP section + * of openssl.cnf. Defaults are taken from the config file, they can be + * overwritten on the command line. + */ +static int read_config(void) +{ + unsigned int i; + long num = 0; + char *txt = NULL; + const OPTIONS *opt; + int start_opt = OPT_VERBOSITY - OPT_HELP; + int start_idx = OPT_VERBOSITY - 2; + /* + * starting with offset OPT_VERBOSITY because OPT_CONFIG and OPT_SECTION + * would not make sense within the config file. + */ + int n_options = OSSL_NELEM(cmp_options) - 1; + + for (opt = &cmp_options[start_opt], i = start_idx; + opt->name != NULL; i++, opt++) + if (!strcmp(opt->name, OPT_SECTION_STR) + || !strcmp(opt->name, OPT_MORE_STR)) + n_options--; + OPENSSL_assert(OSSL_NELEM(cmp_vars) == n_options + + OPT_PROV__FIRST + 1 - OPT_PROV__LAST + + OPT_R__FIRST + 1 - OPT_R__LAST + + OPT_V__FIRST + 1 - OPT_V__LAST); + for (opt = &cmp_options[start_opt], i = start_idx; + opt->name != NULL; i++, opt++) { + int provider_option = (OPT_PROV__FIRST <= opt->retval + && opt->retval < OPT_PROV__LAST); + int rand_state_option = (OPT_R__FIRST <= opt->retval + && opt->retval < OPT_R__LAST); + int verification_option = (OPT_V__FIRST <= opt->retval + && opt->retval < OPT_V__LAST); + + if (strcmp(opt->name, OPT_SECTION_STR) == 0 + || strcmp(opt->name, OPT_MORE_STR) == 0) { + i--; + continue; + } + if (provider_option || rand_state_option || verification_option) + i--; + switch (opt->valtype) { + case '-': + case 'p': + case 'n': + case 'N': + case 'l': + if (!conf_get_number_e(conf, opt_section, opt->name, &num)) { + ERR_clear_error(); + continue; /* option not provided */ + } + if (opt->valtype == 'p' && num <= 0) { + opt_printf_stderr("Non-positive number \"%ld\" for config option -%s\n", + num, opt->name); + return -1; + } + if (opt->valtype == 'N' && num < 0) { + opt_printf_stderr("Negative number \"%ld\" for config option -%s\n", + num, opt->name); + return -1; + } + break; + case 's': + case '>': + case 'M': + txt = conf_get_string(conf, opt_section, opt->name); + if (txt == NULL) { + ERR_clear_error(); + continue; /* option not provided */ + } + break; + default: + CMP_err2("internal: unsupported type '%c' for option '%s'", + opt->valtype, opt->name); + return 0; + break; + } + if (provider_option || verification_option) { + int conf_argc = 1; + char *conf_argv[3]; + char arg1[82]; + + BIO_snprintf(arg1, 81, "-%s", (char *)opt->name); + conf_argv[0] = prog; + conf_argv[1] = arg1; + if (opt->valtype == '-') { + if (num != 0) + conf_argc = 2; + } else { + conf_argc = 3; + conf_argv[2] = conf_get_string(conf, opt_section, opt->name); + /* not NULL */ + } + if (conf_argc > 1) { + (void)opt_init(conf_argc, conf_argv, cmp_options); + + if (provider_option + ? !opt_provider(opt_next()) + : !opt_verify(opt_next(), vpm)) { + CMP_err2("for option '%s' in config file section '%s'", + opt->name, opt_section); + return 0; + } + } + } else { + switch (opt->valtype) { + case '-': + case 'p': + case 'n': + case 'N': + if (num < INT_MIN || INT_MAX < num) { + BIO_printf(bio_err, + "integer value out of range for option '%s'\n", + opt->name); + return 0; + } + *cmp_vars[i].num = (int)num; + break; + case 'l': + *cmp_vars[i].num_long = num; + break; + default: + if (txt != NULL && txt[0] == '\0') + txt = NULL; /* reset option on empty string input */ + *cmp_vars[i].txt = txt; + break; + } + } + } + + return 1; +} + +static char *opt_str(void) +{ + char *arg = opt_arg(); + + if (arg[0] == '\0') { + CMP_warn1("%s option argument is empty string, resetting option", + opt_flag()); + arg = NULL; + } else if (arg[0] == '-') { + CMP_warn1("%s option argument starts with hyphen", opt_flag()); + } + return arg; +} + +/* returns 1 on success, 0 on error, -1 on -help (i.e., stop with success) */ +static int get_opts(int argc, char **argv) +{ + OPTION_CHOICE o; + + prog = opt_init(argc, argv, cmp_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); + return 0; + case OPT_HELP: + opt_help(cmp_options); + return -1; + case OPT_CONFIG: /* has already been handled */ + case OPT_SECTION: /* has already been handled */ + break; + case OPT_VERBOSITY: + if (!set_verbosity(opt_int_arg())) + goto opthelp; + break; +#ifndef OPENSSL_NO_SOCK + case OPT_SERVER: + opt_server = opt_str(); + break; + case OPT_PROXY: + opt_proxy = opt_str(); + break; + case OPT_NO_PROXY: + opt_no_proxy = opt_str(); + break; +#endif + case OPT_RECIPIENT: + opt_recipient = opt_str(); + break; + case OPT_PATH: + opt_path = opt_str(); + break; + case OPT_KEEP_ALIVE: + opt_keep_alive = opt_int_arg(); + if (opt_keep_alive > 2) { + CMP_err("-keep_alive argument must be 0, 1, or 2"); + goto opthelp; + } + break; + case OPT_MSG_TIMEOUT: + opt_msg_timeout = opt_int_arg(); + break; + case OPT_TOTAL_TIMEOUT: + opt_total_timeout = opt_int_arg(); + break; +#ifndef OPENSSL_NO_SOCK + case OPT_TLS_USED: + opt_tls_used = 1; + break; + case OPT_TLS_CERT: + opt_tls_cert = opt_str(); + break; + case OPT_TLS_KEY: + opt_tls_key = opt_str(); + break; + case OPT_TLS_KEYPASS: + opt_tls_keypass = opt_str(); + break; + case OPT_TLS_EXTRA: + opt_tls_extra = opt_str(); + break; + case OPT_TLS_TRUSTED: + opt_tls_trusted = opt_str(); + break; + case OPT_TLS_HOST: + opt_tls_host = opt_str(); + break; +#endif + + case OPT_REF: + opt_ref = opt_str(); + break; + case OPT_SECRET: + opt_secret = opt_str(); + break; + case OPT_CERT: + opt_cert = opt_str(); + break; + case OPT_OWN_TRUSTED: + opt_own_trusted = opt_str(); + break; + case OPT_KEY: + opt_key = opt_str(); + break; + case OPT_KEYPASS: + opt_keypass = opt_str(); + break; + case OPT_DIGEST: + opt_digest = opt_str(); + break; + case OPT_MAC: + opt_mac = opt_str(); + break; + case OPT_EXTRACERTS: + opt_extracerts = opt_str(); + break; + case OPT_UNPROTECTED_REQUESTS: + opt_unprotected_requests = 1; + break; + + case OPT_TRUSTED: + opt_trusted = opt_str(); + break; + case OPT_UNTRUSTED: + opt_untrusted = opt_str(); + break; + case OPT_SRVCERT: + opt_srvcert = opt_str(); + break; + case OPT_EXPECT_SENDER: + opt_expect_sender = opt_str(); + break; + case OPT_IGNORE_KEYUSAGE: + opt_ignore_keyusage = 1; + break; + case OPT_UNPROTECTED_ERRORS: + opt_unprotected_errors = 1; + break; + case OPT_EXTRACERTSOUT: + opt_extracertsout = opt_str(); + break; + case OPT_CACERTSOUT: + opt_cacertsout = opt_str(); + break; + + case OPT_V_CASES: + if (!opt_verify(o, vpm)) + goto opthelp; + break; + case OPT_CMD: + opt_cmd_s = opt_str(); + break; + case OPT_INFOTYPE: + opt_infotype_s = opt_str(); + break; + case OPT_GENINFO: + opt_geninfo = opt_str(); + break; + + case OPT_NEWKEY: + opt_newkey = opt_str(); + break; + case OPT_NEWKEYPASS: + opt_newkeypass = opt_str(); + break; + case OPT_SUBJECT: + opt_subject = opt_str(); + break; + case OPT_ISSUER: + opt_issuer = opt_str(); + break; + case OPT_DAYS: + opt_days = opt_int_arg(); + break; + case OPT_REQEXTS: + opt_reqexts = opt_str(); + break; + case OPT_SANS: + opt_sans = opt_str(); + break; + case OPT_SAN_NODEFAULT: + opt_san_nodefault = 1; + break; + case OPT_POLICIES: + opt_policies = opt_str(); + break; + case OPT_POLICY_OIDS: + opt_policy_oids = opt_str(); + break; + case OPT_POLICY_OIDS_CRITICAL: + opt_policy_oids_critical = 1; + break; + case OPT_POPO: + opt_popo = opt_int_arg(); + if (opt_popo < OSSL_CRMF_POPO_NONE + || opt_popo > OSSL_CRMF_POPO_KEYENC) { + CMP_err("invalid popo spec. Valid values are -1 .. 2"); + goto opthelp; + } + break; + case OPT_CSR: + opt_csr = opt_arg(); + break; + case OPT_OUT_TRUSTED: + opt_out_trusted = opt_str(); + break; + case OPT_IMPLICIT_CONFIRM: + opt_implicit_confirm = 1; + break; + case OPT_DISABLE_CONFIRM: + opt_disable_confirm = 1; + break; + case OPT_CERTOUT: + opt_certout = opt_str(); + break; + case OPT_CHAINOUT: + opt_chainout = opt_str(); + break; + case OPT_OLDCERT: + opt_oldcert = opt_str(); + break; + case OPT_REVREASON: + opt_revreason = opt_int_arg(); + if (opt_revreason < CRL_REASON_NONE + || opt_revreason > CRL_REASON_AA_COMPROMISE + || opt_revreason == 7) { + CMP_err("invalid revreason. Valid values are -1 .. 6, 8 .. 10"); + goto opthelp; + } + break; + case OPT_CERTFORM: + opt_certform_s = opt_str(); + break; + case OPT_KEYFORM: + opt_keyform_s = opt_str(); + break; + case OPT_OTHERPASS: + opt_otherpass = opt_str(); + break; +#ifndef OPENSSL_NO_ENGINE + case OPT_ENGINE: + opt_engine = opt_str(); + break; +#endif + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto opthelp; + break; + case OPT_R_CASES: + if (!opt_rand(o)) + goto opthelp; + break; + + case OPT_BATCH: + opt_batch = 1; + break; + case OPT_REPEAT: + opt_repeat = opt_int_arg(); + break; + case OPT_REQIN: + opt_reqin = opt_str(); + break; + case OPT_REQIN_NEW_TID: + opt_reqin_new_tid = 1; + break; + case OPT_REQOUT: + opt_reqout = opt_str(); + break; + case OPT_RSPIN: + opt_rspin = opt_str(); + break; + case OPT_RSPOUT: + opt_rspout = opt_str(); + break; + case OPT_USE_MOCK_SRV: + opt_use_mock_srv = 1; + break; + +#ifndef OPENSSL_NO_SOCK + case OPT_PORT: + opt_port = opt_str(); + break; + case OPT_MAX_MSGS: + opt_max_msgs = opt_int_arg(); + break; +#endif + case OPT_SRV_REF: + opt_srv_ref = opt_str(); + break; + case OPT_SRV_SECRET: + opt_srv_secret = opt_str(); + break; + case OPT_SRV_CERT: + opt_srv_cert = opt_str(); + break; + case OPT_SRV_KEY: + opt_srv_key = opt_str(); + break; + case OPT_SRV_KEYPASS: + opt_srv_keypass = opt_str(); + break; + case OPT_SRV_TRUSTED: + opt_srv_trusted = opt_str(); + break; + case OPT_SRV_UNTRUSTED: + opt_srv_untrusted = opt_str(); + break; + case OPT_RSP_CERT: + opt_rsp_cert = opt_str(); + break; + case OPT_RSP_EXTRACERTS: + opt_rsp_extracerts = opt_str(); + break; + case OPT_RSP_CAPUBS: + opt_rsp_capubs = opt_str(); + break; + case OPT_POLL_COUNT: + opt_poll_count = opt_int_arg(); + break; + case OPT_CHECK_AFTER: + opt_check_after = opt_int_arg(); + break; + case OPT_GRANT_IMPLICITCONF: + opt_grant_implicitconf = 1; + break; + case OPT_PKISTATUS: + opt_pkistatus = opt_int_arg(); + break; + case OPT_FAILURE: + opt_failure = opt_int_arg(); + break; + case OPT_FAILUREBITS: + opt_failurebits = opt_int_arg(); + break; + case OPT_STATUSSTRING: + opt_statusstring = opt_str(); + break; + case OPT_SEND_ERROR: + opt_send_error = 1; + break; + case OPT_SEND_UNPROTECTED: + opt_send_unprotected = 1; + break; + case OPT_SEND_UNPROT_ERR: + opt_send_unprot_err = 1; + break; + case OPT_ACCEPT_UNPROTECTED: + opt_accept_unprotected = 1; + break; + case OPT_ACCEPT_UNPROT_ERR: + opt_accept_unprot_err = 1; + break; + case OPT_ACCEPT_RAVERIFIED: + opt_accept_raverified = 1; + break; + } + } + + /* No extra args. */ + argc = opt_num_rest(); + argv = opt_rest(); + if (argc != 0) + goto opthelp; + return 1; +} + +#ifndef OPENSSL_NO_SOCK +static int cmp_server(OSSL_CMP_CTX *srv_cmp_ctx) { + BIO *acbio; + BIO *cbio = NULL; + int keep_alive = 0; + int msgs = 0; + int retry = 1; + int ret = 1; + + if ((acbio = http_server_init_bio(prog, opt_port)) == NULL) + return 0; + while (opt_max_msgs <= 0 || msgs < opt_max_msgs) { + char *path = NULL; + OSSL_CMP_MSG *req = NULL; + OSSL_CMP_MSG *resp = NULL; + + ret = http_server_get_asn1_req(ASN1_ITEM_rptr(OSSL_CMP_MSG), + (ASN1_VALUE **)&req, &path, + &cbio, acbio, &keep_alive, + prog, opt_port, 0, 0); + if (ret == 0) { /* no request yet */ + if (retry) { + ossl_sleep(1000); + retry = 0; + continue; + } + ret = 0; + goto next; + } + if (ret++ == -1) /* fatal error */ + break; + + ret = 0; + msgs++; + if (req != NULL) { + if (strcmp(path, "") != 0 && strcmp(path, "pkix/") != 0) { + (void)http_server_send_status(cbio, 404, "Not Found"); + CMP_err1("expecting empty path or 'pkix/' but got '%s'", + path); + OPENSSL_free(path); + OSSL_CMP_MSG_free(req); + goto next; + } + OPENSSL_free(path); + resp = OSSL_CMP_CTX_server_perform(cmp_ctx, req); + OSSL_CMP_MSG_free(req); + if (resp == NULL) { + (void)http_server_send_status(cbio, + 500, "Internal Server Error"); + break; /* treated as fatal error */ + } + ret = http_server_send_asn1_resp(cbio, keep_alive, + "application/pkixcmp", + ASN1_ITEM_rptr(OSSL_CMP_MSG), + (const ASN1_VALUE *)resp); + OSSL_CMP_MSG_free(resp); + if (!ret) + break; /* treated as fatal error */ + } + next: + if (!ret) { /* on transmission error, cancel CMP transaction */ + (void)OSSL_CMP_CTX_set1_transactionID(srv_cmp_ctx, NULL); + (void)OSSL_CMP_CTX_set1_senderNonce(srv_cmp_ctx, NULL); + } + if (!ret || !keep_alive + || OSSL_CMP_CTX_get_status(srv_cmp_ctx) != OSSL_CMP_PKISTATUS_trans + /* transaction closed by OSSL_CMP_CTX_server_perform() */) { + BIO_free_all(cbio); + cbio = NULL; + } + } + + BIO_free_all(cbio); + BIO_free_all(acbio); + return ret; +} +#endif + +static void print_status(void) +{ + /* print PKIStatusInfo */ + int status = OSSL_CMP_CTX_get_status(cmp_ctx); + char *buf = app_malloc(OSSL_CMP_PKISI_BUFLEN, "PKIStatusInfo buf"); + const char *string = + OSSL_CMP_CTX_snprint_PKIStatus(cmp_ctx, buf, OSSL_CMP_PKISI_BUFLEN); + const char *from = "", *server = ""; + +#ifndef OPENSSL_NO_SOCK + if (opt_server != NULL) { + from = " from "; + server = opt_server; + } +#endif + CMP_print(bio_err, + status == OSSL_CMP_PKISTATUS_accepted + ? OSSL_CMP_LOG_INFO : + status == OSSL_CMP_PKISTATUS_rejection + || status == OSSL_CMP_PKISTATUS_waiting + ? OSSL_CMP_LOG_ERR : OSSL_CMP_LOG_WARNING, + status == OSSL_CMP_PKISTATUS_accepted ? "info" : + status == OSSL_CMP_PKISTATUS_rejection ? "server error" : + status == OSSL_CMP_PKISTATUS_waiting ? "internal error" + : "warning", "received%s%s %s", from, server, + string != NULL ? string : "<unknown PKIStatus>"); + OPENSSL_free(buf); +} + +int cmp_main(int argc, char **argv) +{ + char *configfile = NULL; + int i; + X509 *newcert = NULL; + ENGINE *engine = NULL; + OSSL_CMP_CTX *srv_cmp_ctx = NULL; + int ret = 0; /* default: failure */ + + prog = opt_appname(argv[0]); + if (argc <= 1) { + opt_help(cmp_options); + goto err; + } + + /* + * handle options -config, -section, and -verbosity upfront + * to take effect for other options + */ + for (i = 1; i < argc - 1; i++) { + if (*argv[i] == '-') { + if (!strcmp(argv[i] + 1, cmp_options[OPT_CONFIG - OPT_HELP].name)) + opt_config = argv[++i]; + else if (!strcmp(argv[i] + 1, + cmp_options[OPT_SECTION - OPT_HELP].name)) + opt_section = argv[++i]; + else if (strcmp(argv[i] + 1, + cmp_options[OPT_VERBOSITY - OPT_HELP].name) == 0 + && !set_verbosity(atoi(argv[++i]))) + goto err; + } + } + if (opt_section[0] == '\0') /* empty string */ + opt_section = DEFAULT_SECTION; + + vpm = X509_VERIFY_PARAM_new(); + if (vpm == NULL) { + CMP_err("out of memory"); + goto err; + } + + /* read default values for options from config file */ + configfile = opt_config != NULL ? opt_config : default_config_file; + if (configfile != NULL && configfile[0] != '\0' /* non-empty string */ + && (configfile != default_config_file || access(configfile, F_OK) != -1)) { + CMP_info2("using section(s) '%s' of OpenSSL configuration file '%s'", + opt_section, configfile); + conf = app_load_config(configfile); + if (conf == NULL) { + goto err; + } else { + if (strcmp(opt_section, CMP_SECTION) == 0) { /* default */ + if (!NCONF_get_section(conf, opt_section)) + CMP_info2("no [%s] section found in config file '%s';" + " will thus use just [default] and unnamed section if present", + opt_section, configfile); + } else { + const char *end = opt_section + strlen(opt_section); + while ((end = prev_item(opt_section, end)) != NULL) { + if (!NCONF_get_section(conf, opt_item)) { + CMP_err2("no [%s] section found in config file '%s'", + opt_item, configfile); + goto err; + } + } + } + ret = read_config(); + if (!set_verbosity(opt_verbosity)) /* just for checking range */ + ret = -1; + if (ret <= 0) { + if (ret == -1) + BIO_printf(bio_err, "Use -help for summary.\n"); + goto err; + } + } + } + (void)BIO_flush(bio_err); /* prevent interference with opt_help() */ + + ret = get_opts(argc, argv); + if (ret <= 0) + goto err; + ret = 0; + if (!app_RAND_load()) + goto err; + + if (opt_batch) + set_base_ui_method(UI_null()); + + if (opt_engine != NULL) { + engine = setup_engine_methods(opt_engine, 0 /* not: ENGINE_METHOD_ALL */, 0); + if (engine == NULL) { + CMP_err1("cannot load engine %s", opt_engine); + goto err; + } + } + + cmp_ctx = OSSL_CMP_CTX_new(app_get0_libctx(), app_get0_propq()); + if (cmp_ctx == NULL) + goto err; + OSSL_CMP_CTX_set_log_verbosity(cmp_ctx, opt_verbosity); + if (!OSSL_CMP_CTX_set_log_cb(cmp_ctx, print_to_bio_out)) { + CMP_err1("cannot set up error reporting and logging for %s", prog); + goto err; + } + +#ifndef OPENSSL_NO_SOCK + if ((opt_tls_cert != NULL || opt_tls_key != NULL + || opt_tls_keypass != NULL || opt_tls_extra != NULL + || opt_tls_trusted != NULL || opt_tls_host != NULL) + && !opt_tls_used) + CMP_warn("Ingnoring TLS options(s) since -tls_used is not given"); + if (opt_port != NULL) { + if (opt_tls_used) { + CMP_err("-tls_used option not supported with -port option"); + goto err; + } + if (opt_use_mock_srv || opt_server != NULL || opt_rspin != NULL) { + CMP_err("cannot use -port with -use_mock_srv, -server, or -rspin options"); + goto err; + } + } + if (opt_server != NULL && opt_use_mock_srv) { + CMP_err("cannot use both -server and -use_mock_srv options"); + goto err; + } +#endif + if (opt_rspin != NULL && opt_use_mock_srv) { + CMP_err("cannot use both -rspin and -use_mock_srv options"); + goto err; + } + + if (opt_use_mock_srv +#ifndef OPENSSL_NO_SOCK + || opt_port != NULL +#endif + ) { + OSSL_CMP_SRV_CTX *srv_ctx; + + if ((srv_ctx = setup_srv_ctx(engine)) == NULL) + goto err; + srv_cmp_ctx = OSSL_CMP_SRV_CTX_get0_cmp_ctx(srv_ctx); + OSSL_CMP_CTX_set_transfer_cb_arg(cmp_ctx, srv_ctx); + if (!OSSL_CMP_CTX_set_log_cb(srv_cmp_ctx, print_to_bio_err)) { + CMP_err1("cannot set up error reporting and logging for %s", prog); + goto err; + } + OSSL_CMP_CTX_set_log_verbosity(srv_cmp_ctx, opt_verbosity); + } + +#ifndef OPENSSL_NO_SOCK + if (opt_tls_used && (opt_use_mock_srv || opt_rspin != NULL)) { + CMP_warn("ignoring -tls_used option since -use_mock_srv or -rspin is given"); + opt_tls_used = 0; + } + + if (opt_port != NULL) { /* act as very basic CMP HTTP server */ + ret = cmp_server(srv_cmp_ctx); + goto err; + } + + /* act as CMP client, possibly using internal mock server */ + + if (opt_server != NULL) { + if (opt_rspin != NULL) { + CMP_warn("ignoring -server option since -rspin is given"); + opt_server = NULL; + } + } +#endif + + if (!setup_client_ctx(cmp_ctx, engine)) { + CMP_err("cannot set up CMP context"); + goto err; + } + for (i = 0; i < opt_repeat; i++) { + /* everything is ready, now connect and perform the command! */ + switch (opt_cmd) { + case CMP_IR: + newcert = OSSL_CMP_exec_IR_ses(cmp_ctx); + if (newcert != NULL) + ret = 1; + break; + case CMP_KUR: + newcert = OSSL_CMP_exec_KUR_ses(cmp_ctx); + if (newcert != NULL) + ret = 1; + break; + case CMP_CR: + newcert = OSSL_CMP_exec_CR_ses(cmp_ctx); + if (newcert != NULL) + ret = 1; + break; + case CMP_P10CR: + newcert = OSSL_CMP_exec_P10CR_ses(cmp_ctx); + if (newcert != NULL) + ret = 1; + break; + case CMP_RR: + ret = OSSL_CMP_exec_RR_ses(cmp_ctx); + break; + case CMP_GENM: + { + STACK_OF(OSSL_CMP_ITAV) *itavs; + + if (opt_infotype != NID_undef) { + OSSL_CMP_ITAV *itav = + OSSL_CMP_ITAV_create(OBJ_nid2obj(opt_infotype), NULL); + if (itav == NULL) + goto err; + OSSL_CMP_CTX_push0_genm_ITAV(cmp_ctx, itav); + } + + if ((itavs = OSSL_CMP_exec_GENM_ses(cmp_ctx)) != NULL) { + print_itavs(itavs); + sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free); + ret = 1; + } + break; + } + default: + break; + } + if (OSSL_CMP_CTX_get_status(cmp_ctx) < OSSL_CMP_PKISTATUS_accepted) + goto err; /* we got no response, maybe even did not send request */ + + print_status(); + if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_extraCertsIn(cmp_ctx), + opt_extracertsout, "extra") < 0) + ret = 0; + if (!ret) + goto err; + ret = 0; + if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_caPubs(cmp_ctx), + opt_cacertsout, "CA") < 0) + goto err; + if (newcert != NULL) { + STACK_OF(X509) *certs = sk_X509_new_null(); + + if (!X509_add_cert(certs, newcert, X509_ADD_FLAG_UP_REF)) { + sk_X509_free(certs); + goto err; + } + if (save_free_certs(cmp_ctx, certs, opt_certout, "enrolled") < 0) + goto err; + } + if (save_free_certs(cmp_ctx, OSSL_CMP_CTX_get1_newChain(cmp_ctx), + opt_chainout, "chain") < 0) + goto err; + + if (!OSSL_CMP_CTX_reinit(cmp_ctx)) + goto err; + } + ret = 1; + + err: + /* in case we ended up here on error without proper cleaning */ + cleanse(opt_keypass); + cleanse(opt_newkeypass); + cleanse(opt_otherpass); +#ifndef OPENSSL_NO_SOCK + cleanse(opt_tls_keypass); +#endif + cleanse(opt_secret); + cleanse(opt_srv_keypass); + cleanse(opt_srv_secret); + + if (ret != 1) + OSSL_CMP_CTX_print_errors(cmp_ctx); + + if (cmp_ctx != NULL) { +#ifndef OPENSSL_NO_SOCK + APP_HTTP_TLS_INFO *info = OSSL_CMP_CTX_get_http_cb_arg(cmp_ctx); + +#endif + ossl_cmp_mock_srv_free(OSSL_CMP_CTX_get_transfer_cb_arg(cmp_ctx)); + X509_STORE_free(OSSL_CMP_CTX_get_certConf_cb_arg(cmp_ctx)); + /* cannot free info already here, as it may be used indirectly by: */ + OSSL_CMP_CTX_free(cmp_ctx); +#ifndef OPENSSL_NO_SOCK + APP_HTTP_TLS_INFO_free(info); +#endif + } + X509_VERIFY_PARAM_free(vpm); + release_engine(engine); + + NCONF_free(conf); /* must not do as long as opt_... variables are used */ + OSSL_CMP_log_close(); + + return ret == 0 ? EXIT_FAILURE : EXIT_SUCCESS; /* ret == -1 for -help */ +} diff --git a/apps/cms.c b/apps/cms.c index 71554037d0b7..76c789671937 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -1,7 +1,7 @@ /* - * Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,43 +14,41 @@ #include "apps.h" #include "progs.h" -#ifndef OPENSSL_NO_CMS - -# include <openssl/crypto.h> -# include <openssl/pem.h> -# include <openssl/err.h> -# include <openssl/x509_vfy.h> -# include <openssl/x509v3.h> -# include <openssl/cms.h> +#include <openssl/crypto.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509v3.h> +#include <openssl/cms.h> static int save_certs(char *signerfile, STACK_OF(X509) *signers); static int cms_cb(int ok, X509_STORE_CTX *ctx); static void receipt_request_print(CMS_ContentInfo *cms); -static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) - *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING) - *rr_from); +static CMS_ReceiptRequest +*make_receipt_request(STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst, + STACK_OF(OPENSSL_STRING) *rr_from); static int cms_set_pkey_param(EVP_PKEY_CTX *pctx, STACK_OF(OPENSSL_STRING) *param); -# define SMIME_OP 0x10 -# define SMIME_IP 0x20 -# define SMIME_SIGNERS 0x40 -# define SMIME_ENCRYPT (1 | SMIME_OP) -# define SMIME_DECRYPT (2 | SMIME_IP) -# define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS) -# define SMIME_VERIFY (4 | SMIME_IP) -# define SMIME_CMSOUT (5 | SMIME_IP | SMIME_OP) -# define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS) -# define SMIME_DATAOUT (7 | SMIME_IP) -# define SMIME_DATA_CREATE (8 | SMIME_OP) -# define SMIME_DIGEST_VERIFY (9 | SMIME_IP) -# define SMIME_DIGEST_CREATE (10 | SMIME_OP) -# define SMIME_UNCOMPRESS (11 | SMIME_IP) -# define SMIME_COMPRESS (12 | SMIME_OP) -# define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) -# define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP) -# define SMIME_SIGN_RECEIPT (15 | SMIME_IP | SMIME_OP) -# define SMIME_VERIFY_RECEIPT (16 | SMIME_IP) +#define SMIME_OP 0x100 +#define SMIME_IP 0x200 +#define SMIME_SIGNERS 0x400 +#define SMIME_ENCRYPT (1 | SMIME_OP) +#define SMIME_DECRYPT (2 | SMIME_IP) +#define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS) +#define SMIME_VERIFY (4 | SMIME_IP) +#define SMIME_RESIGN (5 | SMIME_IP | SMIME_OP | SMIME_SIGNERS) +#define SMIME_SIGN_RECEIPT (6 | SMIME_IP | SMIME_OP) +#define SMIME_VERIFY_RECEIPT (7 | SMIME_IP) +#define SMIME_DIGEST_CREATE (8 | SMIME_OP) +#define SMIME_DIGEST_VERIFY (9 | SMIME_IP) +#define SMIME_COMPRESS (10 | SMIME_OP) +#define SMIME_UNCOMPRESS (11 | SMIME_IP) +#define SMIME_ENCRYPTED_ENCRYPT (12 | SMIME_OP) +#define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) +#define SMIME_DATA_CREATE (14 | SMIME_OP) +#define SMIME_DATA_OUT (15 | SMIME_IP) +#define SMIME_CMSOUT (16 | SMIME_IP | SMIME_OP) static int verify_err = 0; @@ -63,9 +61,9 @@ struct cms_key_param_st { }; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENCRYPT, - OPT_DECRYPT, OPT_SIGN, OPT_SIGN_RECEIPT, OPT_RESIGN, + OPT_DECRYPT, OPT_SIGN, OPT_CADES, OPT_SIGN_RECEIPT, OPT_RESIGN, OPT_VERIFY, OPT_VERIFY_RETCODE, OPT_VERIFY_RECEIPT, OPT_CMSOUT, OPT_DATA_OUT, OPT_DATA_CREATE, OPT_DIGEST_VERIFY, OPT_DIGEST_CREATE, OPT_COMPRESS, OPT_UNCOMPRESS, @@ -75,151 +73,246 @@ typedef enum OPTION_choice { OPT_NOSIGS, OPT_NO_CONTENT_VERIFY, OPT_NO_ATTR_VERIFY, OPT_INDEF, OPT_NOINDEF, OPT_CRLFEOL, OPT_NOOUT, OPT_RR_PRINT, OPT_RR_ALL, OPT_RR_FIRST, OPT_RCTFORM, OPT_CERTFILE, OPT_CAFILE, - OPT_CAPATH, OPT_NOCAPATH, OPT_NOCAFILE,OPT_CONTENT, OPT_PRINT, + OPT_CAPATH, OPT_CASTORE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, + OPT_CONTENT, OPT_PRINT, OPT_NAMEOPT, OPT_SECRETKEY, OPT_SECRETKEYID, OPT_PWRI_PASSWORD, OPT_ECONTENT_TYPE, OPT_PASSIN, OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP, OPT_CERTSOUT, OPT_MD, OPT_INKEY, OPT_KEYFORM, OPT_KEYOPT, OPT_RR_FROM, OPT_RR_TO, OPT_AES128_WRAP, OPT_AES192_WRAP, OPT_AES256_WRAP, - OPT_3DES_WRAP, OPT_ENGINE, + OPT_3DES_WRAP, OPT_WRAP, OPT_ENGINE, OPT_R_ENUM, + OPT_PROV_ENUM, OPT_CONFIG, OPT_V_ENUM, - OPT_CIPHER + OPT_CIPHER, + OPT_ORIGINATOR } OPTION_CHOICE; const OPTIONS cms_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"}, - {OPT_HELP_STR, 1, '-', - " cert.pem... recipient certs for encryption\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert...]\n"}, {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"}, - {"outform", OPT_OUTFORM, 'c', - "Output format SMIME (default), PEM or DER"}, + + OPT_SECTION("General"), {"in", OPT_IN, '<', "Input file"}, {"out", OPT_OUT, '>', "Output file"}, + OPT_CONFIG_OPTION, + + OPT_SECTION("Operation"), {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"}, {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"}, {"sign", OPT_SIGN, '-', "Sign message"}, - {"sign_receipt", OPT_SIGN_RECEIPT, '-', "Generate a signed receipt for the message"}, - {"resign", OPT_RESIGN, '-', "Resign a signed message"}, {"verify", OPT_VERIFY, '-', "Verify signed message"}, - {"verify_retcode", OPT_VERIFY_RETCODE, '-'}, - {"verify_receipt", OPT_VERIFY_RECEIPT, '<'}, + {"resign", OPT_RESIGN, '-', "Resign a signed message"}, + {"sign_receipt", OPT_SIGN_RECEIPT, '-', + "Generate a signed receipt for a message"}, + {"verify_receipt", OPT_VERIFY_RECEIPT, '<', + "Verify receipts; exit if receipt signatures do not verify"}, + {"digest_create", OPT_DIGEST_CREATE, '-', + "Create a CMS \"DigestedData\" object"}, + {"digest_verify", OPT_DIGEST_VERIFY, '-', + "Verify a CMS \"DigestedData\" object and output it"}, + {"compress", OPT_COMPRESS, '-', "Create a CMS \"CompressedData\" object"}, + {"uncompress", OPT_UNCOMPRESS, '-', + "Uncompress a CMS \"CompressedData\" object"}, + {"EncryptedData_encrypt", OPT_ED_ENCRYPT, '-', + "Create CMS \"EncryptedData\" object using symmetric key"}, + {"EncryptedData_decrypt", OPT_ED_DECRYPT, '-', + "Decrypt CMS \"EncryptedData\" object using symmetric key"}, + {"data_create", OPT_DATA_CREATE, '-', "Create a CMS \"Data\" object"}, + {"data_out", OPT_DATA_OUT, '-', "Copy CMS \"Data\" object to output"}, {"cmsout", OPT_CMSOUT, '-', "Output CMS structure"}, - {"data_out", OPT_DATA_OUT, '-'}, - {"data_create", OPT_DATA_CREATE, '-'}, - {"digest_verify", OPT_DIGEST_VERIFY, '-'}, - {"digest_create", OPT_DIGEST_CREATE, '-'}, - {"compress", OPT_COMPRESS, '-'}, - {"uncompress", OPT_UNCOMPRESS, '-'}, - {"EncryptedData_decrypt", OPT_ED_DECRYPT, '-'}, - {"EncryptedData_encrypt", OPT_ED_ENCRYPT, '-'}, - {"debug_decrypt", OPT_DEBUG_DECRYPT, '-'}, - {"text", OPT_TEXT, '-', "Include or delete text MIME headers"}, - {"asciicrlf", OPT_ASCIICRLF, '-'}, - {"nointern", OPT_NOINTERN, '-', - "Don't search certificates in message for signer"}, - {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"}, - {"nocerts", OPT_NOCERTS, '-', - "Don't include signers certificate when signing"}, - {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"}, - {"nodetach", OPT_NODETACH, '-', "Use opaque signing"}, - {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, - {"binary", OPT_BINARY, '-', "Don't translate message to text"}, - {"keyid", OPT_KEYID, '-', "Use subject key identifier"}, - {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, - {"no_content_verify", OPT_NO_CONTENT_VERIFY, '-'}, - {"no_attr_verify", OPT_NO_ATTR_VERIFY, '-'}, + + OPT_SECTION("File format"), + {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"}, + {"outform", OPT_OUTFORM, 'c', + "Output format SMIME (default), PEM or DER"}, + {"rctform", OPT_RCTFORM, 'F', "Receipt file format"}, {"stream", OPT_INDEF, '-', "Enable CMS streaming"}, {"indef", OPT_INDEF, '-', "Same as -stream"}, {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"}, - {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only" }, - {"noout", OPT_NOOUT, '-', "For the -cmsout operation do not output the parsed CMS structure"}, - {"receipt_request_print", OPT_RR_PRINT, '-', "Print CMS Receipt Request" }, - {"receipt_request_all", OPT_RR_ALL, '-'}, - {"receipt_request_first", OPT_RR_FIRST, '-'}, - {"rctform", OPT_RCTFORM, 'F', "Receipt file format"}, + {"binary", OPT_BINARY, '-', + "Treat input as binary: do not translate to canonical form"}, + {"crlfeol", OPT_CRLFEOL, '-', + "Use CRLF as EOL termination instead of CR only" }, + {"asciicrlf", OPT_ASCIICRLF, '-', + "Perform CRLF canonicalisation when signing"}, + + OPT_SECTION("Keys and passwords"), + {"pwri_password", OPT_PWRI_PASSWORD, 's', + "Specific password for recipient"}, + {"secretkey", OPT_SECRETKEY, 's', + "Use specified hex-encoded key to decrypt/encrypt recipients or content"}, + {"secretkeyid", OPT_SECRETKEYID, 's', + "Identity of the -secretkey for CMS \"KEKRecipientInfo\" object"}, + {"inkey", OPT_INKEY, 's', + "Input private key (if not signer or recipient)"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"keyopt", OPT_KEYOPT, 's', "Set public key parameters as n:v pairs"}, + {"keyform", OPT_KEYFORM, 'f', + "Input private key format (ENGINE, other values ignored)"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, +#endif + OPT_PROV_OPTIONS, + OPT_R_OPTIONS, + + OPT_SECTION("Encryption and decryption"), + {"originator", OPT_ORIGINATOR, 's', "Originator certificate file"}, + {"recip", OPT_RECIP, '<', "Recipient cert file"}, + {"cert...", OPT_PARAM, '.', + "Recipient certs (optional; used only when encrypting)"}, + {"", OPT_CIPHER, '-', + "The encryption algorithm to use (any supported cipher)"}, + {"wrap", OPT_WRAP, 's', + "Key wrap algorithm to use when encrypting with key agreement"}, + {"aes128-wrap", OPT_AES128_WRAP, '-', "Use AES128 to wrap key"}, + {"aes192-wrap", OPT_AES192_WRAP, '-', "Use AES192 to wrap key"}, + {"aes256-wrap", OPT_AES256_WRAP, '-', "Use AES256 to wrap key"}, + {"des3-wrap", OPT_3DES_WRAP, '-', "Use 3DES-EDE to wrap key"}, + {"debug_decrypt", OPT_DEBUG_DECRYPT, '-', + "Disable MMA protection, return error if no recipient found (see doc)"}, + + OPT_SECTION("Signing"), + {"md", OPT_MD, 's', "Digest algorithm to use"}, + {"signer", OPT_SIGNER, 's', "Signer certificate input file"}, {"certfile", OPT_CERTFILE, '<', "Other certificates file"}, + {"cades", OPT_CADES, '-', + "Include signingCertificate attribute (CAdES-BES)"}, + {"nodetach", OPT_NODETACH, '-', "Use opaque signing"}, + {"nocerts", OPT_NOCERTS, '-', + "Don't include signer's certificate when signing"}, + {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"}, + {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, + {"receipt_request_all", OPT_RR_ALL, '-', + "When signing, create a receipt request for all recipients"}, + {"receipt_request_first", OPT_RR_FIRST, '-', + "When signing, create a receipt request for first recipient"}, + {"receipt_request_from", OPT_RR_FROM, 's', + "Create signed receipt request with specified email address"}, + {"receipt_request_to", OPT_RR_TO, 's', + "Create signed receipt targeted to specified address"}, + + OPT_SECTION("Verification"), + {"signer", OPT_DUP, 's', "Signer certificate(s) output file"}, + {"content", OPT_CONTENT, '<', + "Supply or override content for detached signature"}, + {"no_content_verify", OPT_NO_CONTENT_VERIFY, '-', + "Do not verify signed content signatures"}, + {"no_attr_verify", OPT_NO_ATTR_VERIFY, '-', + "Do not verify signed attribute signatures"}, + {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, + {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"}, + {"nointern", OPT_NOINTERN, '-', + "Don't search certificates in message for signer"}, + {"cades", OPT_DUP, '-', "Check signingCertificate (CAdES-BES)"}, + {"verify_retcode", OPT_VERIFY_RETCODE, '-', + "Exit non-zero on verification failure"}, {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, - {"CApath", OPT_CAPATH, '/', "trusted certificates directory"}, + {"CApath", OPT_CAPATH, '/', "Trusted certificates directory"}, + {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"}, {"no-CAfile", OPT_NOCAFILE, '-', "Do not load the default certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', "Do not load certificates from the default certificates directory"}, - {"content", OPT_CONTENT, '<', - "Supply or override content for detached signature"}, - {"print", OPT_PRINT, '-', - "For the -cmsout operation print out all fields of the CMS structure"}, - {"secretkey", OPT_SECRETKEY, 's'}, - {"secretkeyid", OPT_SECRETKEYID, 's'}, - {"pwri_password", OPT_PWRI_PASSWORD, 's'}, - {"econtent_type", OPT_ECONTENT_TYPE, 's'}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store"}, + + OPT_SECTION("Output"), + {"keyid", OPT_KEYID, '-', "Use subject key identifier"}, + {"econtent_type", OPT_ECONTENT_TYPE, 's', "OID for external content"}, + {"text", OPT_TEXT, '-', "Include or delete text MIME headers"}, + {"certsout", OPT_CERTSOUT, '>', "Certificate output file"}, {"to", OPT_TO, 's', "To address"}, {"from", OPT_FROM, 's', "From address"}, {"subject", OPT_SUBJECT, 's', "Subject"}, - {"signer", OPT_SIGNER, 's', "Signer certificate file"}, - {"recip", OPT_RECIP, '<', "Recipient cert file for decryption"}, - {"certsout", OPT_CERTSOUT, '>', "Certificate output file"}, - {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"}, - {"inkey", OPT_INKEY, 's', - "Input private key (if not signer or recipient)"}, - {"keyform", OPT_KEYFORM, 'f', "Input private key format (PEM or ENGINE)"}, - {"keyopt", OPT_KEYOPT, 's', "Set public key parameters as n:v pairs"}, - {"receipt_request_from", OPT_RR_FROM, 's'}, - {"receipt_request_to", OPT_RR_TO, 's'}, - {"", OPT_CIPHER, '-', "Any supported cipher"}, - OPT_R_OPTIONS, + + OPT_SECTION("Printing"), + {"noout", OPT_NOOUT, '-', + "For the -cmsout operation do not output the parsed CMS structure"}, + {"print", OPT_PRINT, '-', + "For the -cmsout operation print out all fields of the CMS structure"}, + {"nameopt", OPT_NAMEOPT, 's', + "For the -print option specifies various strings printing options"}, + {"receipt_request_print", OPT_RR_PRINT, '-', "Print CMS Receipt Request" }, + OPT_V_OPTIONS, - {"aes128-wrap", OPT_AES128_WRAP, '-', "Use AES128 to wrap key"}, - {"aes192-wrap", OPT_AES192_WRAP, '-', "Use AES192 to wrap key"}, - {"aes256-wrap", OPT_AES256_WRAP, '-', "Use AES256 to wrap key"}, -# ifndef OPENSSL_NO_DES - {"des3-wrap", OPT_3DES_WRAP, '-', "Use 3DES-EDE to wrap key"}, -# endif -# ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, -# endif {NULL} }; +static CMS_ContentInfo *load_content_info(int informat, BIO *in, int flags, + BIO **indata, const char *name) +{ + CMS_ContentInfo *ret, *ci; + + ret = CMS_ContentInfo_new_ex(app_get0_libctx(), app_get0_propq()); + if (ret == NULL) { + BIO_printf(bio_err, "Error allocating CMS_contentinfo\n"); + return NULL; + } + switch (informat) { + case FORMAT_SMIME: + ci = SMIME_read_CMS_ex(in, flags, indata, &ret); + break; + case FORMAT_PEM: + ci = PEM_read_bio_CMS(in, &ret, NULL, NULL); + break; + case FORMAT_ASN1: + ci = d2i_CMS_bio(in, &ret); + break; + default: + BIO_printf(bio_err, "Bad input format for %s\n", name); + goto err; + } + if (ci == NULL) { + BIO_printf(bio_err, "Error reading %s Content Info\n", name); + goto err; + } + return ret; + err: + CMS_ContentInfo_free(ret); + return NULL; +} + int cms_main(int argc, char **argv) { + CONF *conf = NULL; ASN1_OBJECT *econtent_type = NULL; BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL; CMS_ContentInfo *cms = NULL, *rcms = NULL; CMS_ReceiptRequest *rr = NULL; ENGINE *e = NULL; EVP_PKEY *key = NULL; - const EVP_CIPHER *cipher = NULL, *wrap_cipher = NULL; - const EVP_MD *sign_md = NULL; + EVP_CIPHER *cipher = NULL, *wrap_cipher = NULL; + EVP_MD *sign_md = NULL; STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL; STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL; - STACK_OF(X509) *encerts = NULL, *other = NULL; - X509 *cert = NULL, *recip = NULL, *signer = NULL; + STACK_OF(X509) *encerts = sk_X509_new_null(), *other = NULL; + X509 *cert = NULL, *recip = NULL, *signer = NULL, *originator = NULL; X509_STORE *store = NULL; - X509_VERIFY_PARAM *vpm = NULL; + X509_VERIFY_PARAM *vpm = X509_VERIFY_PARAM_new(); char *certfile = NULL, *keyfile = NULL, *contfile = NULL; - const char *CAfile = NULL, *CApath = NULL; - char *certsoutfile = NULL; - int noCAfile = 0, noCApath = 0; + const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL; + char *certsoutfile = NULL, *digestname = NULL, *wrapname = NULL; + int noCAfile = 0, noCApath = 0, noCAstore = 0; char *infile = NULL, *outfile = NULL, *rctfile = NULL; - char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *recipfile = NULL; + char *passinarg = NULL, *passin = NULL, *signerfile = NULL; + char *originatorfile = NULL, *recipfile = NULL, *ciphername = NULL; char *to = NULL, *from = NULL, *subject = NULL, *prog; cms_key_param *key_first = NULL, *key_param = NULL; - int flags = CMS_DETACHED, noout = 0, print = 0, keyidx = -1, vpmtouched = 0; + int flags = CMS_DETACHED, binary_files = 0; + int noout = 0, print = 0, keyidx = -1, vpmtouched = 0; int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; int operation = 0, ret = 1, rr_print = 0, rr_allorfirst = -1; - int verify_retcode = 0, rctformat = FORMAT_SMIME, keyform = FORMAT_PEM; + int verify_retcode = 0, rctformat = FORMAT_SMIME, keyform = FORMAT_UNDEF; size_t secret_keylen = 0, secret_keyidlen = 0; unsigned char *pwri_pass = NULL, *pwri_tmp = NULL; unsigned char *secret_key = NULL, *secret_keyid = NULL; long ltmp; const char *mime_eol = "\n"; OPTION_CHOICE o; + OSSL_LIB_CTX *libctx = app_get0_libctx(); - if ((vpm = X509_VERIFY_PARAM_new()) == NULL) - return 1; + if (encerts == NULL || vpm == NULL) + goto end; prog = opt_init(argc, argv, cms_options); while ((o = opt_next()) != OPT_EOF) { @@ -244,6 +337,7 @@ int cms_main(int argc, char **argv) case OPT_OUT: outfile = opt_arg(); break; + case OPT_ENCRYPT: operation = SMIME_ENCRYPT; break; @@ -253,49 +347,50 @@ int cms_main(int argc, char **argv) case OPT_SIGN: operation = SMIME_SIGN; break; - case OPT_SIGN_RECEIPT: - operation = SMIME_SIGN_RECEIPT; + case OPT_VERIFY: + operation = SMIME_VERIFY; break; case OPT_RESIGN: operation = SMIME_RESIGN; break; - case OPT_VERIFY: - operation = SMIME_VERIFY; - break; - case OPT_VERIFY_RETCODE: - verify_retcode = 1; + case OPT_SIGN_RECEIPT: + operation = SMIME_SIGN_RECEIPT; break; case OPT_VERIFY_RECEIPT: operation = SMIME_VERIFY_RECEIPT; rctfile = opt_arg(); break; - case OPT_CMSOUT: - operation = SMIME_CMSOUT; - break; - case OPT_DATA_OUT: - operation = SMIME_DATAOUT; + case OPT_VERIFY_RETCODE: + verify_retcode = 1; break; - case OPT_DATA_CREATE: - operation = SMIME_DATA_CREATE; + case OPT_DIGEST_CREATE: + operation = SMIME_DIGEST_CREATE; break; case OPT_DIGEST_VERIFY: operation = SMIME_DIGEST_VERIFY; break; - case OPT_DIGEST_CREATE: - operation = SMIME_DIGEST_CREATE; - break; case OPT_COMPRESS: operation = SMIME_COMPRESS; break; case OPT_UNCOMPRESS: operation = SMIME_UNCOMPRESS; break; + case OPT_ED_ENCRYPT: + operation = SMIME_ENCRYPTED_ENCRYPT; + break; case OPT_ED_DECRYPT: operation = SMIME_ENCRYPTED_DECRYPT; break; - case OPT_ED_ENCRYPT: - operation = SMIME_ENCRYPTED_ENCRYPT; + case OPT_DATA_CREATE: + operation = SMIME_DATA_CREATE; + break; + case OPT_DATA_OUT: + operation = SMIME_DATA_OUT; break; + case OPT_CMSOUT: + operation = SMIME_CMSOUT; + break; + case OPT_DEBUG_DECRYPT: flags |= CMS_DEBUG_DECRYPT; break; @@ -326,6 +421,9 @@ int cms_main(int argc, char **argv) case OPT_BINARY: flags |= CMS_BINARY; break; + case OPT_CADES: + flags |= CMS_CADES; + break; case OPT_KEYID: flags |= CMS_USE_KEYID; break; @@ -361,14 +459,9 @@ int cms_main(int argc, char **argv) rr_allorfirst = 1; break; case OPT_RCTFORM: - if (rctformat == FORMAT_SMIME) - rcms = SMIME_read_CMS(rctin, NULL); - else if (rctformat == FORMAT_PEM) - rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); - else if (rctformat == FORMAT_ASN1) - if (!opt_format(opt_arg(), - OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat)) - goto opthelp; + if (!opt_format(opt_arg(), + OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat)) + goto opthelp; break; case OPT_CERTFILE: certfile = opt_arg(); @@ -379,12 +472,18 @@ int cms_main(int argc, char **argv) case OPT_CAPATH: CApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_NOCAFILE: noCAfile = 1; break; case OPT_NOCAPATH: noCApath = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_IN: infile = opt_arg(); break; @@ -406,6 +505,10 @@ int cms_main(int argc, char **argv) case OPT_PRINT: noout = print = 1; break; + case OPT_NAMEOPT: + if (!set_nameopt(opt_arg())) + goto opthelp; + break; case OPT_SECRETKEY: if (secret_key != NULL) { BIO_printf(bio_err, "Invalid key (supplied twice) %s\n", @@ -466,8 +569,7 @@ int cms_main(int argc, char **argv) certsoutfile = opt_arg(); break; case OPT_MD: - if (!opt_md(opt_arg(), &sign_md)) - goto end; + digestname = opt_arg(); break; case OPT_SIGNER: /* If previous -signer argument add signer to list */ @@ -486,6 +588,9 @@ int cms_main(int argc, char **argv) } signerfile = opt_arg(); break; + case OPT_ORIGINATOR: + originatorfile = opt_arg(); + break; case OPT_INKEY: /* If previous -inkey argument add signer to list */ if (keyfile != NULL) { @@ -511,9 +616,7 @@ int cms_main(int argc, char **argv) break; case OPT_RECIP: if (operation == SMIME_ENCRYPT) { - if (encerts == NULL && (encerts = sk_X509_new_null()) == NULL) - goto end; - cert = load_cert(opt_arg(), FORMAT_PEM, + cert = load_cert(opt_arg(), FORMAT_UNDEF, "recipient certificate file"); if (cert == NULL) goto end; @@ -524,13 +627,12 @@ int cms_main(int argc, char **argv) } break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &cipher)) - goto end; + ciphername = opt_unknown(); break; case OPT_KEYOPT: keyidx = -1; if (operation == SMIME_ENCRYPT) { - if (encerts != NULL) + if (sk_X509_num(encerts) > 0) keyidx += sk_X509_num(encerts); } else { if (keyfile != NULL || signerfile != NULL) @@ -568,22 +670,43 @@ int cms_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; - case OPT_3DES_WRAP: -# ifndef OPENSSL_NO_DES - wrap_cipher = EVP_des_ede3_wrap(); -# endif + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; break; - case OPT_AES128_WRAP: - wrap_cipher = EVP_aes_128_wrap(); + case OPT_CONFIG: + conf = app_load_config_modules(opt_arg()); + if (conf == NULL) + goto end; break; - case OPT_AES192_WRAP: - wrap_cipher = EVP_aes_192_wrap(); + case OPT_WRAP: + wrapname = opt_arg(); break; + case OPT_AES128_WRAP: + case OPT_AES192_WRAP: case OPT_AES256_WRAP: - wrap_cipher = EVP_aes_256_wrap(); + case OPT_3DES_WRAP: + wrapname = opt_flag() + 1; break; } } + if (!app_RAND_load()) + goto end; + + if (digestname != NULL) { + if (!opt_md(digestname, &sign_md)) + goto end; + } + if (ciphername != NULL) { + if (!opt_cipher_any(ciphername, &cipher)) + goto end; + } + if (wrapname != NULL) { + if (!opt_cipher_any(wrapname, &wrap_cipher)) + goto end; + } + + /* Remaining args are files to process. */ argc = opt_num_rest(); argv = opt_rest(); @@ -601,6 +724,20 @@ int cms_main(int argc, char **argv) goto opthelp; } + if ((flags & CMS_CADES) != 0) { + if ((flags & CMS_NOATTR) != 0) { + BIO_puts(bio_err, "Incompatible options: " + "CAdES requires signed attributes\n"); + goto opthelp; + } + if (operation == SMIME_VERIFY + && (flags & (CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY)) != 0) { + BIO_puts(bio_err, "Incompatible options: CAdES validation requires" + " certs and signed attributes validations\n"); + goto opthelp; + } + } + if (operation & SMIME_SIGNERS) { if (keyfile != NULL && signerfile == NULL) { BIO_puts(bio_err, "Illegal -inkey without -signer\n"); @@ -633,7 +770,7 @@ int cms_main(int argc, char **argv) } } else if (operation == SMIME_ENCRYPT) { if (*argv == NULL && secret_key == NULL - && pwri_pass == NULL && encerts == NULL) { + && pwri_pass == NULL && sk_X509_num(encerts) <= 0) { BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); goto opthelp; } @@ -649,25 +786,36 @@ int cms_main(int argc, char **argv) ret = 2; - if (!(operation & SMIME_SIGNERS)) + if ((operation & SMIME_SIGNERS) == 0) { + if ((flags & CMS_DETACHED) == 0) + BIO_printf(bio_err, + "Warning: -nodetach option is ignored for non-signing operation\n"); + flags &= ~CMS_DETACHED; + } + if ((operation & SMIME_IP) == 0 && contfile != NULL) + BIO_printf(bio_err, + "Warning: -contfile option is ignored for the given operation\n"); - if (!(operation & SMIME_OP)) - if (flags & CMS_BINARY) + if ((flags & CMS_BINARY) != 0) { + if (!(operation & SMIME_OP)) outformat = FORMAT_BINARY; - - if (!(operation & SMIME_IP)) - if (flags & CMS_BINARY) + if (!(operation & SMIME_IP)) informat = FORMAT_BINARY; + if ((operation & SMIME_SIGNERS) != 0 && (flags & CMS_DETACHED) != 0) + binary_files = 1; + if ((operation & SMIME_IP) != 0 && contfile == NULL) + binary_files = 1; + } if (operation == SMIME_ENCRYPT) { if (!cipher) { -# ifndef OPENSSL_NO_DES - cipher = EVP_des_ede3_cbc(); -# else +#ifndef OPENSSL_NO_DES + cipher = (EVP_CIPHER *)EVP_des_ede3_cbc(); +#else BIO_printf(bio_err, "No cipher selected\n"); goto end; -# endif +#endif } if (secret_key && !secret_keyid) { @@ -675,44 +823,54 @@ int cms_main(int argc, char **argv) goto end; } - if (*argv && encerts == NULL) - if ((encerts = sk_X509_new_null()) == NULL) - goto end; - while (*argv) { - if ((cert = load_cert(*argv, FORMAT_PEM, - "recipient certificate file")) == NULL) - goto end; - sk_X509_push(encerts, cert); - cert = NULL; - argv++; + if (*argv != NULL) { + if (operation == SMIME_ENCRYPT) { + for (; *argv != NULL; argv++) { + cert = load_cert(*argv, FORMAT_UNDEF, + "recipient certificate file"); + if (cert == NULL) + goto end; + sk_X509_push(encerts, cert); + cert = NULL; + } + } else { + BIO_printf(bio_err, "Warning: recipient certificate file parameters ignored for operation other than -encrypt\n"); + } } } if (certfile != NULL) { - if (!load_certs(certfile, &other, FORMAT_PEM, NULL, - "certificate file")) { + if (!load_certs(certfile, 0, &other, NULL, "certificate file")) { ERR_print_errors(bio_err); goto end; } } if (recipfile != NULL && (operation == SMIME_DECRYPT)) { - if ((recip = load_cert(recipfile, FORMAT_PEM, + if ((recip = load_cert(recipfile, FORMAT_UNDEF, "recipient certificate file")) == NULL) { ERR_print_errors(bio_err); goto end; } } + if (originatorfile != NULL) { + if ((originator = load_cert(originatorfile, FORMAT_UNDEF, + "originator certificate file")) == NULL) { + ERR_print_errors(bio_err); + goto end; + } + } + if (operation == SMIME_SIGN_RECEIPT) { - if ((signer = load_cert(signerfile, FORMAT_PEM, + if ((signer = load_cert(signerfile, FORMAT_UNDEF, "receipt signer certificate file")) == NULL) { ERR_print_errors(bio_err); goto end; } } - if (operation == SMIME_DECRYPT) { + if ((operation == SMIME_DECRYPT) || (operation == SMIME_ENCRYPT)) { if (keyfile == NULL) keyfile = recipfile; } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) { @@ -723,31 +881,20 @@ int cms_main(int argc, char **argv) } if (keyfile != NULL) { - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key"); if (key == NULL) goto end; } - in = bio_open_default(infile, 'r', informat); + in = bio_open_default(infile, 'r', + binary_files ? FORMAT_BINARY : informat); if (in == NULL) goto end; if (operation & SMIME_IP) { - if (informat == FORMAT_SMIME) { - cms = SMIME_read_CMS(in, &indata); - } else if (informat == FORMAT_PEM) { - cms = PEM_read_bio_CMS(in, NULL, NULL, NULL); - } else if (informat == FORMAT_ASN1) { - cms = d2i_CMS_bio(in, NULL); - } else { - BIO_printf(bio_err, "Bad input format for CMS file\n"); - goto end; - } - - if (cms == NULL) { - BIO_printf(bio_err, "Error reading S/MIME message\n"); + cms = load_content_info(informat, in, flags, &indata, "SMIME"); + if (cms == NULL) goto end; - } if (contfile != NULL) { BIO_free(indata); if ((indata = BIO_new_file(contfile, "rb")) == NULL) { @@ -770,34 +917,25 @@ int cms_main(int argc, char **argv) if (rctfile != NULL) { char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; + if ((rctin = BIO_new_file(rctfile, rctmode)) == NULL) { BIO_printf(bio_err, "Can't open receipt file %s\n", rctfile); goto end; } - if (rctformat == FORMAT_SMIME) { - rcms = SMIME_read_CMS(rctin, NULL); - } else if (rctformat == FORMAT_PEM) { - rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); - } else if (rctformat == FORMAT_ASN1) { - rcms = d2i_CMS_bio(rctin, NULL); - } else { - BIO_printf(bio_err, "Bad input format for receipt\n"); - goto end; - } - - if (rcms == NULL) { - BIO_printf(bio_err, "Error reading receipt\n"); + rcms = load_content_info(rctformat, rctin, 0, NULL, "receipt"); + if (rcms == NULL) goto end; - } } - out = bio_open_default(outfile, 'w', outformat); + out = bio_open_default(outfile, 'w', + binary_files ? FORMAT_BINARY : outformat); if (out == NULL) goto end; if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) { - if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) + if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) == NULL) goto end; X509_STORE_set_verify_cb(store, cms_cb); if (vpmtouched) @@ -807,39 +945,49 @@ int cms_main(int argc, char **argv) ret = 3; if (operation == SMIME_DATA_CREATE) { - cms = CMS_data_create(in, flags); + cms = CMS_data_create_ex(in, flags, libctx, app_get0_propq()); } else if (operation == SMIME_DIGEST_CREATE) { - cms = CMS_digest_create(in, sign_md, flags); + cms = CMS_digest_create_ex(in, sign_md, flags, libctx, app_get0_propq()); } else if (operation == SMIME_COMPRESS) { cms = CMS_compress(in, -1, flags); } else if (operation == SMIME_ENCRYPT) { int i; flags |= CMS_PARTIAL; - cms = CMS_encrypt(NULL, in, cipher, flags); + cms = CMS_encrypt_ex(NULL, in, cipher, flags, libctx, app_get0_propq()); if (cms == NULL) goto end; for (i = 0; i < sk_X509_num(encerts); i++) { CMS_RecipientInfo *ri; cms_key_param *kparam; - int tflags = flags; + int tflags = flags | CMS_KEY_PARAM; + /* This flag enforces allocating the EVP_PKEY_CTX for the recipient here */ + EVP_PKEY_CTX *pctx; X509 *x = sk_X509_value(encerts, i); + int res; + for (kparam = key_first; kparam; kparam = kparam->next) { if (kparam->idx == i) { - tflags |= CMS_KEY_PARAM; break; } } - ri = CMS_add1_recipient_cert(cms, x, tflags); + ri = CMS_add1_recipient(cms, x, key, originator, tflags); if (ri == NULL) goto end; + + pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (kparam != NULL) { - EVP_PKEY_CTX *pctx; - pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); if (!cms_set_pkey_param(pctx, kparam->param)) goto end; } + + res = EVP_PKEY_CTX_ctrl(pctx, -1, -1, + EVP_PKEY_CTRL_CIPHER, + EVP_CIPHER_get_nid(cipher), NULL); + if (res <= 0 && res != -2) + goto end; + if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE - && wrap_cipher) { + && wrap_cipher != NULL) { EVP_CIPHER_CTX *wctx; wctx = CMS_RecipientInfo_kari_get0_ctx(ri); EVP_EncryptInit_ex(wctx, wrap_cipher, NULL, NULL, NULL); @@ -871,8 +1019,8 @@ int cms_main(int argc, char **argv) goto end; } } else if (operation == SMIME_ENCRYPTED_ENCRYPT) { - cms = CMS_EncryptedData_encrypt(in, cipher, - secret_key, secret_keylen, flags); + cms = CMS_EncryptedData_encrypt_ex(in, cipher, secret_key, + secret_keylen, flags, libctx, app_get0_propq()); } else if (operation == SMIME_SIGN_RECEIPT) { CMS_ContentInfo *srcms = NULL; @@ -900,19 +1048,17 @@ int cms_main(int argc, char **argv) flags |= CMS_STREAM; } flags |= CMS_PARTIAL; - cms = CMS_sign(NULL, NULL, other, in, flags); + cms = CMS_sign_ex(NULL, NULL, other, in, flags, libctx, app_get0_propq()); if (cms == NULL) goto end; if (econtent_type != NULL) CMS_set1_eContentType(cms, econtent_type); - if (rr_to != NULL) { - rr = make_receipt_request(rr_to, rr_allorfirst, rr_from); - if (rr == NULL) { - BIO_puts(bio_err, - "Signed Receipt Request Creation Error\n"); - goto end; - } + if (rr_to != NULL + && ((rr = make_receipt_request(rr_to, rr_allorfirst, rr_from)) + == NULL)) { + BIO_puts(bio_err, "Signed Receipt Request Creation Error\n"); + goto end; } } else { flags |= CMS_REUSE_DIGEST; @@ -924,16 +1070,17 @@ int cms_main(int argc, char **argv) signerfile = sk_OPENSSL_STRING_value(sksigners, i); keyfile = sk_OPENSSL_STRING_value(skkeys, i); - signer = load_cert(signerfile, FORMAT_PEM, "signer certificate"); + signer = load_cert(signerfile, FORMAT_UNDEF, "signer certificate"); if (signer == NULL) { ret = 2; goto end; } - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key"); if (key == NULL) { ret = 2; goto end; } + for (kparam = key_first; kparam; kparam = kparam->next) { if (kparam->idx == i) { tflags |= CMS_KEY_PARAM; @@ -983,7 +1130,7 @@ int cms_main(int argc, char **argv) } if (key != NULL) { - if (!CMS_decrypt_set1_pkey(cms, key, recip)) { + if (!CMS_decrypt_set1_pkey_and_peer(cms, key, recip, originator)) { BIO_puts(bio_err, "Error decrypting CMS using private key\n"); goto end; } @@ -1000,7 +1147,7 @@ int cms_main(int argc, char **argv) BIO_printf(bio_err, "Error decrypting CMS structure\n"); goto end; } - } else if (operation == SMIME_DATAOUT) { + } else if (operation == SMIME_DATA_OUT) { if (!CMS_data(cms, out, flags)) goto end; } else if (operation == SMIME_UNCOMPRESS) { @@ -1019,16 +1166,18 @@ int cms_main(int argc, char **argv) goto end; } else if (operation == SMIME_VERIFY) { if (CMS_verify(cms, other, store, indata, out, flags) > 0) { - BIO_printf(bio_err, "Verification successful\n"); + BIO_printf(bio_err, "%s Verification successful\n", + (flags & CMS_CADES) != 0 ? "CAdES" : "CMS"); } else { - BIO_printf(bio_err, "Verification failure\n"); + BIO_printf(bio_err, "%s Verification failure\n", + (flags & CMS_CADES) != 0 ? "CAdES" : "CMS"); if (verify_retcode) ret = verify_err + 32; goto end; } if (signerfile != NULL) { - STACK_OF(X509) *signers; - signers = CMS_get0_signers(cms); + STACK_OF(X509) *signers = CMS_get0_signers(cms); + if (!save_certs(signerfile, signers)) { BIO_printf(bio_err, "Error writing signers to %s\n", signerfile); @@ -1049,8 +1198,19 @@ int cms_main(int argc, char **argv) } } else { if (noout) { - if (print) - CMS_ContentInfo_print_ctx(out, cms, 0, NULL); + if (print) { + ASN1_PCTX *pctx = NULL; + if (get_nameopt() != XN_FLAG_ONELINE) { + pctx = ASN1_PCTX_new(); + if (pctx != NULL) { /* Print anyway if malloc failed */ + ASN1_PCTX_set_flags(pctx, ASN1_PCTX_FLAGS_SHOW_ABSENT); + ASN1_PCTX_set_str_flags(pctx, get_nameopt()); + ASN1_PCTX_set_nm_flags(pctx, get_nameopt()); + } + } + CMS_ContentInfo_print_ctx(out, cms, 0, pctx); + ASN1_PCTX_free(pctx); + } } else if (outformat == FORMAT_SMIME) { if (to) BIO_printf(out, "To: %s%s", to, mime_eol); @@ -1103,6 +1263,9 @@ int cms_main(int argc, char **argv) X509_free(recip); X509_free(signer); EVP_PKEY_free(key); + EVP_CIPHER_free(cipher); + EVP_CIPHER_free(wrap_cipher); + EVP_MD_free(sign_md); CMS_ContentInfo_free(cms); CMS_ContentInfo_free(rcms); release_engine(e); @@ -1111,6 +1274,7 @@ int cms_main(int argc, char **argv) BIO_free(indata); BIO_free_all(out); OPENSSL_free(passin); + NCONF_free(conf); return ret; } @@ -1247,12 +1411,12 @@ static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(OPENSSL_STRING) *ns) return NULL; } -static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) - *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING) - *rr_from) +static CMS_ReceiptRequest +*make_receipt_request(STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst, + STACK_OF(OPENSSL_STRING) *rr_from) { STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL; - CMS_ReceiptRequest *rr; + rct_to = make_names_stack(rr_to); if (rct_to == NULL) goto err; @@ -1263,9 +1427,8 @@ static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) } else { rct_from = NULL; } - rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from, - rct_to); - return rr; + return CMS_ReceiptRequest_create0_ex(NULL, -1, rr_allorfirst, rct_from, + rct_to, app_get0_libctx()); err: sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free); return NULL; @@ -1288,5 +1451,3 @@ static int cms_set_pkey_param(EVP_PKEY_CTX *pctx, } return 1; } - -#endif diff --git a/apps/crl.c b/apps/crl.c index 031fada14c84..2158a107e551 100644 --- a/apps/crl.c +++ b/apps/crl.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -19,22 +19,38 @@ #include <openssl/pem.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY, OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT, - OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE, - OPT_NOCAPATH, OPT_NOCAFILE, OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD, - OPT_NOOUT, OPT_NAMEOPT, OPT_MD + OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE, + OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_VERIFY, OPT_DATEOPT, OPT_TEXT, OPT_HASH, + OPT_HASH_OLD, OPT_NOOUT, OPT_NAMEOPT, OPT_MD, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS crl_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format; default PEM"}, + {"verify", OPT_VERIFY, '-', "Verify CRL signature"}, + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file - default stdin"}, - {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, - {"out", OPT_OUT, '>', "output file - default stdout"}, - {"keyform", OPT_KEYFORM, 'F', "Private key file format (PEM or ENGINE)"}, + {"inform", OPT_INFORM, 'F', "CRL input format (DER or PEM); has no effect"}, {"key", OPT_KEY, '<', "CRL signing Private key to use"}, + {"keyform", OPT_KEYFORM, 'F', "Private key file format (DER/PEM/P12); has no effect"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "output file - default stdout"}, + {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, + {"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."}, + {"text", OPT_TEXT, '-', "Print out a text format version"}, + {"hash", OPT_HASH, '-', "Print hash value"}, +#ifndef OPENSSL_NO_MD5 + {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"}, +#endif + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, + {"", OPT_MD, '-', "Any supported digest"}, + + OPT_SECTION("CRL"), {"issuer", OPT_ISSUER, '-', "Print issuer DN"}, {"lastupdate", OPT_LASTUPDATE, '-', "Set lastUpdate field"}, {"nextupdate", OPT_NEXTUPDATE, '-', "Set nextUpdate field"}, @@ -43,20 +59,18 @@ const OPTIONS crl_options[] = { {"crlnumber", OPT_CRLNUMBER, '-', "Print CRL number"}, {"badsig", OPT_BADSIG, '-', "Corrupt last byte of loaded CRL signature (for test)" }, {"gendelta", OPT_GENDELTA, '<', "Other CRL to compare/diff to the Input one"}, + + OPT_SECTION("Certificate"), {"CApath", OPT_CAPATH, '/', "Verify CRL using certificates in dir"}, {"CAfile", OPT_CAFILE, '<', "Verify CRL using certificates in file name"}, + {"CAstore", OPT_CASTORE, ':', "Verify CRL using certificates in store URI"}, {"no-CAfile", OPT_NOCAFILE, '-', "Do not load the default certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', "Do not load certificates from the default certificates directory"}, - {"verify", OPT_VERIFY, '-', "Verify CRL signature"}, - {"text", OPT_TEXT, '-', "Print out a text format version"}, - {"hash", OPT_HASH, '-', "Print hash value"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, - {"", OPT_MD, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_MD5 - {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"}, -#endif + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store"}, + OPT_PROV_OPTIONS, {NULL} }; @@ -69,14 +83,16 @@ int crl_main(int argc, char **argv) X509_LOOKUP *lookup = NULL; X509_OBJECT *xobj = NULL; EVP_PKEY *pkey; - const EVP_MD *digest = EVP_sha1(); + EVP_MD *digest = (EVP_MD *)EVP_sha1(); char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL; - const char *CAfile = NULL, *CApath = NULL, *prog; + char *digestname = NULL; + const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL, *prog; OPTION_CHOICE o; int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyformat = FORMAT_UNDEF; int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0; - int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0; + int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0, noCAstore = 0; + unsigned long dateopt = ASN1_DTFLGS_RFC822; int i; #ifndef OPENSSL_NO_MD5 int hash_old = 0; @@ -109,7 +125,7 @@ int crl_main(int argc, char **argv) outfile = opt_arg(); break; case OPT_KEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyformat)) goto opthelp; break; case OPT_KEY: @@ -126,12 +142,19 @@ int crl_main(int argc, char **argv) CAfile = opt_arg(); do_ver = 1; break; + case OPT_CASTORE: + CAstore = opt_arg(); + do_ver = 1; + break; case OPT_NOCAPATH: noCApath = 1; break; case OPT_NOCAFILE: noCAfile = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_HASH_OLD: #ifndef OPENSSL_NO_MD5 hash_old = ++num; @@ -140,6 +163,10 @@ int crl_main(int argc, char **argv) case OPT_VERIFY: do_ver = 1; break; + case OPT_DATEOPT: + if (!set_dateopt(&dateopt, opt_arg())) + goto opthelp; + break; case OPT_TEXT: text = 1; break; @@ -156,7 +183,7 @@ int crl_main(int argc, char **argv) nextupdate = ++num; break; case OPT_NOOUT: - noout = ++num; + noout = 1; break; case OPT_FINGERPRINT: fingerprint = ++num; @@ -172,20 +199,31 @@ int crl_main(int argc, char **argv) goto opthelp; break; case OPT_MD: - if (!opt_md(opt_unknown(), &digest)) - goto opthelp; + digestname = opt_unknown(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No remaining args. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; - x = load_crl(infile, informat); + if (digestname != NULL) { + if (!opt_md(digestname, &digest)) + goto opthelp; + } + x = load_crl(infile, informat, 1, "CRL"); if (x == NULL) goto end; if (do_ver) { - if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) + if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) == NULL) goto end; lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if (lookup == NULL) @@ -204,7 +242,7 @@ int crl_main(int argc, char **argv) } pkey = X509_get_pubkey(X509_OBJECT_get0_X509(xobj)); X509_OBJECT_free(xobj); - if (!pkey) { + if (pkey == NULL) { BIO_printf(bio_err, "Error getting CRL issuer public key\n"); goto end; } @@ -218,17 +256,17 @@ int crl_main(int argc, char **argv) BIO_printf(bio_err, "verify OK\n"); } - if (crldiff) { + if (crldiff != NULL) { X509_CRL *newcrl, *delta; if (!keyfile) { BIO_puts(bio_err, "Missing CRL signing key\n"); goto end; } - newcrl = load_crl(crldiff, informat); + newcrl = load_crl(crldiff, informat, 0, "other CRL"); if (!newcrl) goto end; pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key"); - if (!pkey) { + if (pkey == NULL) { X509_CRL_free(newcrl); goto end; } @@ -254,39 +292,54 @@ int crl_main(int argc, char **argv) if (num) { for (i = 1; i <= num; i++) { if (issuer == i) { - print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), - get_nameopt()); + print_name(bio_out, "issuer=", X509_CRL_get_issuer(x)); } if (crlnumber == i) { ASN1_INTEGER *crlnum; + crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL); BIO_printf(bio_out, "crlNumber="); if (crlnum) { + BIO_puts(bio_out, "0x"); i2a_ASN1_INTEGER(bio_out, crlnum); ASN1_INTEGER_free(crlnum); - } else + } else { BIO_puts(bio_out, "<NONE>"); + } BIO_printf(bio_out, "\n"); } if (hash == i) { - BIO_printf(bio_out, "%08lx\n", - X509_NAME_hash(X509_CRL_get_issuer(x))); + int ok; + unsigned long hash_value = + X509_NAME_hash_ex(X509_CRL_get_issuer(x), app_get0_libctx(), + app_get0_propq(), &ok); + + if (num > 1) + BIO_printf(bio_out, "issuer name hash="); + if (ok) { + BIO_printf(bio_out, "%08lx\n", hash_value); + } else { + BIO_puts(bio_out, "<ERROR>"); + goto end; + } } #ifndef OPENSSL_NO_MD5 if (hash_old == i) { + if (num > 1) + BIO_printf(bio_out, "issuer name old hash="); BIO_printf(bio_out, "%08lx\n", X509_NAME_hash_old(X509_CRL_get_issuer(x))); } #endif if (lastupdate == i) { BIO_printf(bio_out, "lastUpdate="); - ASN1_TIME_print(bio_out, X509_CRL_get0_lastUpdate(x)); + ASN1_TIME_print_ex(bio_out, X509_CRL_get0_lastUpdate(x), dateopt); BIO_printf(bio_out, "\n"); } if (nextupdate == i) { BIO_printf(bio_out, "nextUpdate="); if (X509_CRL_get0_nextUpdate(x)) - ASN1_TIME_print(bio_out, X509_CRL_get0_nextUpdate(x)); + ASN1_TIME_print_ex(bio_out, X509_CRL_get0_nextUpdate(x), dateopt); else BIO_printf(bio_out, "NONE"); BIO_printf(bio_out, "\n"); @@ -301,7 +354,7 @@ int crl_main(int argc, char **argv) goto end; } BIO_printf(bio_out, "%s Fingerprint=", - OBJ_nid2sn(EVP_MD_type(digest))); + EVP_MD_get0_name(digest)); for (j = 0; j < (int)n; j++) { BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n) ? '\n' : ':'); @@ -335,6 +388,7 @@ int crl_main(int argc, char **argv) if (ret != 0) ERR_print_errors(bio_err); BIO_free_all(out); + EVP_MD_free(digest); X509_CRL_free(x); X509_STORE_CTX_free(ctx); X509_STORE_free(store); diff --git a/apps/crl2p7.c b/apps/crl2pkcs7.c index 3f619bf5278e..fe59e654270d 100644 --- a/apps/crl2p7.c +++ b/apps/crl2pkcs7.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -22,19 +22,27 @@ static int add_certs_from_file(STACK_OF(X509) *stack, char *certfile); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_NOCRL, OPT_CERTFILE + OPT_COMMON, + OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_NOCRL, OPT_CERTFILE, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS crl2pkcs7_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, - {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, + {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, {"nocrl", OPT_NOCRL, '-', "No crl to load, just certs from '-certfile'"}, {"certfile", OPT_CERTFILE, '<', "File of chain of certs to a trusted CA; can be repeated"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, + + OPT_PROV_OPTIONS, {NULL} }; @@ -88,8 +96,14 @@ int crl2pkcs7_main(int argc, char **argv) if (!sk_OPENSSL_STRING_push(certflst, opt_arg())) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No remaining args. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; diff --git a/apps/dgst.c b/apps/dgst.c index f9b184be4cc1..1042d940f49c 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -24,7 +24,7 @@ #undef BUFSIZE #define BUFSIZE 1024*8 -int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, +int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen, EVP_PKEY *key, unsigned char *sigin, int siglen, const char *sig_name, const char *md_name, const char *file); @@ -36,49 +36,58 @@ struct doall_dgst_digests { }; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_LIST, + OPT_COMMON, + OPT_LIST, OPT_C, OPT_R, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY, OPT_PRVERIFY, OPT_SIGNATURE, OPT_KEYFORM, OPT_ENGINE, OPT_ENGINE_IMPL, OPT_HEX, OPT_BINARY, OPT_DEBUG, OPT_FIPS_FINGERPRINT, - OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, + OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, OPT_XOFLEN, OPT_DIGEST, - OPT_R_ENUM + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS dgst_options[] = { {OPT_HELP_STR, 1, '-', "Usage: %s [options] [file...]\n"}, - {OPT_HELP_STR, 1, '-', - " file... files to digest (default is stdin)\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, {"list", OPT_LIST, '-', "List digests"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, + {"engine_impl", OPT_ENGINE_IMPL, '-', + "Also use engine given by -engine for digest operations"}, +#endif + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + + OPT_SECTION("Output"), {"c", OPT_C, '-', "Print the digest with separating colons"}, {"r", OPT_R, '-', "Print the digest in coreutils format"}, {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"sign", OPT_SIGN, 's', "Sign digest using private key"}, - {"verify", OPT_VERIFY, 's', - "Verify a signature using public key"}, - {"prverify", OPT_PRVERIFY, 's', - "Verify a signature using private key"}, - {"signature", OPT_SIGNATURE, '<', "File with signature to verify"}, - {"keyform", OPT_KEYFORM, 'f', "Key file format (PEM or ENGINE)"}, + {"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"}, {"hex", OPT_HEX, '-', "Print as hex dump"}, {"binary", OPT_BINARY, '-', "Print in binary form"}, + {"xoflen", OPT_XOFLEN, 'p', "Output length for XOF algorithms. To obtain the maximum security strength set this to 32 (or greater) for SHAKE128, and 64 (or greater) for SHAKE256"}, {"d", OPT_DEBUG, '-', "Print debug info"}, {"debug", OPT_DEBUG, '-', "Print debug info"}, - {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-', - "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"}, + + OPT_SECTION("Signing"), + {"sign", OPT_SIGN, 's', "Sign digest using private key"}, + {"verify", OPT_VERIFY, 's', "Verify a signature using public key"}, + {"prverify", OPT_PRVERIFY, 's', "Verify a signature using private key"}, + {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, + {"signature", OPT_SIGNATURE, '<', "File with signature to verify"}, {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"}, {"mac", OPT_MAC, 's', "Create MAC (not necessarily HMAC)"}, - {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form or key"}, {"", OPT_DIGEST, '-', "Any supported digest"}, + {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-', + "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, - {"engine_impl", OPT_ENGINE_IMPL, '-', - "Also use engine given by -engine for digest operations"}, -#endif + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"file", 0, 0, "Files to digest (optional; default is stdin)"}, {NULL} }; @@ -89,21 +98,24 @@ int dgst_main(int argc, char **argv) EVP_PKEY *sigkey = NULL; STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL; char *hmac_key = NULL; - char *mac_name = NULL; + char *mac_name = NULL, *digestname = NULL; char *passinarg = NULL, *passin = NULL; - const EVP_MD *md = NULL, *m; + EVP_MD *md = NULL; const char *outfile = NULL, *keyfile = NULL, *prog = NULL; const char *sigfile = NULL; + const char *md_name = NULL; OPTION_CHOICE o; - int separator = 0, debug = 0, keyform = FORMAT_PEM, siglen = 0; - int i, ret = 1, out_bin = -1, want_pub = 0, do_verify = 0; + int separator = 0, debug = 0, keyform = FORMAT_UNDEF, siglen = 0; + int i, ret = EXIT_FAILURE, out_bin = -1, want_pub = 0, do_verify = 0; + int xoflen = 0; unsigned char *buf = NULL, *sigbuf = NULL; int engine_impl = 0; struct doall_dgst_digests dec; - prog = opt_progname(argv[0]); buf = app_malloc(BUFSIZE, "I/O buffer"); - md = EVP_get_digestbyname(prog); + md = (EVP_MD *)EVP_get_digestbyname(argv[0]); + if (md != NULL) + digestname = argv[0]; prog = opt_init(argc, argv, dgst_options); while ((o = opt_next()) != OPT_EOF) { @@ -115,7 +127,7 @@ int dgst_main(int argc, char **argv) goto end; case OPT_HELP: opt_help(dgst_options); - ret = 0; + ret = EXIT_SUCCESS; goto end; case OPT_LIST: BIO_printf(bio_out, "Supported digests:\n"); @@ -124,7 +136,7 @@ int dgst_main(int argc, char **argv) OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, show_digests, &dec); BIO_printf(bio_out, "\n"); - ret = 0; + ret = EXIT_SUCCESS; goto end; case OPT_C: separator = 1; @@ -172,6 +184,9 @@ int dgst_main(int argc, char **argv) case OPT_BINARY: out_bin = 1; break; + case OPT_XOFLEN: + xoflen = atoi(opt_arg()); + break; case OPT_DEBUG: debug = 1; break; @@ -197,18 +212,29 @@ int dgst_main(int argc, char **argv) goto opthelp; break; case OPT_DIGEST: - if (!opt_md(opt_unknown(), &m)) - goto opthelp; - md = m; + digestname = opt_unknown(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; break; } } + + /* Remaining args are files to digest. */ argc = opt_num_rest(); argv = opt_rest(); if (keyfile != NULL && argc > 1) { BIO_printf(bio_err, "%s: Can only sign or verify one file.\n", prog); goto end; } + if (!app_RAND_load()) + goto end; + + if (digestname != NULL) { + if (!opt_md(digestname, &md)) + goto opthelp; + } if (do_verify && sigfile == NULL) { BIO_printf(bio_err, @@ -220,13 +246,11 @@ int dgst_main(int argc, char **argv) in = BIO_new(BIO_s_file()); bmd = BIO_new(BIO_f_md()); - if ((in == NULL) || (bmd == NULL)) { - ERR_print_errors(bio_err); + if (in == NULL || bmd == NULL) goto end; - } if (debug) { - BIO_set_callback(in, BIO_debug_callback); + BIO_set_callback_ex(in, BIO_debug_callback_ex); /* needed for windows 3.1 */ BIO_set_callback_arg(in, (char *)bio_err); } @@ -248,7 +272,7 @@ int dgst_main(int argc, char **argv) goto end; if ((!(mac_name == NULL) + !(keyfile == NULL) + !(hmac_key == NULL)) > 1) { - BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n"); + BIO_printf(bio_err, "MAC and signing key cannot both be specified\n"); goto end; } @@ -256,16 +280,16 @@ int dgst_main(int argc, char **argv) int type; if (want_pub) - sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "key file"); + sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "public key"); else - sigkey = load_key(keyfile, keyform, 0, passin, e, "key file"); + sigkey = load_key(keyfile, keyform, 0, passin, e, "private key"); if (sigkey == NULL) { /* * load_[pub]key() has already printed an appropriate message */ goto end; } - type = EVP_PKEY_id(sigkey); + type = EVP_PKEY_get_id(sigkey); if (type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448) { /* * We implement PureEdDSA for these which doesn't have a separate @@ -278,36 +302,34 @@ int dgst_main(int argc, char **argv) if (mac_name != NULL) { EVP_PKEY_CTX *mac_ctx = NULL; - int r = 0; - if (!init_gen_str(&mac_ctx, mac_name, impl, 0)) - goto mac_end; + + if (!init_gen_str(&mac_ctx, mac_name, impl, 0, NULL, NULL)) + goto end; if (macopts != NULL) { - char *macopt; for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) { - macopt = sk_OPENSSL_STRING_value(macopts, i); + char *macopt = sk_OPENSSL_STRING_value(macopts, i); + if (pkey_ctrl_string(mac_ctx, macopt) <= 0) { - BIO_printf(bio_err, - "MAC parameter error \"%s\"\n", macopt); - ERR_print_errors(bio_err); - goto mac_end; + EVP_PKEY_CTX_free(mac_ctx); + BIO_printf(bio_err, "MAC parameter error \"%s\"\n", macopt); + goto end; } } } - if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) { - BIO_puts(bio_err, "Error generating key\n"); - ERR_print_errors(bio_err); - goto mac_end; - } - r = 1; - mac_end: + + sigkey = app_keygen(mac_ctx, mac_name, 0, 0 /* not verbose */); + /* Verbose output would make external-tests gost-engine fail */ EVP_PKEY_CTX_free(mac_ctx); - if (r == 0) - goto end; } if (hmac_key != NULL) { + if (md == NULL) { + md = (EVP_MD *)EVP_sha256(); + digestname = SN_sha256; + } sigkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, impl, - (unsigned char *)hmac_key, -1); + (unsigned char *)hmac_key, + strlen(hmac_key)); if (sigkey == NULL) goto end; } @@ -315,28 +337,37 @@ int dgst_main(int argc, char **argv) if (sigkey != NULL) { EVP_MD_CTX *mctx = NULL; EVP_PKEY_CTX *pctx = NULL; - int r; + int res; + if (BIO_get_md_ctx(bmd, &mctx) <= 0) { BIO_printf(bio_err, "Error getting context\n"); - ERR_print_errors(bio_err); goto end; } if (do_verify) - r = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey); + if (impl == NULL) + res = EVP_DigestVerifyInit_ex(mctx, &pctx, digestname, + app_get0_libctx(), + app_get0_propq(), sigkey, NULL); + else + res = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey); else - r = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey); - if (!r) { + if (impl == NULL) + res = EVP_DigestSignInit_ex(mctx, &pctx, digestname, + app_get0_libctx(), + app_get0_propq(), sigkey, NULL); + else + res = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey); + if (res == 0) { BIO_printf(bio_err, "Error setting context\n"); - ERR_print_errors(bio_err); goto end; } if (sigopts != NULL) { - char *sigopt; for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { - sigopt = sk_OPENSSL_STRING_value(sigopts, i); + char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); + if (pkey_ctrl_string(pctx, sigopt) <= 0) { - BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Signature parameter error \"%s\"\n", + sigopt); goto end; } } @@ -347,32 +378,29 @@ int dgst_main(int argc, char **argv) EVP_MD_CTX *mctx = NULL; if (BIO_get_md_ctx(bmd, &mctx) <= 0) { BIO_printf(bio_err, "Error getting context\n"); - ERR_print_errors(bio_err); goto end; } if (md == NULL) - md = EVP_sha256(); + md = (EVP_MD *)EVP_sha256(); if (!EVP_DigestInit_ex(mctx, md, impl)) { BIO_printf(bio_err, "Error setting digest\n"); - ERR_print_errors(bio_err); goto end; } } if (sigfile != NULL && sigkey != NULL) { BIO *sigbio = BIO_new_file(sigfile, "rb"); + if (sigbio == NULL) { BIO_printf(bio_err, "Error opening signature file %s\n", sigfile); - ERR_print_errors(bio_err); goto end; } - siglen = EVP_PKEY_size(sigkey); + siglen = EVP_PKEY_get_size(sigkey); sigbuf = app_malloc(siglen, "signature buffer"); siglen = BIO_read(sigbio, sigbuf, siglen); BIO_free(sigbio); if (siglen <= 0) { BIO_printf(bio_err, "Error reading signature file %s\n", sigfile); - ERR_print_errors(bio_err); goto end; } } @@ -380,48 +408,62 @@ int dgst_main(int argc, char **argv) if (md == NULL) { EVP_MD_CTX *tctx; + BIO_get_md_ctx(bmd, &tctx); - md = EVP_MD_CTX_md(tctx); + md = EVP_MD_CTX_get1_md(tctx); + } + if (md != NULL) + md_name = EVP_MD_get0_name(md); + + if (xoflen > 0) { + if (!(EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF)) { + BIO_printf(bio_err, "Length can only be specified for XOF\n"); + goto end; + } + /* + * Signing using XOF is not supported by any algorithms currently since + * each algorithm only calls EVP_DigestFinal_ex() in their sign_final + * and verify_final methods. + */ + if (sigkey != NULL) { + BIO_printf(bio_err, "Signing key cannot be specified for XOF\n"); + goto end; + } } if (argc == 0) { BIO_set_fp(in, stdin, BIO_NOCLOSE); - ret = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, - siglen, NULL, NULL, "stdin"); + ret = do_fp(out, buf, inp, separator, out_bin, xoflen, sigkey, sigbuf, + siglen, NULL, md_name, "stdin"); } else { - const char *md_name = NULL, *sig_name = NULL; - if (!out_bin) { - if (sigkey != NULL) { - const EVP_PKEY_ASN1_METHOD *ameth; - ameth = EVP_PKEY_get0_asn1(sigkey); - if (ameth) - EVP_PKEY_asn1_get0_info(NULL, NULL, - NULL, NULL, &sig_name, ameth); - } - if (md != NULL) - md_name = EVP_MD_name(md); + const char *sig_name = NULL; + + if (out_bin == 0) { + if (sigkey != NULL) + sig_name = EVP_PKEY_get0_type_name(sigkey); } - ret = 0; + ret = EXIT_SUCCESS; for (i = 0; i < argc; i++) { - int r; if (BIO_read_filename(in, argv[i]) <= 0) { perror(argv[i]); - ret++; + ret = EXIT_FAILURE; continue; } else { - r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, - siglen, sig_name, md_name, argv[i]); + if (do_fp(out, buf, inp, separator, out_bin, xoflen, + sigkey, sigbuf, siglen, sig_name, md_name, argv[i])) + ret = EXIT_FAILURE; } - if (r) - ret = r; (void)BIO_reset(bmd); } } end: + if (ret != EXIT_SUCCESS) + ERR_print_errors(bio_err); OPENSSL_clear_free(buf, BUFSIZE); BIO_free(in); OPENSSL_free(passin); BIO_free_all(out); + EVP_MD_free(md); EVP_PKEY_free(sigkey); sk_OPENSSL_STRING_free(sigopts); sk_OPENSSL_STRING_free(macopts); @@ -444,7 +486,7 @@ static void show_digests(const OBJ_NAME *name, void *arg) return; /* Filter out message digests that we cannot use */ - md = EVP_get_digestbyname(name->name); + md = EVP_MD_fetch(app_get0_libctx(), name->name, app_get0_propq()); if (md == NULL) return; @@ -496,20 +538,19 @@ static const char *newline_escape_filename(const char *file, int * backslash) } -int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, +int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen, EVP_PKEY *key, unsigned char *sigin, int siglen, const char *sig_name, const char *md_name, const char *file) { size_t len = BUFSIZE; - int i, backslash = 0, ret = 1; - unsigned char *sigbuf = NULL; + int i, backslash = 0, ret = EXIT_FAILURE; + unsigned char *allocated_buf = NULL; while (BIO_pending(bp) || !BIO_eof(bp)) { i = BIO_read(bp, (char *)buf, BUFSIZE); if (i < 0) { - BIO_printf(bio_err, "Read Error in %s\n", file); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Read error in %s\n", file); goto end; } if (i == 0) @@ -522,37 +563,52 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, if (i > 0) { BIO_printf(out, "Verified OK\n"); } else if (i == 0) { - BIO_printf(out, "Verification Failure\n"); + BIO_printf(out, "Verification failure\n"); goto end; } else { - BIO_printf(bio_err, "Error Verifying Data\n"); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Error verifying data\n"); goto end; } - ret = 0; + ret = EXIT_SUCCESS; goto end; } if (key != NULL) { EVP_MD_CTX *ctx; - int pkey_len; + size_t tmplen; + BIO_get_md_ctx(bp, &ctx); - pkey_len = EVP_PKEY_size(key); - if (pkey_len > BUFSIZE) { - len = pkey_len; - sigbuf = app_malloc(len, "Signature buffer"); - buf = sigbuf; + if (!EVP_DigestSignFinal(ctx, NULL, &tmplen)) { + BIO_printf(bio_err, "Error getting maximum length of signed data\n"); + goto end; + } + if (tmplen > BUFSIZE) { + len = tmplen; + allocated_buf = app_malloc(len, "Signature buffer"); + buf = allocated_buf; } if (!EVP_DigestSignFinal(ctx, buf, &len)) { - BIO_printf(bio_err, "Error Signing Data\n"); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Error signing data\n"); + goto end; + } + } else if (xoflen > 0) { + EVP_MD_CTX *ctx; + + len = xoflen; + if (len > BUFSIZE) { + allocated_buf = app_malloc(len, "Digest buffer"); + buf = allocated_buf; + } + + BIO_get_md_ctx(bp, &ctx); + + if (!EVP_DigestFinalXOF(ctx, buf, len)) { + BIO_printf(bio_err, "Error Digesting Data\n"); goto end; } } else { len = BIO_gets(bp, (char *)buf, BUFSIZE); - if ((int)len < 0) { - ERR_print_errors(bio_err); + if ((int)len < 0) goto end; - } } if (binout) { @@ -587,10 +643,10 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, BIO_printf(out, "\n"); } - ret = 0; + ret = EXIT_SUCCESS; end: - if (sigbuf != NULL) - OPENSSL_clear_free(sigbuf, len); + if (allocated_buf != NULL) + OPENSSL_clear_free(allocated_buf, len); return ret; } diff --git a/apps/dh1024.pem b/apps/dh1024.pem deleted file mode 100644 index 813e8a4a4822..000000000000 --- a/apps/dh1024.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR -Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL -/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC ------END DH PARAMETERS----- - -These are the 1024-bit DH parameters from "Internet Key Exchange -Protocol Version 2 (IKEv2)": https://tools.ietf.org/html/rfc5996 - -See https://tools.ietf.org/html/rfc2412 for how they were generated. diff --git a/apps/dh2048.pem b/apps/dh2048.pem deleted file mode 100644 index 288a20997e5a..000000000000 --- a/apps/dh2048.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb -IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft -awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT -mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh -fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq -5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg== ------END DH PARAMETERS----- - -These are the 2048-bit DH parameters from "More Modular Exponential -(MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)": -https://tools.ietf.org/html/rfc3526 - -See https://tools.ietf.org/html/rfc2412 for how they were generated. diff --git a/apps/dh4096.pem b/apps/dh4096.pem deleted file mode 100644 index 08560e1284e2..000000000000 --- a/apps/dh4096.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb -IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft -awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT -mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh -fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq -5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM -fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq -ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI -ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O -+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI -HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI= ------END DH PARAMETERS----- - -These are the 4096-bit DH parameters from "More Modular Exponential -(MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)": -https://tools.ietf.org/html/rfc3526 - -See https://tools.ietf.org/html/rfc2412 for how they were generated. diff --git a/apps/dhparam.c b/apps/dhparam.c index 98c73214b53e..43906cea5649 100644 --- a/apps/dhparam.c +++ b/apps/dhparam.c @@ -1,13 +1,14 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include <stdio.h> #include <stdlib.h> #include <time.h> @@ -17,61 +18,73 @@ #include <openssl/bio.h> #include <openssl/err.h> #include <openssl/bn.h> +#include <openssl/dsa.h> #include <openssl/dh.h> #include <openssl/x509.h> #include <openssl/pem.h> - -#ifndef OPENSSL_NO_DSA -# include <openssl/dsa.h> -#endif +#include <openssl/core_names.h> +#include <openssl/core_dispatch.h> +#include <openssl/param_build.h> +#include <openssl/encoder.h> +#include <openssl/decoder.h> #define DEFBITS 2048 -static int dh_cb(int p, int n, BN_GENCB *cb); +static EVP_PKEY *dsa_to_dh(EVP_PKEY *dh); +static int gendh_cb(EVP_PKEY_CTX *ctx); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENGINE, OPT_CHECK, OPT_TEXT, OPT_NOOUT, - OPT_DSAPARAM, OPT_C, OPT_2, OPT_5, - OPT_R_ENUM + OPT_DSAPARAM, OPT_2, OPT_3, OPT_5, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS dhparam_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [flags] [numbits]\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [numbits]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"in", OPT_IN, '<', "Input file"}, - {"inform", OPT_INFORM, 'F', "Input format, DER or PEM"}, - {"outform", OPT_OUTFORM, 'F', "Output format, DER or PEM"}, - {"out", OPT_OUT, '>', "Output file"}, {"check", OPT_CHECK, '-', "Check the DH parameters"}, - {"text", OPT_TEXT, '-', "Print a text form of the DH parameters"}, - {"noout", OPT_NOOUT, '-', "Don't output any DH parameters"}, - OPT_R_OPTIONS, - {"C", OPT_C, '-', "Print C code"}, - {"2", OPT_2, '-', "Generate parameters using 2 as the generator value"}, - {"5", OPT_5, '-', "Generate parameters using 5 as the generator value"}, -#ifndef OPENSSL_NO_DSA +#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_DEPRECATED_3_0) {"dsaparam", OPT_DSAPARAM, '-', "Read or generate DSA parameters, convert to DH"}, #endif #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, #endif + + OPT_SECTION("Input"), + {"in", OPT_IN, '<', "Input file"}, + {"inform", OPT_INFORM, 'F', "Input format, DER or PEM"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "Output format, DER or PEM"}, + {"text", OPT_TEXT, '-', "Print a text form of the DH parameters"}, + {"noout", OPT_NOOUT, '-', "Don't output any DH parameters"}, + {"2", OPT_2, '-', "Generate parameters using 2 as the generator value"}, + {"3", OPT_3, '-', "Generate parameters using 3 as the generator value"}, + {"5", OPT_5, '-', "Generate parameters using 5 as the generator value"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"numbits", 0, 0, "Number of bits if generating parameters (optional)"}, {NULL} }; int dhparam_main(int argc, char **argv) { BIO *in = NULL, *out = NULL; - DH *dh = NULL; + EVP_PKEY *pkey = NULL, *tmppkey = NULL; + EVP_PKEY_CTX *ctx = NULL; char *infile = NULL, *outfile = NULL, *prog; ENGINE *e = NULL; -#ifndef OPENSSL_NO_DSA int dsaparam = 0; -#endif - int i, text = 0, C = 0, ret = 1, num = 0, g = 0; + int text = 0, ret = 1, num = 0, g = 0; int informat = FORMAT_PEM, outformat = FORMAT_PEM, check = 0, noout = 0; OPTION_CHOICE o; @@ -111,16 +124,14 @@ int dhparam_main(int argc, char **argv) text = 1; break; case OPT_DSAPARAM: -#ifndef OPENSSL_NO_DSA dsaparam = 1; -#endif - break; - case OPT_C: - C = 1; break; case OPT_2: g = 2; break; + case OPT_3: + g = 3; + break; case OPT_5: g = 5; break; @@ -131,24 +142,33 @@ int dhparam_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* One optional argument, bitsize to generate. */ argc = opt_num_rest(); argv = opt_rest(); - - if (argv[0] != NULL && (!opt_int(argv[0], &num) || num <= 0)) + if (argc == 1) { + if (!opt_int(argv[0], &num) || num <= 0) + goto opthelp; + } else if (argc != 0) { + goto opthelp; + } + if (!app_RAND_load()) goto end; if (g && !num) num = DEFBITS; -#ifndef OPENSSL_NO_DSA if (dsaparam && g) { BIO_printf(bio_err, - "generator may not be chosen for DSA parameters\n"); + "Error, generator may not be chosen for DSA parameters\n"); goto end; } -#endif out = bio_open_default(outfile, 'w', outformat); if (out == NULL) @@ -159,216 +179,238 @@ int dhparam_main(int argc, char **argv) g = 2; if (num) { + const char *alg = dsaparam ? "DSA" : "DH"; + + if (infile != NULL) { + BIO_printf(bio_err, "Warning, input file %s ignored\n", infile); + } - BN_GENCB *cb; - cb = BN_GENCB_new(); - if (cb == NULL) { - ERR_print_errors(bio_err); + ctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), alg, app_get0_propq()); + if (ctx == NULL) { + BIO_printf(bio_err, + "Error, %s param generation context allocation failed\n", + alg); goto end; } + EVP_PKEY_CTX_set_cb(ctx, gendh_cb); + EVP_PKEY_CTX_set_app_data(ctx, bio_err); + BIO_printf(bio_err, + "Generating %s parameters, %d bit long %sprime\n", + alg, num, dsaparam ? "" : "safe "); - BN_GENCB_set(cb, dh_cb, bio_err); + if (EVP_PKEY_paramgen_init(ctx) <= 0) { + BIO_printf(bio_err, + "Error, unable to initialise %s parameters\n", + alg); + goto end; + } -#ifndef OPENSSL_NO_DSA if (dsaparam) { - DSA *dsa = DSA_new(); - - BIO_printf(bio_err, - "Generating DSA parameters, %d bit long prime\n", num); - if (dsa == NULL - || !DSA_generate_parameters_ex(dsa, num, NULL, 0, NULL, NULL, - cb)) { - DSA_free(dsa); - BN_GENCB_free(cb); - ERR_print_errors(bio_err); + if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, num) <= 0) { + BIO_printf(bio_err, "Error, unable to set DSA prime length\n"); goto end; } - - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - BN_GENCB_free(cb); - ERR_print_errors(bio_err); + } else { + if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, num) <= 0) { + BIO_printf(bio_err, "Error, unable to set DH prime length\n"); goto end; } - } else -#endif - { - dh = DH_new(); - BIO_printf(bio_err, - "Generating DH parameters, %d bit long safe prime, generator %d\n", - num, g); - BIO_printf(bio_err, "This is going to take a long time\n"); - if (dh == NULL || !DH_generate_parameters_ex(dh, num, g, cb)) { - BN_GENCB_free(cb); - ERR_print_errors(bio_err); + if (EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, g) <= 0) { + BIO_printf(bio_err, "Error, unable to set generator\n"); goto end; } } - BN_GENCB_free(cb); + tmppkey = app_paramgen(ctx, alg); + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + if (dsaparam) { + pkey = dsa_to_dh(tmppkey); + if (pkey == NULL) + goto end; + EVP_PKEY_free(tmppkey); + } else { + pkey = tmppkey; + } + tmppkey = NULL; } else { + OSSL_DECODER_CTX *decoderctx = NULL; + const char *keytype = "DH"; + int done; in = bio_open_default(infile, 'r', informat); if (in == NULL) goto end; -#ifndef OPENSSL_NO_DSA - if (dsaparam) { - DSA *dsa; - - if (informat == FORMAT_ASN1) - dsa = d2i_DSAparams_bio(in, NULL); - else /* informat == FORMAT_PEM */ - dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); - - if (dsa == NULL) { - BIO_printf(bio_err, "unable to load DSA parameters\n"); - ERR_print_errors(bio_err); - goto end; - } - - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - ERR_print_errors(bio_err); - goto end; - } - } else -#endif - { - if (informat == FORMAT_ASN1) { + do { + /* + * We assume we're done unless we explicitly want to retry and set + * this to 0 below. + */ + done = 1; + /* + * We set NULL for the keytype to allow any key type. We don't know + * if we're going to get DH or DHX (or DSA in the event of dsaparam). + * We check that we got one of those key types afterwards. + */ + decoderctx + = OSSL_DECODER_CTX_new_for_pkey(&tmppkey, + (informat == FORMAT_ASN1) + ? "DER" : "PEM", + NULL, + (informat == FORMAT_ASN1) + ? keytype : NULL, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + NULL, NULL); + + if (decoderctx != NULL + && !OSSL_DECODER_from_bio(decoderctx, in) + && informat == FORMAT_ASN1 + && strcmp(keytype, "DH") == 0) { + /* + * When reading DER we explicitly state the expected keytype + * because, unlike PEM, there is no header to declare what + * the contents of the DER file are. The decoders just try + * and guess. Unfortunately with DHX key types they may guess + * wrong and think we have a DSA keytype. Therefore we try + * both DH and DHX sequentially. + */ + keytype = "DHX"; /* - * We have no PEM header to determine what type of DH params it - * is. We'll just try both. + * BIO_reset() returns 0 for success for file BIOs only!!! + * This won't work for stdin (and never has done) */ - dh = d2i_DHparams_bio(in, NULL); - /* BIO_reset() returns 0 for success for file BIOs only!!! */ - if (dh == NULL && BIO_reset(in) == 0) - dh = d2i_DHxparams_bio(in, NULL); - } else { - /* informat == FORMAT_PEM */ - dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); + if (BIO_reset(in) == 0) + done = 0; } + OSSL_DECODER_CTX_free(decoderctx); + } while (!done); + if (tmppkey == NULL) { + BIO_printf(bio_err, "Error, unable to load parameters\n"); + goto end; + } - if (dh == NULL) { - BIO_printf(bio_err, "unable to load DH parameters\n"); - ERR_print_errors(bio_err); + if (dsaparam) { + if (!EVP_PKEY_is_a(tmppkey, "DSA")) { + BIO_printf(bio_err, "Error, unable to load DSA parameters\n"); goto end; } + pkey = dsa_to_dh(tmppkey); + if (pkey == NULL) + goto end; + } else { + if (!EVP_PKEY_is_a(tmppkey, "DH") + && !EVP_PKEY_is_a(tmppkey, "DHX")) { + BIO_printf(bio_err, "Error, unable to load DH parameters\n"); + goto end; + } + pkey = tmppkey; + tmppkey = NULL; } - - /* dh != NULL */ } - if (text) { - DHparams_print(out, dh); - } + if (text) + EVP_PKEY_print_params(out, pkey, 4, NULL); if (check) { - if (!DH_check(dh, &i)) { - ERR_print_errors(bio_err); + ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), pkey, app_get0_propq()); + if (ctx == NULL) { + BIO_printf(bio_err, "Error, failed to check DH parameters\n"); goto end; } - if (i & DH_CHECK_P_NOT_PRIME) - BIO_printf(bio_err, "WARNING: p value is not prime\n"); - if (i & DH_CHECK_P_NOT_SAFE_PRIME) - BIO_printf(bio_err, "WARNING: p value is not a safe prime\n"); - if (i & DH_CHECK_Q_NOT_PRIME) - BIO_printf(bio_err, "WARNING: q value is not a prime\n"); - if (i & DH_CHECK_INVALID_Q_VALUE) - BIO_printf(bio_err, "WARNING: q value is invalid\n"); - if (i & DH_CHECK_INVALID_J_VALUE) - BIO_printf(bio_err, "WARNING: j value is invalid\n"); - if (i & DH_UNABLE_TO_CHECK_GENERATOR) - BIO_printf(bio_err, - "WARNING: unable to check the generator value\n"); - if (i & DH_NOT_SUITABLE_GENERATOR) - BIO_printf(bio_err, "WARNING: the g value is not a generator\n"); - if (i == 0) - BIO_printf(bio_err, "DH parameters appear to be ok.\n"); - if (num != 0 && i != 0) { - /* - * We have generated parameters but DH_check() indicates they are - * invalid! This should never happen! - */ - BIO_printf(bio_err, "ERROR: Invalid parameters generated\n"); + if (EVP_PKEY_param_check(ctx) <= 0) { + BIO_printf(bio_err, "Error, invalid parameters generated\n"); goto end; } - } - if (C) { - unsigned char *data; - int len, bits; - const BIGNUM *pbn, *gbn; - - len = DH_size(dh); - bits = DH_bits(dh); - DH_get0_pqg(dh, &pbn, NULL, &gbn); - data = app_malloc(len, "print a BN"); - - BIO_printf(out, "static DH *get_dh%d(void)\n{\n", bits); - print_bignum_var(out, pbn, "dhp", bits, data); - print_bignum_var(out, gbn, "dhg", bits, data); - BIO_printf(out, " DH *dh = DH_new();\n" - " BIGNUM *p, *g;\n" - "\n" - " if (dh == NULL)\n" - " return NULL;\n"); - BIO_printf(out, " p = BN_bin2bn(dhp_%d, sizeof(dhp_%d), NULL);\n", - bits, bits); - BIO_printf(out, " g = BN_bin2bn(dhg_%d, sizeof(dhg_%d), NULL);\n", - bits, bits); - BIO_printf(out, " if (p == NULL || g == NULL\n" - " || !DH_set0_pqg(dh, p, NULL, g)) {\n" - " DH_free(dh);\n" - " BN_free(p);\n" - " BN_free(g);\n" - " return NULL;\n" - " }\n"); - if (DH_get_length(dh) > 0) - BIO_printf(out, - " if (!DH_set_length(dh, %ld)) {\n" - " DH_free(dh);\n" - " return NULL;\n" - " }\n", DH_get_length(dh)); - BIO_printf(out, " return dh;\n}\n"); - OPENSSL_free(data); + BIO_printf(bio_err, "DH parameters appear to be ok.\n"); } if (!noout) { - const BIGNUM *q; - DH_get0_pqg(dh, NULL, &q, NULL); - if (outformat == FORMAT_ASN1) { - if (q != NULL) - i = i2d_DHxparams_bio(out, dh); - else - i = i2d_DHparams_bio(out, dh); - } else if (q != NULL) { - i = PEM_write_bio_DHxparams(out, dh); - } else { - i = PEM_write_bio_DHparams(out, dh); - } - if (!i) { - BIO_printf(bio_err, "unable to write DH parameters\n"); - ERR_print_errors(bio_err); + OSSL_ENCODER_CTX *ectx = + OSSL_ENCODER_CTX_new_for_pkey(pkey, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + outformat == FORMAT_ASN1 + ? "DER" : "PEM", + NULL, NULL); + + if (ectx == NULL || !OSSL_ENCODER_to_bio(ectx, out)) { + OSSL_ENCODER_CTX_free(ectx); + BIO_printf(bio_err, "Error, unable to write DH parameters\n"); goto end; } + OSSL_ENCODER_CTX_free(ectx); } ret = 0; end: + if (ret != 0) + ERR_print_errors(bio_err); BIO_free(in); BIO_free_all(out); - DH_free(dh); + EVP_PKEY_free(pkey); + EVP_PKEY_free(tmppkey); + EVP_PKEY_CTX_free(ctx); release_engine(e); return ret; } -static int dh_cb(int p, int n, BN_GENCB *cb) +/* + * Historically we had the low level call DSA_dup_DH() to do this. + * That is now deprecated with no replacement. Since we still need to do this + * for backwards compatibility reasons, we do it "manually". + */ +static EVP_PKEY *dsa_to_dh(EVP_PKEY *dh) +{ + OSSL_PARAM_BLD *tmpl = NULL; + OSSL_PARAM *params = NULL; + BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + + if (!EVP_PKEY_get_bn_param(dh, OSSL_PKEY_PARAM_FFC_P, &bn_p) + || !EVP_PKEY_get_bn_param(dh, OSSL_PKEY_PARAM_FFC_Q, &bn_q) + || !EVP_PKEY_get_bn_param(dh, OSSL_PKEY_PARAM_FFC_G, &bn_g)) { + BIO_printf(bio_err, "Error, failed to set DH parameters\n"); + goto err; + } + + if ((tmpl = OSSL_PARAM_BLD_new()) == NULL + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, + bn_p) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, + bn_q) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, + bn_g) + || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) { + BIO_printf(bio_err, "Error, failed to set DH parameters\n"); + goto err; + } + + ctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "DHX", app_get0_propq()); + if (ctx == NULL + || EVP_PKEY_fromdata_init(ctx) <= 0 + || EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS, params) <= 0) { + BIO_printf(bio_err, "Error, failed to set DH parameters\n"); + goto err; + } + + err: + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(tmpl); + BN_free(bn_p); + BN_free(bn_q); + BN_free(bn_g); + return pkey; +} + +static int gendh_cb(EVP_PKEY_CTX *ctx) { + int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + BIO *b = EVP_PKEY_CTX_get_app_data(ctx); static const char symbols[] = ".+*\n"; char c = (p >= 0 && (size_t)p < sizeof(symbols) - 1) ? symbols[p] : '?'; - BIO_write(BN_GENCB_get_arg(cb), &c, 1); - (void)BIO_flush(BN_GENCB_get_arg(cb)); + BIO_write(b, &c, 1); + (void)BIO_flush(b); return 1; } diff --git a/apps/dsa.c b/apps/dsa.c index c7884df166b7..51c02843539f 100644 --- a/apps/dsa.c +++ b/apps/dsa.c @@ -1,13 +1,14 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -21,29 +22,29 @@ #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/bn.h> +#include <openssl/encoder.h> +#include <openssl/core_names.h> +#include <openssl/core_dispatch.h> + +#ifndef OPENSSL_NO_RC4 +# define DEFAULT_PVK_ENCR_STRENGTH 2 +#else +# define DEFAULT_PVK_ENCR_STRENGTH 0 +#endif typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_ENGINE, /* Do not change the order here; see case statements below */ OPT_PVK_NONE, OPT_PVK_WEAK, OPT_PVK_STRONG, OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_PUBIN, - OPT_PUBOUT, OPT_CIPHER, OPT_PASSIN, OPT_PASSOUT + OPT_PUBOUT, OPT_CIPHER, OPT_PASSIN, OPT_PASSOUT, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS dsa_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'f', "Input format, DER PEM PVK"}, - {"outform", OPT_OUTFORM, 'f', "Output format, DER PEM PVK"}, - {"in", OPT_IN, 's', "Input key"}, - {"out", OPT_OUT, '>', "Output file"}, - {"noout", OPT_NOOUT, '-', "Don't print key out"}, - {"text", OPT_TEXT, '-', "Print the key in text"}, - {"modulus", OPT_MODULUS, '-', "Print the DSA public value"}, - {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, - {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, {"", OPT_CIPHER, '-', "Any supported cipher"}, #ifndef OPENSSL_NO_RC4 {"pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)"}, @@ -53,24 +54,43 @@ const OPTIONS dsa_options[] = { #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, #endif + + OPT_SECTION("Input"), + {"in", OPT_IN, 's', "Input key"}, + {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/PVK); has no effect"}, + {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'f', "Output format, DER PEM PVK"}, + {"noout", OPT_NOOUT, '-', "Don't print key out"}, + {"text", OPT_TEXT, '-', "Print the key in text"}, + {"modulus", OPT_MODULUS, '-', "Print the DSA public value"}, + {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, + {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, + + OPT_PROV_OPTIONS, {NULL} }; int dsa_main(int argc, char **argv) { BIO *out = NULL; - DSA *dsa = NULL; ENGINE *e = NULL; - const EVP_CIPHER *enc = NULL; + EVP_PKEY *pkey = NULL; + EVP_CIPHER *enc = NULL; char *infile = NULL, *outfile = NULL, *prog; char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; OPTION_CHOICE o; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, noout = 0; - int i, modulus = 0, pubin = 0, pubout = 0, ret = 1; -#ifndef OPENSSL_NO_RC4 - int pvk_encr = 2; -#endif + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0; + int modulus = 0, pubin = 0, pubout = 0, ret = 1; + int pvk_encr = DEFAULT_PVK_ENCR_STRENGTH; int private = 0; + const char *output_type = NULL, *ciphername = NULL; + const char *output_structure = NULL; + int selection = 0; + OSSL_ENCODER_CTX *ectx = NULL; prog = opt_init(argc, argv, dsa_options); while ((o = opt_next()) != OPT_EOF) { @@ -131,15 +151,24 @@ int dsa_main(int argc, char **argv) pubout = 1; break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &enc)) + ciphername = opt_unknown(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) goto end; break; } } + + /* No extra args. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &enc)) + goto end; + } private = pubin || pubout ? 0 : 1; if (text && !pubin) private = 1; @@ -150,24 +179,20 @@ int dsa_main(int argc, char **argv) } BIO_printf(bio_err, "read DSA key\n"); - { - EVP_PKEY *pkey; - - if (pubin) - pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); - else - pkey = load_key(infile, informat, 1, passin, e, "Private Key"); + if (pubin) + pkey = load_pubkey(infile, informat, 1, passin, e, "public key"); + else + pkey = load_key(infile, informat, 1, passin, e, "private key"); - if (pkey != NULL) { - dsa = EVP_PKEY_get1_DSA(pkey); - EVP_PKEY_free(pkey); - } - } - if (dsa == NULL) { + if (pkey == NULL) { BIO_printf(bio_err, "unable to load Key\n"); ERR_print_errors(bio_err); goto end; } + if (!EVP_PKEY_is_a(pkey, "DSA")) { + BIO_printf(bio_err, "Not a DSA key\n"); + goto end; + } out = bio_open_owner(outfile, outformat, private); if (out == NULL) @@ -175,7 +200,8 @@ int dsa_main(int argc, char **argv) if (text) { assert(pubin || private); - if (!DSA_print(out, dsa, 0)) { + if ((pubin && EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) + || (!pubin && EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)) { perror(outfile); ERR_print_errors(bio_err); goto end; @@ -183,11 +209,16 @@ int dsa_main(int argc, char **argv) } if (modulus) { - const BIGNUM *pub_key = NULL; - DSA_get0_key(dsa, &pub_key, NULL); + BIGNUM *pub_key = NULL; + + if (!EVP_PKEY_get_bn_param(pkey, "pub", &pub_key)) { + ERR_print_errors(bio_err); + goto end; + } BIO_printf(out, "Public Key="); BN_print(out, pub_key); BIO_printf(out, "\n"); + BN_free(pub_key); } if (noout) { @@ -196,63 +227,83 @@ int dsa_main(int argc, char **argv) } BIO_printf(bio_err, "writing DSA key\n"); if (outformat == FORMAT_ASN1) { - if (pubin || pubout) { - i = i2d_DSA_PUBKEY_bio(out, dsa); - } else { - assert(private); - i = i2d_DSAPrivateKey_bio(out, dsa); - } + output_type = "DER"; } else if (outformat == FORMAT_PEM) { - if (pubin || pubout) { - i = PEM_write_bio_DSA_PUBKEY(out, dsa); - } else { - assert(private); - i = PEM_write_bio_DSAPrivateKey(out, dsa, enc, - NULL, 0, NULL, passout); - } -#ifndef OPENSSL_NO_RSA - } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { - EVP_PKEY *pk; - pk = EVP_PKEY_new(); - if (pk == NULL) - goto end; - - EVP_PKEY_set1_DSA(pk, dsa); - if (outformat == FORMAT_PVK) { - if (pubin) { - BIO_printf(bio_err, "PVK form impossible with public key input\n"); - EVP_PKEY_free(pk); - goto end; - } - assert(private); -# ifdef OPENSSL_NO_RC4 - BIO_printf(bio_err, "PVK format not supported\n"); - EVP_PKEY_free(pk); + output_type = "PEM"; + } else if (outformat == FORMAT_MSBLOB) { + output_type = "MSBLOB"; + } else if (outformat == FORMAT_PVK) { + if (pubin) { + BIO_printf(bio_err, "PVK form impossible with public key input\n"); goto end; -# else - i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); -# endif - } else if (pubin || pubout) { - i = i2b_PublicKey_bio(out, pk); - } else { - assert(private); - i = i2b_PrivateKey_bio(out, pk); } - EVP_PKEY_free(pk); -#endif + output_type = "PVK"; } else { BIO_printf(bio_err, "bad output format specified for outfile\n"); goto end; } - if (i <= 0) { - BIO_printf(bio_err, "unable to write private key\n"); - ERR_print_errors(bio_err); + + if (outformat == FORMAT_ASN1 || outformat == FORMAT_PEM) { + if (pubout || pubin) + output_structure = "SubjectPublicKeyInfo"; + else + output_structure = "type-specific"; + } + + /* Select what you want in the output */ + if (pubout || pubin) { + selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + } else { + assert(private); + selection = (OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS); + } + + /* Perform the encoding */ + ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, output_type, + output_structure, NULL); + if (OSSL_ENCODER_CTX_get_num_encoders(ectx) == 0) { + BIO_printf(bio_err, "%s format not supported\n", output_type); + goto end; + } + + /* Passphrase setup */ + if (enc != NULL) + OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); + + /* Default passphrase prompter */ + if (enc != NULL || outformat == FORMAT_PVK) { + OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); + if (passout != NULL) + /* When passout given, override the passphrase prompter */ + OSSL_ENCODER_CTX_set_passphrase(ectx, + (const unsigned char *)passout, + strlen(passout)); + } + + /* PVK requires a bit more */ + if (outformat == FORMAT_PVK) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_int("encrypt-level", &pvk_encr); + if (!OSSL_ENCODER_CTX_set_params(ectx, params)) { + BIO_printf(bio_err, "invalid PVK encryption level\n"); + goto end; + } + } + + if (!OSSL_ENCODER_to_bio(ectx, out)) { + BIO_printf(bio_err, "unable to write key\n"); goto end; } ret = 0; end: + if (ret != 0) + ERR_print_errors(bio_err); + OSSL_ENCODER_CTX_free(ectx); BIO_free_all(out); - DSA_free(dsa); + EVP_PKEY_free(pkey); + EVP_CIPHER_free(enc); release_engine(e); OPENSSL_free(passin); OPENSSL_free(passout); diff --git a/apps/dsaparam.c b/apps/dsaparam.c index 75589ac6bc4e..b5555282be6e 100644 --- a/apps/dsaparam.c +++ b/apps/dsaparam.c @@ -1,15 +1,17 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include <stdio.h> #include <stdlib.h> +#include "apps.h" #include <time.h> #include <string.h> #include "apps.h" @@ -21,39 +23,54 @@ #include <openssl/x509.h> #include <openssl/pem.h> -static int dsa_cb(int p, int n, BN_GENCB *cb); +static int verbose = 0; + +static int gendsa_cb(EVP_PKEY_CTX *ctx); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C, - OPT_NOOUT, OPT_GENKEY, OPT_ENGINE, OPT_R_ENUM + OPT_COMMON, + OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, + OPT_NOOUT, OPT_GENKEY, OPT_ENGINE, OPT_VERBOSE, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS dsaparam_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [numbits]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, - {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, + {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, + + OPT_SECTION("Output"), {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, {"text", OPT_TEXT, '-', "Print as text"}, - {"C", OPT_C, '-', "Output C code"}, {"noout", OPT_NOOUT, '-', "No output"}, + {"verbose", OPT_VERBOSE, '-', "Verbose output"}, {"genkey", OPT_GENKEY, '-', "Generate a DSA key"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"}, -#endif + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"numbits", 0, 0, "Number of bits if generating parameters (optional)"}, {NULL} }; int dsaparam_main(int argc, char **argv) { ENGINE *e = NULL; - DSA *dsa = NULL; - BIO *in = NULL, *out = NULL; - BN_GENCB *cb = NULL; + BIO *out = NULL; + EVP_PKEY *params = NULL, *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; int numbits = -1, num = 0, genkey = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, noout = 0; int ret = 1, i, text = 0, private = 0; char *infile = NULL, *outfile = NULL, *prog; OPTION_CHOICE o; @@ -90,9 +107,6 @@ int dsaparam_main(int argc, char **argv) case OPT_TEXT: text = 1; break; - case OPT_C: - C = 1; - break; case OPT_GENKEY: genkey = 1; break; @@ -100,29 +114,45 @@ int dsaparam_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_NOOUT: noout = 1; break; + case OPT_VERBOSE: + verbose = 1; + break; } } + + /* Optional arg is bitsize. */ argc = opt_num_rest(); argv = opt_rest(); - if (argc == 1) { if (!opt_int(argv[0], &num) || num < 0) - goto end; - /* generate a key */ - numbits = num; + goto opthelp; + } else if (argc != 0) { + goto opthelp; } + if (!app_RAND_load()) + goto end; + + /* generate a key */ + numbits = num; private = genkey ? 1 : 0; - in = bio_open_default(infile, 'r', informat); - if (in == NULL) - goto end; out = bio_open_owner(outfile, outformat, private); if (out == NULL) goto end; + ctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "DSA", app_get0_propq()); + if (ctx == NULL) { + BIO_printf(bio_err, + "Error, DSA parameter generation context allocation failed\n"); + goto end; + } if (numbits > 0) { if (numbits > OPENSSL_DSA_MAX_MODULUS_BITS) BIO_printf(bio_err, @@ -130,74 +160,34 @@ int dsaparam_main(int argc, char **argv) " Your key size is %d! Larger key size may behave not as expected.\n", OPENSSL_DSA_MAX_MODULUS_BITS, numbits); - cb = BN_GENCB_new(); - if (cb == NULL) { - BIO_printf(bio_err, "Error allocating BN_GENCB object\n"); - goto end; + EVP_PKEY_CTX_set_cb(ctx, gendsa_cb); + EVP_PKEY_CTX_set_app_data(ctx, bio_err); + if (verbose) { + BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", + num); + BIO_printf(bio_err, "This could take some time\n"); } - BN_GENCB_set(cb, dsa_cb, bio_err); - dsa = DSA_new(); - if (dsa == NULL) { - BIO_printf(bio_err, "Error allocating DSA object\n"); + if (EVP_PKEY_paramgen_init(ctx) <= 0) { + BIO_printf(bio_err, + "Error, DSA key generation paramgen init failed\n"); goto end; } - BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", - num); - BIO_printf(bio_err, "This could take some time\n"); - if (!DSA_generate_parameters_ex(dsa, num, NULL, 0, NULL, NULL, cb)) { - ERR_print_errors(bio_err); - BIO_printf(bio_err, "Error, DSA key generation failed\n"); + if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, num) <= 0) { + BIO_printf(bio_err, + "Error, DSA key generation setting bit length failed\n"); goto end; } - } else if (informat == FORMAT_ASN1) { - dsa = d2i_DSAparams_bio(in, NULL); + params = app_paramgen(ctx, "DSA"); } else { - dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); + params = load_keyparams(infile, informat, 1, "DSA", "DSA parameters"); } - if (dsa == NULL) { - BIO_printf(bio_err, "unable to load DSA parameters\n"); - ERR_print_errors(bio_err); + if (params == NULL) { + /* Error message should already have been displayed */ goto end; } if (text) { - DSAparams_print(out, dsa); - } - - if (C) { - const BIGNUM *p = NULL, *q = NULL, *g = NULL; - unsigned char *data; - int len, bits_p; - - DSA_get0_pqg(dsa, &p, &q, &g); - len = BN_num_bytes(p); - bits_p = BN_num_bits(p); - - data = app_malloc(len + 20, "BN space"); - - BIO_printf(bio_out, "static DSA *get_dsa%d(void)\n{\n", bits_p); - print_bignum_var(bio_out, p, "dsap", bits_p, data); - print_bignum_var(bio_out, q, "dsaq", bits_p, data); - print_bignum_var(bio_out, g, "dsag", bits_p, data); - BIO_printf(bio_out, " DSA *dsa = DSA_new();\n" - " BIGNUM *p, *q, *g;\n" - "\n"); - BIO_printf(bio_out, " if (dsa == NULL)\n" - " return NULL;\n"); - BIO_printf(bio_out, " if (!DSA_set0_pqg(dsa, p = BN_bin2bn(dsap_%d, sizeof(dsap_%d), NULL),\n", - bits_p, bits_p); - BIO_printf(bio_out, " q = BN_bin2bn(dsaq_%d, sizeof(dsaq_%d), NULL),\n", - bits_p, bits_p); - BIO_printf(bio_out, " g = BN_bin2bn(dsag_%d, sizeof(dsag_%d), NULL))) {\n", - bits_p, bits_p); - BIO_printf(bio_out, " DSA_free(dsa);\n" - " BN_free(p);\n" - " BN_free(q);\n" - " BN_free(g);\n" - " return NULL;\n" - " }\n" - " return dsa;\n}\n"); - OPENSSL_free(data); + EVP_PKEY_print_params(out, params, 0, NULL); } if (outformat == FORMAT_ASN1 && genkey) @@ -205,49 +195,62 @@ int dsaparam_main(int argc, char **argv) if (!noout) { if (outformat == FORMAT_ASN1) - i = i2d_DSAparams_bio(out, dsa); + i = i2d_KeyParams_bio(out, params); else - i = PEM_write_bio_DSAparams(out, dsa); + i = PEM_write_bio_Parameters(out, params); if (!i) { - BIO_printf(bio_err, "unable to write DSA parameters\n"); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Error, unable to write DSA parameters\n"); goto end; } } if (genkey) { - DSA *dsakey; - - if ((dsakey = DSAparams_dup(dsa)) == NULL) + EVP_PKEY_CTX_free(ctx); + ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), params, + app_get0_propq()); + if (ctx == NULL) { + BIO_printf(bio_err, + "Error, DSA key generation context allocation failed\n"); goto end; - if (!DSA_generate_key(dsakey)) { - ERR_print_errors(bio_err); - DSA_free(dsakey); + } + if (EVP_PKEY_keygen_init(ctx) <= 0) { + BIO_printf(bio_err, + "Error, unable to initialise for key generation\n"); goto end; } + pkey = app_keygen(ctx, "DSA", numbits, verbose); assert(private); if (outformat == FORMAT_ASN1) - i = i2d_DSAPrivateKey_bio(out, dsakey); + i = i2d_PrivateKey_bio(out, pkey); else - i = PEM_write_bio_DSAPrivateKey(out, dsakey, NULL, NULL, 0, NULL, - NULL); - DSA_free(dsakey); + i = PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, NULL); } ret = 0; end: - BN_GENCB_free(cb); - BIO_free(in); + if (ret != 0) + ERR_print_errors(bio_err); BIO_free_all(out); - DSA_free(dsa); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + EVP_PKEY_free(params); release_engine(e); return ret; } -static int dsa_cb(int p, int n, BN_GENCB *cb) +static int gendsa_cb(EVP_PKEY_CTX *ctx) { static const char symbols[] = ".+*\n"; - char c = (p >= 0 && (size_t)p < sizeof(symbols) - 1) ? symbols[p] : '?'; + int p; + char c; + BIO *b; + + if (!verbose) + return 1; + + b = EVP_PKEY_CTX_get_app_data(ctx); + p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + c = (p >= 0 && (size_t)p < sizeof(symbols) - 1) ? symbols[p] : '?'; - BIO_write(BN_GENCB_get_arg(cb), &c, 1); - (void)BIO_flush(BN_GENCB_get_arg(cb)); + BIO_write(b, &c, 1); + (void)BIO_flush(b); return 1; } diff --git a/apps/ec.c b/apps/ec.c index 0c8ed750cc17..e2dd6f2b48f3 100644 --- a/apps/ec.c +++ b/apps/ec.c @@ -1,84 +1,84 @@ /* - * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> -#include <stdio.h> -#include <stdlib.h> #include <string.h> -#include "apps.h" -#include "progs.h" -#include <openssl/bio.h> -#include <openssl/err.h> +#include <openssl/opensslconf.h> #include <openssl/evp.h> -#include <openssl/pem.h> - -static OPT_PAIR conv_forms[] = { - {"compressed", POINT_CONVERSION_COMPRESSED}, - {"uncompressed", POINT_CONVERSION_UNCOMPRESSED}, - {"hybrid", POINT_CONVERSION_HYBRID}, - {NULL} -}; +#include <openssl/encoder.h> +#include <openssl/decoder.h> +#include <openssl/core_names.h> +#include <openssl/core_dispatch.h> +#include <openssl/params.h> +#include <openssl/err.h> -static OPT_PAIR param_enc[] = { - {"named_curve", OPENSSL_EC_NAMED_CURVE}, - {"explicit", 0}, - {NULL} -}; +#include "apps.h" +#include "progs.h" +#include "ec_common.h" typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, OPT_NOOUT, OPT_TEXT, OPT_PARAM_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_PASSIN, OPT_PASSOUT, OPT_PARAM_ENC, OPT_CONV_FORM, OPT_CIPHER, - OPT_NO_PUBLIC, OPT_CHECK + OPT_NO_PUBLIC, OPT_CHECK, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS ec_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), {"in", OPT_IN, 's', "Input file"}, - {"inform", OPT_INFORM, 'f', "Input format - DER or PEM"}, + {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)"}, + {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"check", OPT_CHECK, '-', "check key consistency"}, + {"", OPT_CIPHER, '-', "Any supported cipher"}, + {"param_enc", OPT_PARAM_ENC, 's', + "Specifies the way the ec parameters are encoded"}, + {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "}, + + OPT_SECTION("Output"), {"out", OPT_OUT, '>', "Output file"}, {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, {"noout", OPT_NOOUT, '-', "Don't print key out"}, {"text", OPT_TEXT, '-', "Print the key"}, {"param_out", OPT_PARAM_OUT, '-', "Print the elliptic curve parameters"}, - {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, {"no_public", OPT_NO_PUBLIC, '-', "exclude public key from private key"}, - {"check", OPT_CHECK, '-', "check key consistency"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - {"param_enc", OPT_PARAM_ENC, 's', - "Specifies the way the ec parameters are encoded"}, - {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "}, - {"", OPT_CIPHER, '-', "Any supported cipher"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + + OPT_PROV_OPTIONS, {NULL} }; int ec_main(int argc, char **argv) { - BIO *in = NULL, *out = NULL; + OSSL_ENCODER_CTX *ectx = NULL; + OSSL_DECODER_CTX *dctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *eckey = NULL; + BIO *out = NULL; ENGINE *e = NULL; - EC_KEY *eckey = NULL; - const EC_GROUP *group; - const EVP_CIPHER *enc = NULL; - point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; - char *infile = NULL, *outfile = NULL, *prog; + EVP_CIPHER *enc = NULL; + char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog; char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; OPTION_CHOICE o; - int asn1_flag = OPENSSL_EC_NAMED_CURVE, new_form = 0, new_asn1_flag = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, noout = 0; - int pubin = 0, pubout = 0, param_out = 0, i, ret = 1, private = 0; - int no_public = 0, check = 0; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0; + int pubin = 0, pubout = 0, param_out = 0, ret = 1, private = 0; + int check = 0; + char *asn1_encoding = NULL; + char *point_format = NULL; + int no_public = 0; prog = opt_init(argc, argv, ec_options); while ((o = opt_next()) != OPT_EOF) { @@ -131,20 +131,17 @@ int ec_main(int argc, char **argv) e = setup_engine(opt_arg(), 0); break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &enc)) - goto opthelp; + ciphername = opt_unknown(); break; case OPT_CONV_FORM: - if (!opt_pair(opt_arg(), conv_forms, &i)) + point_format = opt_arg(); + if (!opt_string(point_format, point_format_options)) goto opthelp; - new_form = 1; - form = i; break; case OPT_PARAM_ENC: - if (!opt_pair(opt_arg(), param_enc, &i)) + asn1_encoding = opt_arg(); + if (!opt_string(asn1_encoding, asn1_encoding_options)) goto opthelp; - new_asn1_flag = 1; - asn1_flag = i; break; case OPT_NO_PUBLIC: no_public = 1; @@ -152,12 +149,22 @@ int ec_main(int argc, char **argv) case OPT_CHECK: check = 1; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &enc)) + goto opthelp; + } private = param_out || pubin || pubout ? 0 : 1; if (text && !pubin) private = 1; @@ -167,37 +174,15 @@ int ec_main(int argc, char **argv) goto end; } - if (informat != FORMAT_ENGINE) { - in = bio_open_default(infile, 'r', informat); - if (in == NULL) - goto end; - } - BIO_printf(bio_err, "read EC key\n"); - if (informat == FORMAT_ASN1) { - if (pubin) - eckey = d2i_EC_PUBKEY_bio(in, NULL); - else - eckey = d2i_ECPrivateKey_bio(in, NULL); - } else if (informat == FORMAT_ENGINE) { - EVP_PKEY *pkey; - if (pubin) - pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key"); - else - pkey = load_key(infile, informat, 1, passin, e, "Private Key"); - if (pkey != NULL) { - eckey = EVP_PKEY_get1_EC_KEY(pkey); - EVP_PKEY_free(pkey); - } - } else { - if (pubin) - eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); - else - eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, passin); - } + + if (pubin) + eckey = load_pubkey(infile, informat, 1, passin, e, "public key"); + else + eckey = load_key(infile, informat, 1, passin, e, "private key"); + if (eckey == NULL) { BIO_printf(bio_err, "unable to load Key\n"); - ERR_print_errors(bio_err); goto end; } @@ -205,74 +190,105 @@ int ec_main(int argc, char **argv) if (out == NULL) goto end; - group = EC_KEY_get0_group(eckey); - - if (new_form) - EC_KEY_set_conv_form(eckey, form); + if (point_format + && !EVP_PKEY_set_utf8_string_param( + eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + point_format)) { + BIO_printf(bio_err, "unable to set point conversion format\n"); + goto end; + } - if (new_asn1_flag) - EC_KEY_set_asn1_flag(eckey, asn1_flag); + if (asn1_encoding != NULL + && !EVP_PKEY_set_utf8_string_param( + eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) { + BIO_printf(bio_err, "unable to set asn1 encoding format\n"); + goto end; + } - if (no_public) - EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY); + if (no_public) { + if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) { + BIO_printf(bio_err, "unable to disable public key encoding\n"); + goto end; + } + } else { + if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) { + BIO_printf(bio_err, "unable to enable public key encoding\n"); + goto end; + } + } if (text) { assert(pubin || private); - if (!EC_KEY_print(out, eckey, 0)) { - perror(outfile); - ERR_print_errors(bio_err); + if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0) + || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) { + BIO_printf(bio_err, "unable to print EC key\n"); goto end; } } if (check) { - if (EC_KEY_check_key(eckey) == 1) { - BIO_printf(bio_err, "EC Key valid.\n"); - } else { - BIO_printf(bio_err, "EC Key Invalid!\n"); - ERR_print_errors(bio_err); + pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL); + if (pctx == NULL) { + BIO_printf(bio_err, "unable to check EC key\n"); + goto end; } + if (EVP_PKEY_check(pctx) <= 0) + BIO_printf(bio_err, "EC Key Invalid!\n"); + else + BIO_printf(bio_err, "EC Key valid.\n"); + ERR_print_errors(bio_err); } - if (noout) { - ret = 0; - goto end; - } + if (!noout) { + int selection; + const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM"; + const char *output_structure = "type-specific"; - BIO_printf(bio_err, "writing EC key\n"); - if (outformat == FORMAT_ASN1) { + BIO_printf(bio_err, "writing EC key\n"); if (param_out) { - i = i2d_ECPKParameters_bio(out, group); + selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; } else if (pubin || pubout) { - i = i2d_EC_PUBKEY_bio(out, eckey); + selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS + | OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + output_structure = "SubjectPublicKeyInfo"; } else { + selection = OSSL_KEYMGMT_SELECT_ALL; assert(private); - i = i2d_ECPrivateKey_bio(out, eckey); } - } else { - if (param_out) { - i = PEM_write_bio_ECPKParameters(out, group); - } else if (pubin || pubout) { - i = PEM_write_bio_EC_PUBKEY(out, eckey); - } else { - assert(private); - i = PEM_write_bio_ECPrivateKey(out, eckey, enc, - NULL, 0, NULL, passout); + + ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection, + output_type, output_structure, + NULL); + if (enc != NULL) { + OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); + /* Default passphrase prompter */ + OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); + if (passout != NULL) + /* When passout given, override the passphrase prompter */ + OSSL_ENCODER_CTX_set_passphrase(ectx, + (const unsigned char *)passout, + strlen(passout)); + } + if (!OSSL_ENCODER_to_bio(ectx, out)) { + BIO_printf(bio_err, "unable to write EC key\n"); + goto end; } } - if (!i) { - BIO_printf(bio_err, "unable to write private key\n"); + ret = 0; +end: + if (ret != 0) ERR_print_errors(bio_err); - } else { - ret = 0; - } - end: - BIO_free(in); BIO_free_all(out); - EC_KEY_free(eckey); + EVP_PKEY_free(eckey); + EVP_CIPHER_free(enc); + OSSL_ENCODER_CTX_free(ectx); + OSSL_DECODER_CTX_free(dctx); + EVP_PKEY_CTX_free(pctx); release_engine(e); - OPENSSL_free(passin); - OPENSSL_free(passout); + if (passin != NULL) + OPENSSL_clear_free(passin, strlen(passin)); + if (passout != NULL) + OPENSSL_clear_free(passout, strlen(passout)); return ret; } diff --git a/apps/ecparam.c b/apps/ecparam.c index 58fbeb95c9ce..9e9ad136837b 100644 --- a/apps/ecparam.c +++ b/apps/ecparam.c @@ -1,92 +1,115 @@ /* - * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2022 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> #include <string.h> +#include <openssl/opensslconf.h> +#include <openssl/evp.h> +#include <openssl/encoder.h> +#include <openssl/decoder.h> +#include <openssl/core_names.h> +#include <openssl/core_dispatch.h> +#include <openssl/params.h> +#include <openssl/err.h> #include "apps.h" #include "progs.h" -#include <openssl/bio.h> -#include <openssl/err.h> -#include <openssl/bn.h> -#include <openssl/ec.h> -#include <openssl/x509.h> -#include <openssl/pem.h> +#include "ec_common.h" typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C, + OPT_COMMON, + OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_CHECK, OPT_LIST_CURVES, OPT_NO_SEED, OPT_NOOUT, OPT_NAME, - OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_ENGINE, - OPT_R_ENUM + OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_ENGINE, OPT_CHECK_NAMED, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS ecparam_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format - default PEM (DER or PEM)"}, - {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, + {"list_curves", OPT_LIST_CURVES, '-', + "Prints a list of all curve 'short names'"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + {"genkey", OPT_GENKEY, '-', "Generate ec key"}, {"in", OPT_IN, '<', "Input file - default stdin"}, + {"inform", OPT_INFORM, 'F', "Input format - default PEM (DER or PEM)"}, {"out", OPT_OUT, '>', "Output file - default stdout"}, + {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, + + OPT_SECTION("Output"), {"text", OPT_TEXT, '-', "Print the ec parameters in text form"}, - {"C", OPT_C, '-', "Print a 'C' function creating the parameters"}, + {"noout", OPT_NOOUT, '-', "Do not print the ec parameter"}, + {"param_enc", OPT_PARAM_ENC, 's', + "Specifies the way the ec parameters are encoded"}, + + OPT_SECTION("Parameter"), {"check", OPT_CHECK, '-', "Validate the ec parameters"}, - {"list_curves", OPT_LIST_CURVES, '-', - "Prints a list of all curve 'short names'"}, + {"check_named", OPT_CHECK_NAMED, '-', + "Check that named EC curve parameters have not been modified"}, {"no_seed", OPT_NO_SEED, '-', "If 'explicit' parameters are chosen do not use the seed"}, - {"noout", OPT_NOOUT, '-', "Do not print the ec parameter"}, {"name", OPT_NAME, 's', "Use the ec parameters with specified 'short name'"}, {"conv_form", OPT_CONV_FORM, 's', "Specifies the point conversion form "}, - {"param_enc", OPT_PARAM_ENC, 's', - "Specifies the way the ec parameters are encoded"}, - {"genkey", OPT_GENKEY, '-', "Generate ec key"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + OPT_PROV_OPTIONS, {NULL} }; -static OPT_PAIR forms[] = { - {"compressed", POINT_CONVERSION_COMPRESSED}, - {"uncompressed", POINT_CONVERSION_UNCOMPRESSED}, - {"hybrid", POINT_CONVERSION_HYBRID}, - {NULL} -}; +static int list_builtin_curves(BIO *out) +{ + int ret = 0; + EC_builtin_curve *curves = NULL; + size_t n, crv_len = EC_get_builtin_curves(NULL, 0); -static OPT_PAIR encodings[] = { - {"named_curve", OPENSSL_EC_NAMED_CURVE}, - {"explicit", 0}, - {NULL} -}; + curves = app_malloc((int)sizeof(*curves) * crv_len, "list curves"); + if (!EC_get_builtin_curves(curves, crv_len)) + goto end; + + for (n = 0; n < crv_len; n++) { + const char *comment = curves[n].comment; + const char *sname = OBJ_nid2sn(curves[n].nid); + + if (comment == NULL) + comment = "CURVE DESCRIPTION NOT AVAILABLE"; + if (sname == NULL) + sname = ""; + + BIO_printf(out, " %-10s: ", sname); + BIO_printf(out, "%s\n", comment); + } + ret = 1; +end: + OPENSSL_free(curves); + return ret; +} int ecparam_main(int argc, char **argv) { + EVP_PKEY_CTX *gctx_params = NULL, *gctx_key = NULL, *pctx = NULL; + EVP_PKEY *params_key = NULL, *key = NULL; + OSSL_ENCODER_CTX *ectx_key = NULL, *ectx_params = NULL; + OSSL_DECODER_CTX *dctx_params = NULL; ENGINE *e = NULL; - BIGNUM *ec_gen = NULL, *ec_order = NULL, *ec_cofactor = NULL; - BIGNUM *ec_p = NULL, *ec_a = NULL, *ec_b = NULL; - BIO *in = NULL, *out = NULL; - EC_GROUP *group = NULL; - point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; + BIO *out = NULL; char *curve_name = NULL; + char *asn1_encoding = NULL; + char *point_format = NULL; char *infile = NULL, *outfile = NULL, *prog; - unsigned char *buffer = NULL; OPTION_CHOICE o; - int asn1_flag = OPENSSL_EC_NAMED_CURVE, new_asn1_flag = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0; + int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0; int ret = 1, private = 0; - int list_curves = 0, no_seed = 0, check = 0, new_form = 0; - int text = 0, i, genkey = 0; + int no_seed = 0, check = 0, check_named = 0, text = 0, genkey = 0; + int list_curves = 0; prog = opt_init(argc, argv, ecparam_options); while ((o = opt_next()) != OPT_EOF) { @@ -117,12 +140,12 @@ int ecparam_main(int argc, char **argv) case OPT_TEXT: text = 1; break; - case OPT_C: - C = 1; - break; case OPT_CHECK: check = 1; break; + case OPT_CHECK_NAMED: + check_named = 1; + break; case OPT_LIST_CURVES: list_curves = 1; break; @@ -136,15 +159,14 @@ int ecparam_main(int argc, char **argv) curve_name = opt_arg(); break; case OPT_CONV_FORM: - if (!opt_pair(opt_arg(), forms, &new_form)) + point_format = opt_arg(); + if (!opt_string(point_format, point_format_options)) goto opthelp; - form = new_form; - new_form = 1; break; case OPT_PARAM_ENC: - if (!opt_pair(opt_arg(), encodings, &asn1_flag)) + asn1_encoding = opt_arg(); + if (!opt_string(asn1_encoding, asn1_encoding_options)) goto opthelp; - new_asn1_flag = 1; break; case OPT_GENKEY: genkey = 1; @@ -153,292 +175,178 @@ int ecparam_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; } } + + /* No extra args. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (!app_RAND_load()) + goto end; + private = genkey ? 1 : 0; - in = bio_open_default(infile, 'r', informat); - if (in == NULL) - goto end; out = bio_open_owner(outfile, outformat, private); if (out == NULL) goto end; if (list_curves) { - EC_builtin_curve *curves = NULL; - size_t crv_len = EC_get_builtin_curves(NULL, 0); - size_t n; - - curves = app_malloc((int)sizeof(*curves) * crv_len, "list curves"); - if (!EC_get_builtin_curves(curves, crv_len)) { - OPENSSL_free(curves); - goto end; - } - - for (n = 0; n < crv_len; n++) { - const char *comment; - const char *sname; - comment = curves[n].comment; - sname = OBJ_nid2sn(curves[n].nid); - if (comment == NULL) - comment = "CURVE DESCRIPTION NOT AVAILABLE"; - if (sname == NULL) - sname = ""; - - BIO_printf(out, " %-10s: ", sname); - BIO_printf(out, "%s\n", comment); - } - - OPENSSL_free(curves); - ret = 0; + if (list_builtin_curves(out)) + ret = 0; goto end; } if (curve_name != NULL) { - int nid; + OSSL_PARAM params[4]; + OSSL_PARAM *p = params; - /* - * workaround for the SECG curve names secp192r1 and secp256r1 (which - * are the same as the curves prime192v1 and prime256v1 defined in - * X9.62) - */ if (strcmp(curve_name, "secp192r1") == 0) { - BIO_printf(bio_err, "using curve name prime192v1 " - "instead of secp192r1\n"); - nid = NID_X9_62_prime192v1; + BIO_printf(bio_err, + "using curve name prime192v1 instead of secp192r1\n"); + curve_name = SN_X9_62_prime192v1; } else if (strcmp(curve_name, "secp256r1") == 0) { - BIO_printf(bio_err, "using curve name prime256v1 " - "instead of secp256r1\n"); - nid = NID_X9_62_prime256v1; - } else { - nid = OBJ_sn2nid(curve_name); + BIO_printf(bio_err, + "using curve name prime256v1 instead of secp256r1\n"); + curve_name = SN_X9_62_prime256v1; } - - if (nid == 0) - nid = EC_curve_nist2nid(curve_name); - - if (nid == 0) { - BIO_printf(bio_err, "unknown curve name (%s)\n", curve_name); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + curve_name, 0); + if (asn1_encoding != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, + asn1_encoding, 0); + if (point_format != NULL) + *p++ = OSSL_PARAM_construct_utf8_string( + OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + point_format, 0); + *p = OSSL_PARAM_construct_end(); + + if (OPENSSL_strcasecmp(curve_name, "SM2") == 0) + gctx_params = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "sm2", + app_get0_propq()); + else + gctx_params = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "ec", + app_get0_propq()); + if (gctx_params == NULL + || EVP_PKEY_keygen_init(gctx_params) <= 0 + || EVP_PKEY_CTX_set_params(gctx_params, params) <= 0 + || EVP_PKEY_keygen(gctx_params, ¶ms_key) <= 0) { + BIO_printf(bio_err, "unable to generate key\n"); + goto end; + } + } else { + params_key = load_keyparams(infile, informat, 1, "EC", "EC parameters"); + if (params_key == NULL || !EVP_PKEY_is_a(params_key, "EC")) + goto end; + if (point_format + && !EVP_PKEY_set_utf8_string_param( + params_key, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + point_format)) { + BIO_printf(bio_err, "unable to set point conversion format\n"); goto end; } - group = EC_GROUP_new_by_curve_name(nid); - if (group == NULL) { - BIO_printf(bio_err, "unable to create curve (%s)\n", curve_name); + if (asn1_encoding != NULL + && !EVP_PKEY_set_utf8_string_param( + params_key, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) { + BIO_printf(bio_err, "unable to set asn1 encoding format\n"); goto end; } - EC_GROUP_set_asn1_flag(group, asn1_flag); - EC_GROUP_set_point_conversion_form(group, form); - } else if (informat == FORMAT_ASN1) { - group = d2i_ECPKParameters_bio(in, NULL); - } else { - group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); } - if (group == NULL) { - BIO_printf(bio_err, "unable to load elliptic curve parameters\n"); - ERR_print_errors(bio_err); - goto end; - } - - if (new_form) - EC_GROUP_set_point_conversion_form(group, form); - if (new_asn1_flag) - EC_GROUP_set_asn1_flag(group, asn1_flag); - - if (no_seed) { - EC_GROUP_set_seed(group, NULL, 0); + if (no_seed + && !EVP_PKEY_set_octet_string_param(params_key, OSSL_PKEY_PARAM_EC_SEED, + NULL, 0)) { + BIO_printf(bio_err, "unable to clear seed\n"); + goto end; } - if (text) { - if (!ECPKParameters_print(out, group, 0)) - goto end; + if (text + && !EVP_PKEY_print_params(out, params_key, 0, NULL)) { + BIO_printf(bio_err, "unable to print params\n"); + goto end; } - if (check) { + if (check || check_named) { BIO_printf(bio_err, "checking elliptic curve parameters: "); - if (!EC_GROUP_check(group, NULL)) { - BIO_printf(bio_err, "failed\n"); - ERR_print_errors(bio_err); - goto end; - } - BIO_printf(bio_err, "ok\n"); - - } - - if (C) { - size_t buf_len = 0, tmp_len = 0; - const EC_POINT *point; - int is_prime, len = 0; - const EC_METHOD *meth = EC_GROUP_method_of(group); - if ((ec_p = BN_new()) == NULL - || (ec_a = BN_new()) == NULL - || (ec_b = BN_new()) == NULL - || (ec_gen = BN_new()) == NULL - || (ec_order = BN_new()) == NULL - || (ec_cofactor = BN_new()) == NULL) { - perror("Can't allocate BN"); - goto end; + if (check_named + && !EVP_PKEY_set_utf8_string_param(params_key, + OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE, + OSSL_PKEY_EC_GROUP_CHECK_NAMED)) { + BIO_printf(bio_err, "unable to set check_type\n"); + goto end; } - - is_prime = (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field); - if (!is_prime) { - BIO_printf(bio_err, "Can only handle X9.62 prime fields\n"); + pctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), params_key, + app_get0_propq()); + if (pctx == NULL || EVP_PKEY_param_check(pctx) <= 0) { + BIO_printf(bio_err, "failed\n"); goto end; } - - if (!EC_GROUP_get_curve(group, ec_p, ec_a, ec_b, NULL)) - goto end; - - if ((point = EC_GROUP_get0_generator(group)) == NULL) - goto end; - if (!EC_POINT_point2bn(group, point, - EC_GROUP_get_point_conversion_form(group), - ec_gen, NULL)) - goto end; - if (!EC_GROUP_get_order(group, ec_order, NULL)) - goto end; - if (!EC_GROUP_get_cofactor(group, ec_cofactor, NULL)) - goto end; - - if (!ec_p || !ec_a || !ec_b || !ec_gen || !ec_order || !ec_cofactor) - goto end; - - len = BN_num_bits(ec_order); - - if ((tmp_len = (size_t)BN_num_bytes(ec_p)) > buf_len) - buf_len = tmp_len; - if ((tmp_len = (size_t)BN_num_bytes(ec_a)) > buf_len) - buf_len = tmp_len; - if ((tmp_len = (size_t)BN_num_bytes(ec_b)) > buf_len) - buf_len = tmp_len; - if ((tmp_len = (size_t)BN_num_bytes(ec_gen)) > buf_len) - buf_len = tmp_len; - if ((tmp_len = (size_t)BN_num_bytes(ec_order)) > buf_len) - buf_len = tmp_len; - if ((tmp_len = (size_t)BN_num_bytes(ec_cofactor)) > buf_len) - buf_len = tmp_len; - - buffer = app_malloc(buf_len, "BN buffer"); - - BIO_printf(out, "EC_GROUP *get_ec_group_%d(void)\n{\n", len); - print_bignum_var(out, ec_p, "ec_p", len, buffer); - print_bignum_var(out, ec_a, "ec_a", len, buffer); - print_bignum_var(out, ec_b, "ec_b", len, buffer); - print_bignum_var(out, ec_gen, "ec_gen", len, buffer); - print_bignum_var(out, ec_order, "ec_order", len, buffer); - print_bignum_var(out, ec_cofactor, "ec_cofactor", len, buffer); - BIO_printf(out, " int ok = 0;\n" - " EC_GROUP *group = NULL;\n" - " EC_POINT *point = NULL;\n" - " BIGNUM *tmp_1 = NULL;\n" - " BIGNUM *tmp_2 = NULL;\n" - " BIGNUM *tmp_3 = NULL;\n" - "\n"); - - BIO_printf(out, " if ((tmp_1 = BN_bin2bn(ec_p_%d, sizeof(ec_p_%d), NULL)) == NULL)\n" - " goto err;\n", len, len); - BIO_printf(out, " if ((tmp_2 = BN_bin2bn(ec_a_%d, sizeof(ec_a_%d), NULL)) == NULL)\n" - " goto err;\n", len, len); - BIO_printf(out, " if ((tmp_3 = BN_bin2bn(ec_b_%d, sizeof(ec_b_%d), NULL)) == NULL)\n" - " goto err;\n", len, len); - BIO_printf(out, " if ((group = EC_GROUP_new_curve_GFp(tmp_1, tmp_2, tmp_3, NULL)) == NULL)\n" - " goto err;\n" - "\n"); - BIO_printf(out, " /* build generator */\n"); - BIO_printf(out, " if ((tmp_1 = BN_bin2bn(ec_gen_%d, sizeof(ec_gen_%d), tmp_1)) == NULL)\n" - " goto err;\n", len, len); - BIO_printf(out, " point = EC_POINT_bn2point(group, tmp_1, NULL, NULL);\n"); - BIO_printf(out, " if (point == NULL)\n" - " goto err;\n"); - BIO_printf(out, " if ((tmp_2 = BN_bin2bn(ec_order_%d, sizeof(ec_order_%d), tmp_2)) == NULL)\n" - " goto err;\n", len, len); - BIO_printf(out, " if ((tmp_3 = BN_bin2bn(ec_cofactor_%d, sizeof(ec_cofactor_%d), tmp_3)) == NULL)\n" - " goto err;\n", len, len); - BIO_printf(out, " if (!EC_GROUP_set_generator(group, point, tmp_2, tmp_3))\n" - " goto err;\n" - "ok = 1;" - "\n"); - BIO_printf(out, "err:\n" - " BN_free(tmp_1);\n" - " BN_free(tmp_2);\n" - " BN_free(tmp_3);\n" - " EC_POINT_free(point);\n" - " if (!ok) {\n" - " EC_GROUP_free(group);\n" - " return NULL;\n" - " }\n" - " return (group);\n" - "}\n"); + BIO_printf(bio_err, "ok\n"); } if (outformat == FORMAT_ASN1 && genkey) noout = 1; if (!noout) { - if (outformat == FORMAT_ASN1) - i = i2d_ECPKParameters_bio(out, group); - else - i = PEM_write_bio_ECPKParameters(out, group); - if (!i) { - BIO_printf(bio_err, "unable to write elliptic " - "curve parameters\n"); - ERR_print_errors(bio_err); + ectx_params = OSSL_ENCODER_CTX_new_for_pkey( + params_key, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + outformat == FORMAT_ASN1 ? "DER" : "PEM", NULL, NULL); + if (!OSSL_ENCODER_to_bio(ectx_params, out)) { + BIO_printf(bio_err, "unable to write elliptic curve parameters\n"); goto end; } } if (genkey) { - EC_KEY *eckey = EC_KEY_new(); - - if (eckey == NULL) - goto end; - - if (EC_KEY_set_group(eckey, group) == 0) { - BIO_printf(bio_err, "unable to set group when generating key\n"); - EC_KEY_free(eckey); - ERR_print_errors(bio_err); - goto end; - } - - if (new_form) - EC_KEY_set_conv_form(eckey, form); - - if (!EC_KEY_generate_key(eckey)) { + /* + * NOTE: EC keygen does not normally need to pass in the param_key + * for named curves. This can be achieved using: + * gctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + * EVP_PKEY_keygen_init(gctx); + * EVP_PKEY_CTX_set_group_name(gctx, curvename); + * EVP_PKEY_keygen(gctx, &key) <= 0) + */ + gctx_key = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), params_key, + app_get0_propq()); + if (EVP_PKEY_keygen_init(gctx_key) <= 0 + || EVP_PKEY_keygen(gctx_key, &key) <= 0) { BIO_printf(bio_err, "unable to generate key\n"); - EC_KEY_free(eckey); - ERR_print_errors(bio_err); goto end; } assert(private); - if (outformat == FORMAT_ASN1) - i = i2d_ECPrivateKey_bio(out, eckey); - else - i = PEM_write_bio_ECPrivateKey(out, eckey, NULL, - NULL, 0, NULL, NULL); - EC_KEY_free(eckey); + ectx_key = OSSL_ENCODER_CTX_new_for_pkey( + key, OSSL_KEYMGMT_SELECT_ALL, + outformat == FORMAT_ASN1 ? "DER" : "PEM", NULL, NULL); + if (!OSSL_ENCODER_to_bio(ectx_key, out)) { + BIO_printf(bio_err, "unable to write elliptic " + "curve parameters\n"); + goto end; + } } ret = 0; - end: - BN_free(ec_p); - BN_free(ec_a); - BN_free(ec_b); - BN_free(ec_gen); - BN_free(ec_order); - BN_free(ec_cofactor); - OPENSSL_free(buffer); - EC_GROUP_free(group); +end: + if (ret != 0) + ERR_print_errors(bio_err); release_engine(e); - BIO_free(in); + EVP_PKEY_free(params_key); + EVP_PKEY_free(key); + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_CTX_free(gctx_params); + EVP_PKEY_CTX_free(gctx_key); + OSSL_DECODER_CTX_free(dctx_params); + OSSL_ENCODER_CTX_free(ectx_params); + OSSL_ENCODER_CTX_free(ectx_key); BIO_free_all(out); return ret; } diff --git a/apps/enc.c b/apps/enc.c index 65710771a089..3dd609856304 100644 --- a/apps/enc.c +++ b/apps/enc.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -39,38 +39,51 @@ struct doall_enc_ciphers { }; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_LIST, OPT_E, OPT_IN, OPT_OUT, OPT_PASS, OPT_ENGINE, OPT_D, OPT_P, OPT_V, OPT_NOPAD, OPT_SALT, OPT_NOSALT, OPT_DEBUG, OPT_UPPER_P, OPT_UPPER_A, OPT_A, OPT_Z, OPT_BUFSIZE, OPT_K, OPT_KFILE, OPT_UPPER_K, OPT_NONE, OPT_UPPER_S, OPT_IV, OPT_MD, OPT_ITER, OPT_PBKDF2, OPT_CIPHER, - OPT_R_ENUM + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS enc_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, {"list", OPT_LIST, '-', "List ciphers"}, +#ifndef OPENSSL_NO_DEPRECATED_3_0 {"ciphers", OPT_LIST, '-', "Alias for -list"}, - {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, - {"pass", OPT_PASS, 's', "Passphrase source"}, +#endif {"e", OPT_E, '-', "Encrypt"}, {"d", OPT_D, '-', "Decrypt"}, {"p", OPT_P, '-', "Print the iv/key"}, {"P", OPT_UPPER_P, '-', "Print the iv/key and exit"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), + {"in", OPT_IN, '<', "Input file"}, + {"k", OPT_K, 's', "Passphrase"}, + {"kfile", OPT_KFILE, '<', "Read passphrase from file"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"pass", OPT_PASS, 's', "Passphrase source"}, {"v", OPT_V, '-', "Verbose output"}, - {"nopad", OPT_NOPAD, '-', "Disable standard block padding"}, - {"salt", OPT_SALT, '-', "Use salt in the KDF (default)"}, - {"nosalt", OPT_NOSALT, '-', "Do not use salt in the KDF"}, - {"debug", OPT_DEBUG, '-', "Print debug info"}, {"a", OPT_A, '-', "Base64 encode/decode, depending on encryption flag"}, {"base64", OPT_A, '-', "Same as option -a"}, {"A", OPT_UPPER_A, '-', "Used with -[base64|a] to specify base64 buffer as a single line"}, + + OPT_SECTION("Encryption"), + {"nopad", OPT_NOPAD, '-', "Disable standard block padding"}, + {"salt", OPT_SALT, '-', "Use salt in the KDF (default)"}, + {"nosalt", OPT_NOSALT, '-', "Do not use salt in the KDF"}, + {"debug", OPT_DEBUG, '-', "Print debug info"}, + {"bufsize", OPT_BUFSIZE, 's', "Buffer size"}, - {"k", OPT_K, 's', "Passphrase"}, - {"kfile", OPT_KFILE, '<', "Read passphrase from file"}, {"K", OPT_UPPER_K, 's', "Raw key, in hex"}, {"S", OPT_UPPER_S, 's', "Salt, in hex"}, {"iv", OPT_IV, 's', "IV in hex"}, @@ -78,14 +91,13 @@ const OPTIONS enc_options[] = { {"iter", OPT_ITER, 'p', "Specify the iteration count and force use of PBKDF2"}, {"pbkdf2", OPT_PBKDF2, '-', "Use password-based key derivation function 2"}, {"none", OPT_NONE, '-', "Don't encrypt"}, - {"", OPT_CIPHER, '-', "Any supported cipher"}, - OPT_R_OPTIONS, #ifdef ZLIB {"z", OPT_Z, '-', "Compress or decompress encrypted data using zlib"}, #endif -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + {"", OPT_CIPHER, '-', "Any supported cipher"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, {NULL} }; @@ -97,11 +109,13 @@ int enc_main(int argc, char **argv) BIO *in = NULL, *out = NULL, *b64 = NULL, *benc = NULL, *rbio = NULL, *wbio = NULL; EVP_CIPHER_CTX *ctx = NULL; - const EVP_CIPHER *cipher = NULL, *c; - const EVP_MD *dgst = NULL; + EVP_CIPHER *cipher = NULL; + EVP_MD *dgst = NULL; + const char *digestname = NULL; char *hkey = NULL, *hiv = NULL, *hsalt = NULL, *p; char *infile = NULL, *outfile = NULL, *prog; char *str = NULL, *passarg = NULL, *pass = NULL, *strbuf = NULL; + const char *ciphername = NULL; char mbuf[sizeof(magic) - 1]; OPTION_CHOICE o; int bsize = BSIZE, verbose = 0, debug = 0, olb64 = 0, nosalt = 0; @@ -119,21 +133,15 @@ int enc_main(int argc, char **argv) BIO *bzl = NULL; #endif - /* first check the program name */ - prog = opt_progname(argv[0]); - if (strcmp(prog, "base64") == 0) { + /* first check the command name */ + if (strcmp(argv[0], "base64") == 0) base64 = 1; #ifdef ZLIB - } else if (strcmp(prog, "zlib") == 0) { + else if (strcmp(argv[0], "zlib") == 0) do_zlib = 1; #endif - } else { - cipher = EVP_get_cipherbyname(prog); - if (cipher == NULL && strcmp(prog, "enc") != 0) { - BIO_printf(bio_err, "%s is not a known cipher\n", prog); - goto end; - } - } + else if (strcmp(argv[0], "enc") != 0) + ciphername = argv[0]; prog = opt_init(argc, argv, enc_options); while ((o = opt_next()) != OPT_EOF) { @@ -252,17 +260,13 @@ int enc_main(int argc, char **argv) hiv = opt_arg(); break; case OPT_MD: - if (!opt_md(opt_arg(), &dgst)) - goto opthelp; + digestname = opt_arg(); break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &c)) - goto opthelp; - cipher = c; + ciphername = opt_unknown(); break; case OPT_ITER: - if (!opt_int(opt_arg(), &iter)) - goto opthelp; + iter = opt_int_arg(); pbkdf2 = 1; break; case OPT_PBKDF2: @@ -277,25 +281,31 @@ int enc_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } - if (opt_num_rest() != 0) { - BIO_printf(bio_err, "Extra arguments given.\n"); - goto opthelp; - } - if (cipher && EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) { - BIO_printf(bio_err, "%s: AEAD ciphers not supported\n", prog); + /* No extra arguments. */ + argc = opt_num_rest(); + if (argc != 0) + goto opthelp; + if (!app_RAND_load()) goto end; - } - if (cipher && (EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE)) { - BIO_printf(bio_err, "%s XTS ciphers not supported\n", prog); - goto end; + /* Get the cipher name, either from progname (if set) or flag. */ + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &cipher)) + goto opthelp; + } + if (digestname != NULL) { + if (!opt_md(digestname, &dgst)) + goto opthelp; } - if (dgst == NULL) - dgst = EVP_sha256(); + dgst = (EVP_MD *)EVP_sha256(); if (iter == 0) iter = 1; @@ -342,7 +352,7 @@ int enc_main(int argc, char **argv) char prompt[200]; BIO_snprintf(prompt, sizeof(prompt), "enter %s %s password:", - OBJ_nid2ln(EVP_CIPHER_nid(cipher)), + EVP_CIPHER_get0_name(cipher), (enc) ? "encryption" : "decryption"); strbuf[0] = '\0'; i = EVP_read_pw_string((char *)strbuf, SIZE, prompt, enc); @@ -371,8 +381,8 @@ int enc_main(int argc, char **argv) goto end; if (debug) { - BIO_set_callback(in, BIO_debug_callback); - BIO_set_callback(out, BIO_debug_callback); + BIO_set_callback_ex(in, BIO_debug_callback_ex); + BIO_set_callback_ex(out, BIO_debug_callback_ex); BIO_set_callback_arg(in, (char *)bio_err); BIO_set_callback_arg(out, (char *)bio_err); } @@ -385,7 +395,7 @@ int enc_main(int argc, char **argv) if ((bzl = BIO_new(BIO_f_zlib())) == NULL) goto end; if (debug) { - BIO_set_callback(bzl, BIO_debug_callback); + BIO_set_callback_ex(bzl, BIO_debug_callback_ex); BIO_set_callback_arg(bzl, (char *)bio_err); } if (enc) @@ -399,7 +409,7 @@ int enc_main(int argc, char **argv) if ((b64 = BIO_new(BIO_f_base64())) == NULL) goto end; if (debug) { - BIO_set_callback(b64, BIO_debug_callback); + BIO_set_callback_ex(b64, BIO_debug_callback_ex); BIO_set_callback_arg(b64, (char *)bio_err); } if (olb64) @@ -411,14 +421,11 @@ int enc_main(int argc, char **argv) } if (cipher != NULL) { - /* - * Note that str is NULL if a key was passed on the command line, so - * we get no salt in that case. Is this a bug? - */ - if (str != NULL) { + if (str != NULL) { /* a passphrase is available */ /* - * Salt handling: if encrypting generate a salt and write to - * output BIO. If decrypting read salt from input BIO. + * Salt handling: if encrypting generate a salt if not supplied, + * and write to output BIO. If decrypting use salt from input BIO + * if not given with args */ unsigned char *sptr; size_t str_len = strlen(str); @@ -426,36 +433,47 @@ int enc_main(int argc, char **argv) if (nosalt) { sptr = NULL; } else { - if (enc) { - if (hsalt) { - if (!set_hex(hsalt, salt, sizeof(salt))) { - BIO_printf(bio_err, "invalid hex salt value\n"); + if (hsalt != NULL && !set_hex(hsalt, salt, sizeof(salt))) { + BIO_printf(bio_err, "invalid hex salt value\n"); + goto end; + } + if (enc) { /* encryption */ + if (hsalt == NULL) { + if (RAND_bytes(salt, sizeof(salt)) <= 0) { + BIO_printf(bio_err, "RAND_bytes failed\n"); + goto end; + } + /* + * If -P option then don't bother writing. + * If salt is given, shouldn't either ? + */ + if ((printkey != 2) + && (BIO_write(wbio, magic, + sizeof(magic) - 1) != sizeof(magic) - 1 + || BIO_write(wbio, + (char *)salt, + sizeof(salt)) != sizeof(salt))) { + BIO_printf(bio_err, "error writing output file\n"); goto end; } - } else if (RAND_bytes(salt, sizeof(salt)) <= 0) { - goto end; } - /* - * If -P option then don't bother writing - */ - if ((printkey != 2) - && (BIO_write(wbio, magic, - sizeof(magic) - 1) != sizeof(magic) - 1 - || BIO_write(wbio, - (char *)salt, - sizeof(salt)) != sizeof(salt))) { - BIO_printf(bio_err, "error writing output file\n"); - goto end; + } else { /* decryption */ + if (hsalt == NULL) { + if (BIO_read(rbio, mbuf, sizeof(mbuf)) != sizeof(mbuf)) { + BIO_printf(bio_err, "error reading input file\n"); + goto end; + } + if (memcmp(mbuf, magic, sizeof(mbuf)) == 0) { /* file IS salted */ + if (BIO_read(rbio, salt, + sizeof(salt)) != sizeof(salt)) { + BIO_printf(bio_err, "error reading input file\n"); + goto end; + } + } else { /* file is NOT salted, NO salt available */ + BIO_printf(bio_err, "bad magic number\n"); + goto end; + } } - } else if (BIO_read(rbio, mbuf, sizeof(mbuf)) != sizeof(mbuf) - || BIO_read(rbio, - (unsigned char *)salt, - sizeof(salt)) != sizeof(salt)) { - BIO_printf(bio_err, "error reading input file\n"); - goto end; - } else if (memcmp(mbuf, magic, sizeof(magic) - 1)) { - BIO_printf(bio_err, "bad magic number\n"); - goto end; } sptr = salt; } @@ -466,8 +484,8 @@ int enc_main(int argc, char **argv) * concatenated into a temporary buffer */ unsigned char tmpkeyiv[EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH]; - int iklen = EVP_CIPHER_key_length(cipher); - int ivlen = EVP_CIPHER_iv_length(cipher); + int iklen = EVP_CIPHER_get_key_length(cipher); + int ivlen = EVP_CIPHER_get_iv_length(cipher); /* not needed if HASH_UPDATE() is fixed : */ int islen = (sptr != NULL ? sizeof(salt) : 0); if (!PKCS5_PBKDF2_HMAC(str, str_len, sptr, islen, @@ -499,7 +517,7 @@ int enc_main(int argc, char **argv) OPENSSL_cleanse(str, str_len); } if (hiv != NULL) { - int siz = EVP_CIPHER_iv_length(cipher); + int siz = EVP_CIPHER_get_iv_length(cipher); if (siz == 0) { BIO_printf(bio_err, "warning: iv not used by this cipher\n"); } else if (!set_hex(hiv, iv, siz)) { @@ -508,7 +526,7 @@ int enc_main(int argc, char **argv) } } if ((hiv == NULL) && (str == NULL) - && EVP_CIPHER_iv_length(cipher) != 0) { + && EVP_CIPHER_get_iv_length(cipher) != 0) { /* * No IV was explicitly set and no IV was generated. * Hence the IV is undefined, making correct decryption impossible. @@ -517,12 +535,12 @@ int enc_main(int argc, char **argv) goto end; } if (hkey != NULL) { - if (!set_hex(hkey, key, EVP_CIPHER_key_length(cipher))) { + if (!set_hex(hkey, key, EVP_CIPHER_get_key_length(cipher))) { BIO_printf(bio_err, "invalid hex key value\n"); goto end; } /* wiping secret data as we no longer need it */ - OPENSSL_cleanse(hkey, strlen(hkey)); + cleanse(hkey); } if ((benc = BIO_new(BIO_f_cipher())) == NULL) @@ -535,9 +553,9 @@ int enc_main(int argc, char **argv) BIO_get_cipher_ctx(benc, &ctx); - if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc)) { + if (!EVP_CipherInit_ex(ctx, cipher, e, NULL, NULL, enc)) { BIO_printf(bio_err, "Error setting cipher %s\n", - EVP_CIPHER_name(cipher)); + EVP_CIPHER_get0_name(cipher)); ERR_print_errors(bio_err); goto end; } @@ -547,13 +565,13 @@ int enc_main(int argc, char **argv) if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc)) { BIO_printf(bio_err, "Error setting cipher %s\n", - EVP_CIPHER_name(cipher)); + EVP_CIPHER_get0_name(cipher)); ERR_print_errors(bio_err); goto end; } if (debug) { - BIO_set_callback(benc, BIO_debug_callback); + BIO_set_callback_ex(benc, BIO_debug_callback_ex); BIO_set_callback_arg(benc, (char *)bio_err); } @@ -564,15 +582,15 @@ int enc_main(int argc, char **argv) printf("%02X", salt[i]); printf("\n"); } - if (EVP_CIPHER_key_length(cipher) > 0) { + if (EVP_CIPHER_get_key_length(cipher) > 0) { printf("key="); - for (i = 0; i < EVP_CIPHER_key_length(cipher); i++) + for (i = 0; i < EVP_CIPHER_get_key_length(cipher); i++) printf("%02X", key[i]); printf("\n"); } - if (EVP_CIPHER_iv_length(cipher) > 0) { + if (EVP_CIPHER_get_iv_length(cipher) > 0) { printf("iv ="); - for (i = 0; i < EVP_CIPHER_iv_length(cipher); i++) + for (i = 0; i < EVP_CIPHER_get_iv_length(cipher); i++) printf("%02X", iv[i]); printf("\n"); } @@ -614,6 +632,8 @@ int enc_main(int argc, char **argv) BIO_free_all(out); BIO_free(benc); BIO_free(b64); + EVP_MD_free(dgst); + EVP_CIPHER_free(cipher); #ifdef ZLIB BIO_free(bzl); #endif @@ -632,9 +652,9 @@ static void show_ciphers(const OBJ_NAME *name, void *arg) /* Filter out ciphers that we cannot use */ cipher = EVP_get_cipherbyname(name->name); - if (cipher == NULL || - (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0 || - EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE) + if (cipher == NULL + || (EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0 + || EVP_CIPHER_get_mode(cipher) == EVP_CIPH_XTS_MODE) return; BIO_printf(dec->bio, "-%-25s", name->name); diff --git a/apps/engine.c b/apps/engine.c index 746cace354b2..1b0f64309c6f 100644 --- a/apps/engine.c +++ b/apps/engine.c @@ -1,13 +1,17 @@ /* - * Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 */ +/* We need to use some engine deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include <openssl/opensslconf.h> + #include "apps.h" #include "progs.h" #include <stdio.h> @@ -19,27 +23,32 @@ #include <openssl/store.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_C, OPT_T, OPT_TT, OPT_PRE, OPT_POST, OPT_V = 100, OPT_VV, OPT_VVV, OPT_VVVV } OPTION_CHOICE; const OPTIONS engine_options[] = { {OPT_HELP_STR, 1, '-', "Usage: %s [options] engine...\n"}, - {OPT_HELP_STR, 1, '-', - " engine... Engines to load\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"t", OPT_T, '-', "Check that specified engine is available"}, + {"pre", OPT_PRE, 's', "Run command against the ENGINE before loading it"}, + {"post", OPT_POST, 's', "Run command against the ENGINE after loading it"}, + + OPT_SECTION("Output"), {"v", OPT_V, '-', "List 'control commands' For each specified engine"}, {"vv", OPT_VV, '-', "Also display each command's description"}, {"vvv", OPT_VVV, '-', "Also add the input flags for each command"}, {"vvvv", OPT_VVVV, '-', "Also show internal input flags"}, {"c", OPT_C, '-', "List the capabilities of specified engine"}, - {"t", OPT_T, '-', "Check that specified engine is available"}, {"tt", OPT_TT, '-', "Display error trace for unavailable engines"}, - {"pre", OPT_PRE, 's', "Run command against the ENGINE before loading it"}, - {"post", OPT_POST, 's', "Run command against the ENGINE after loading it"}, {OPT_MORE_STR, OPT_EOF, 1, "Commands are like \"SO_PATH:/lib/libdriver.so\""}, + + OPT_PARAMETERS(), + {"engine", 0, 0, "ID of engine(s) to load"}, {NULL} }; @@ -351,7 +360,7 @@ int engine_main(int argc, char **argv) } } - /* Allow any trailing parameters as engine names. */ + /* Any remaining arguments are engine names. */ argc = opt_num_rest(); argv = opt_rest(); for ( ; *argv; argv++) { diff --git a/apps/errstr.c b/apps/errstr.c index 3ef01f076a8c..782705a78a33 100644 --- a/apps/errstr.c +++ b/apps/errstr.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -22,8 +22,12 @@ typedef enum OPTION_choice { const OPTIONS errstr_options[] = { {OPT_HELP_STR, 1, '-', "Usage: %s [options] errnum...\n"}, - {OPT_HELP_STR, 1, '-', " errnum Error number\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_PARAMETERS(), + {"errnum", 0, 0, "Error number(s) to decode"}, {NULL} }; @@ -48,16 +52,19 @@ int errstr_main(int argc, char **argv) } } + /* + * We're not really an SSL application so this won't auto-init, but + * we're still interested in SSL error strings + */ + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + + /* All remaining arg are error code. */ ret = 0; - for (argv = opt_rest(); *argv; argv++) { + for (argv = opt_rest(); *argv != NULL; argv++) { if (sscanf(*argv, "%lx", &l) == 0) { ret++; } else { - /* We're not really an SSL application so this won't auto-init, but - * we're still interested in SSL error strings - */ - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); ERR_error_string_n(l, buf, sizeof(buf)); BIO_printf(bio_out, "%s\n", buf); } diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c new file mode 100644 index 000000000000..d0efdf7643bd --- /dev/null +++ b/apps/fipsinstall.c @@ -0,0 +1,590 @@ +/* + * Copyright 2019-2021 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 <string.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/provider.h> +#include <openssl/params.h> +#include <openssl/fips_names.h> +#include <openssl/core_names.h> +#include <openssl/self_test.h> +#include <openssl/fipskey.h> +#include "apps.h" +#include "progs.h" + +#define BUFSIZE 4096 + +/* Configuration file values */ +#define VERSION_KEY "version" +#define VERSION_VAL "1" +#define INSTALL_STATUS_VAL "INSTALL_SELF_TEST_KATS_RUN" + +static OSSL_CALLBACK self_test_events; +static char *self_test_corrupt_desc = NULL; +static char *self_test_corrupt_type = NULL; +static int self_test_log = 1; +static int quiet = 0; + +typedef enum OPTION_choice { + OPT_COMMON, + OPT_IN, OPT_OUT, OPT_MODULE, + OPT_PROV_NAME, OPT_SECTION_NAME, OPT_MAC_NAME, OPT_MACOPT, OPT_VERIFY, + OPT_NO_LOG, OPT_CORRUPT_DESC, OPT_CORRUPT_TYPE, OPT_QUIET, OPT_CONFIG, + OPT_NO_CONDITIONAL_ERRORS, + OPT_NO_SECURITY_CHECKS, + OPT_SELF_TEST_ONLOAD +} OPTION_CHOICE; + +const OPTIONS fipsinstall_options[] = { + OPT_SECTION("General"), + {"help", OPT_HELP, '-', "Display this summary"}, + {"verify", OPT_VERIFY, '-', + "Verify a config file instead of generating one"}, + {"module", OPT_MODULE, '<', "File name of the provider module"}, + {"provider_name", OPT_PROV_NAME, 's', "FIPS provider name"}, + {"section_name", OPT_SECTION_NAME, 's', + "FIPS Provider config section name (optional)"}, + {"no_conditional_errors", OPT_NO_CONDITIONAL_ERRORS, '-', + "Disable the ability of the fips module to enter an error state if" + " any conditional self tests fail"}, + {"no_security_checks", OPT_NO_SECURITY_CHECKS, '-', + "Disable the run-time FIPS security checks in the module"}, + {"self_test_onload", OPT_SELF_TEST_ONLOAD, '-', + "Forces self tests to always run on module load"}, + OPT_SECTION("Input"), + {"in", OPT_IN, '<', "Input config file, used when verifying"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output config file, used when generating"}, + {"mac_name", OPT_MAC_NAME, 's', "MAC name"}, + {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form. " + "See 'PARAMETER NAMES' in the EVP_MAC_ docs"}, + {"noout", OPT_NO_LOG, '-', "Disable logging of self test events"}, + {"corrupt_desc", OPT_CORRUPT_DESC, 's', "Corrupt a self test by description"}, + {"corrupt_type", OPT_CORRUPT_TYPE, 's', "Corrupt a self test by type"}, + {"config", OPT_CONFIG, '<', "The parent config to verify"}, + {"quiet", OPT_QUIET, '-', "No messages, just exit status"}, + {NULL} +}; + +static int do_mac(EVP_MAC_CTX *ctx, unsigned char *tmp, BIO *in, + unsigned char *out, size_t *out_len) +{ + int ret = 0; + int i; + size_t outsz = *out_len; + + if (!EVP_MAC_init(ctx, NULL, 0, NULL)) + goto err; + if (EVP_MAC_CTX_get_mac_size(ctx) > outsz) + goto end; + while ((i = BIO_read(in, (char *)tmp, BUFSIZE)) != 0) { + if (i < 0 || !EVP_MAC_update(ctx, tmp, i)) + goto err; + } +end: + if (!EVP_MAC_final(ctx, out, out_len, outsz)) + goto err; + ret = 1; +err: + return ret; +} + +static int load_fips_prov_and_run_self_test(const char *prov_name) +{ + int ret = 0; + OSSL_PROVIDER *prov = NULL; + + prov = OSSL_PROVIDER_load(NULL, prov_name); + if (prov == NULL) { + BIO_printf(bio_err, "Failed to load FIPS module\n"); + goto end; + } + ret = 1; +end: + OSSL_PROVIDER_unload(prov); + return ret; +} + +static int print_mac(BIO *bio, const char *label, const unsigned char *mac, + size_t len) +{ + int ret; + char *hexstr = NULL; + + hexstr = OPENSSL_buf2hexstr(mac, (long)len); + if (hexstr == NULL) + return 0; + ret = BIO_printf(bio, "%s = %s\n", label, hexstr); + OPENSSL_free(hexstr); + return ret; +} + +static int write_config_header(BIO *out, const char *prov_name, + const char *section) +{ + return BIO_printf(out, "openssl_conf = openssl_init\n\n") + && BIO_printf(out, "[openssl_init]\n") + && BIO_printf(out, "providers = provider_section\n\n") + && BIO_printf(out, "[provider_section]\n") + && BIO_printf(out, "%s = %s\n\n", prov_name, section); +} + +/* + * Outputs a fips related config file that contains entries for the fips + * module checksum, installation indicator checksum and the options + * conditional_errors and security_checks. + * + * Returns 1 if the config file is written otherwise it returns 0 on error. + */ +static int write_config_fips_section(BIO *out, const char *section, + unsigned char *module_mac, + size_t module_mac_len, + int conditional_errors, + int security_checks, + unsigned char *install_mac, + size_t install_mac_len) +{ + int ret = 0; + + if (BIO_printf(out, "[%s]\n", section) <= 0 + || BIO_printf(out, "activate = 1\n") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_VERSION, + VERSION_VAL) <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS, + conditional_errors ? "1" : "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS, + security_checks ? "1" : "0") <= 0 + || !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac, + module_mac_len)) + goto end; + + if (install_mac != NULL && install_mac_len > 0) { + if (!print_mac(out, OSSL_PROV_FIPS_PARAM_INSTALL_MAC, install_mac, + install_mac_len) + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_STATUS, + INSTALL_STATUS_VAL) <= 0) + goto end; + } + ret = 1; +end: + return ret; +} + +static CONF *generate_config_and_load(const char *prov_name, + const char *section, + unsigned char *module_mac, + size_t module_mac_len, + int conditional_errors, + int security_checks) +{ + BIO *mem_bio = NULL; + CONF *conf = NULL; + + mem_bio = BIO_new(BIO_s_mem()); + if (mem_bio == NULL) + return 0; + if (!write_config_header(mem_bio, prov_name, section) + || !write_config_fips_section(mem_bio, section, + module_mac, module_mac_len, + conditional_errors, + security_checks, + NULL, 0)) + goto end; + + conf = app_load_config_bio(mem_bio, NULL); + if (conf == NULL) + goto end; + + if (CONF_modules_load(conf, NULL, 0) <= 0) + goto end; + BIO_free(mem_bio); + return conf; +end: + NCONF_free(conf); + BIO_free(mem_bio); + return NULL; +} + +static void free_config_and_unload(CONF *conf) +{ + if (conf != NULL) { + NCONF_free(conf); + CONF_modules_unload(1); + } +} + +static int verify_module_load(const char *parent_config_file) +{ + return OSSL_LIB_CTX_load_config(NULL, parent_config_file); +} + +/* + * Returns 1 if the config file entries match the passed in module_mac and + * install_mac values, otherwise it returns 0. + */ +static int verify_config(const char *infile, const char *section, + unsigned char *module_mac, size_t module_mac_len, + unsigned char *install_mac, size_t install_mac_len) +{ + int ret = 0; + char *s = NULL; + unsigned char *buf1 = NULL, *buf2 = NULL; + long len; + CONF *conf = NULL; + + /* read in the existing values and check they match the saved values */ + conf = app_load_config(infile); + if (conf == NULL) + goto end; + + s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_VERSION); + if (s == NULL || strcmp(s, VERSION_VAL) != 0) { + BIO_printf(bio_err, "version not found\n"); + goto end; + } + s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_MODULE_MAC); + if (s == NULL) { + BIO_printf(bio_err, "Module integrity MAC not found\n"); + goto end; + } + buf1 = OPENSSL_hexstr2buf(s, &len); + if (buf1 == NULL + || (size_t)len != module_mac_len + || memcmp(module_mac, buf1, module_mac_len) != 0) { + BIO_printf(bio_err, "Module integrity mismatch\n"); + goto end; + } + if (install_mac != NULL && install_mac_len > 0) { + s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_STATUS); + if (s == NULL || strcmp(s, INSTALL_STATUS_VAL) != 0) { + BIO_printf(bio_err, "install status not found\n"); + goto end; + } + s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_MAC); + if (s == NULL) { + BIO_printf(bio_err, "Install indicator MAC not found\n"); + goto end; + } + buf2 = OPENSSL_hexstr2buf(s, &len); + if (buf2 == NULL + || (size_t)len != install_mac_len + || memcmp(install_mac, buf2, install_mac_len) != 0) { + BIO_printf(bio_err, "Install indicator status mismatch\n"); + goto end; + } + } + ret = 1; +end: + OPENSSL_free(buf1); + OPENSSL_free(buf2); + NCONF_free(conf); + return ret; +} + +int fipsinstall_main(int argc, char **argv) +{ + int ret = 1, verify = 0, gotkey = 0, gotdigest = 0, self_test_onload = 0; + int enable_conditional_errors = 1, enable_security_checks = 1; + const char *section_name = "fips_sect"; + const char *mac_name = "HMAC"; + const char *prov_name = "fips"; + BIO *module_bio = NULL, *mem_bio = NULL, *fout = NULL; + char *in_fname = NULL, *out_fname = NULL, *prog; + char *module_fname = NULL, *parent_config = NULL, *module_path = NULL; + const char *tail; + EVP_MAC_CTX *ctx = NULL, *ctx2 = NULL; + STACK_OF(OPENSSL_STRING) *opts = NULL; + OPTION_CHOICE o; + unsigned char *read_buffer = NULL; + unsigned char module_mac[EVP_MAX_MD_SIZE]; + size_t module_mac_len = EVP_MAX_MD_SIZE; + unsigned char install_mac[EVP_MAX_MD_SIZE]; + size_t install_mac_len = EVP_MAX_MD_SIZE; + EVP_MAC *mac = NULL; + CONF *conf = NULL; + + if ((opts = sk_OPENSSL_STRING_new_null()) == NULL) + goto end; + + prog = opt_init(argc, argv, fipsinstall_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 cleanup; + case OPT_HELP: + opt_help(fipsinstall_options); + ret = 0; + goto end; + case OPT_IN: + in_fname = opt_arg(); + break; + case OPT_OUT: + out_fname = opt_arg(); + break; + case OPT_NO_CONDITIONAL_ERRORS: + enable_conditional_errors = 0; + break; + case OPT_NO_SECURITY_CHECKS: + enable_security_checks = 0; + break; + case OPT_QUIET: + quiet = 1; + /* FALLTHROUGH */ + case OPT_NO_LOG: + self_test_log = 0; + break; + case OPT_CORRUPT_DESC: + self_test_corrupt_desc = opt_arg(); + break; + case OPT_CORRUPT_TYPE: + self_test_corrupt_type = opt_arg(); + break; + case OPT_PROV_NAME: + prov_name = opt_arg(); + break; + case OPT_MODULE: + module_fname = opt_arg(); + break; + case OPT_SECTION_NAME: + section_name = opt_arg(); + break; + case OPT_MAC_NAME: + mac_name = opt_arg(); + break; + case OPT_CONFIG: + parent_config = opt_arg(); + break; + case OPT_MACOPT: + if (!sk_OPENSSL_STRING_push(opts, opt_arg())) + goto opthelp; + if (strncmp(opt_arg(), "hexkey:", 7) == 0) + gotkey = 1; + else if (strncmp(opt_arg(), "digest:", 7) == 0) + gotdigest = 1; + break; + case OPT_VERIFY: + verify = 1; + break; + case OPT_SELF_TEST_ONLOAD: + self_test_onload = 1; + break; + } + } + + /* No extra arguments. */ + argc = opt_num_rest(); + if (argc != 0 || (verify && in_fname == NULL)) + goto opthelp; + + if (parent_config != NULL) { + /* Test that a parent config can load the module */ + if (verify_module_load(parent_config)) { + ret = OSSL_PROVIDER_available(NULL, prov_name) ? 0 : 1; + if (!quiet) + BIO_printf(bio_err, "FIPS provider is %s\n", + ret == 0 ? "available" : " not available"); + } + goto end; + } + if (module_fname == NULL) + goto opthelp; + + tail = opt_path_end(module_fname); + if (tail != NULL) { + module_path = OPENSSL_strdup(module_fname); + if (module_path == NULL) + goto end; + module_path[tail - module_fname] = '\0'; + if (!OSSL_PROVIDER_set_default_search_path(NULL, module_path)) + goto end; + } + + if (self_test_log + || self_test_corrupt_desc != NULL + || self_test_corrupt_type != NULL) + OSSL_SELF_TEST_set_callback(NULL, self_test_events, NULL); + + /* Use the default FIPS HMAC digest and key if not specified. */ + if (!gotdigest && !sk_OPENSSL_STRING_push(opts, "digest:SHA256")) + goto end; + if (!gotkey && !sk_OPENSSL_STRING_push(opts, "hexkey:" FIPS_KEY_STRING)) + goto end; + + module_bio = bio_open_default(module_fname, 'r', FORMAT_BINARY); + if (module_bio == NULL) { + BIO_printf(bio_err, "Failed to open module file\n"); + goto end; + } + + read_buffer = app_malloc(BUFSIZE, "I/O buffer"); + if (read_buffer == NULL) + goto end; + + mac = EVP_MAC_fetch(app_get0_libctx(), mac_name, app_get0_propq()); + if (mac == NULL) { + BIO_printf(bio_err, "Unable to get MAC of type %s\n", mac_name); + goto end; + } + + ctx = EVP_MAC_CTX_new(mac); + if (ctx == NULL) { + BIO_printf(bio_err, "Unable to create MAC CTX for module check\n"); + goto end; + } + + if (opts != NULL) { + int ok = 1; + OSSL_PARAM *params = + app_params_new_from_opts(opts, EVP_MAC_settable_ctx_params(mac)); + + if (params == NULL) + goto end; + + if (!EVP_MAC_CTX_set_params(ctx, params)) { + BIO_printf(bio_err, "MAC parameter error\n"); + ERR_print_errors(bio_err); + ok = 0; + } + app_params_free(params); + if (!ok) + goto end; + } + + ctx2 = EVP_MAC_CTX_dup(ctx); + if (ctx2 == NULL) { + BIO_printf(bio_err, "Unable to create MAC CTX for install indicator\n"); + goto end; + } + + if (!do_mac(ctx, read_buffer, module_bio, module_mac, &module_mac_len)) + goto end; + + if (self_test_onload == 0) { + mem_bio = BIO_new_mem_buf((const void *)INSTALL_STATUS_VAL, + strlen(INSTALL_STATUS_VAL)); + if (mem_bio == NULL) { + BIO_printf(bio_err, "Unable to create memory BIO\n"); + goto end; + } + if (!do_mac(ctx2, read_buffer, mem_bio, install_mac, &install_mac_len)) + goto end; + } else { + install_mac_len = 0; + } + + if (verify) { + if (!verify_config(in_fname, section_name, module_mac, module_mac_len, + install_mac, install_mac_len)) + goto end; + if (!quiet) + BIO_printf(bio_err, "VERIFY PASSED\n"); + } else { + + conf = generate_config_and_load(prov_name, section_name, module_mac, + module_mac_len, + enable_conditional_errors, + enable_security_checks); + if (conf == NULL) + goto end; + if (!load_fips_prov_and_run_self_test(prov_name)) + goto end; + + fout = + out_fname == NULL ? dup_bio_out(FORMAT_TEXT) + : bio_open_default(out_fname, 'w', FORMAT_TEXT); + if (fout == NULL) { + BIO_printf(bio_err, "Failed to open file\n"); + goto end; + } + if (!write_config_fips_section(fout, section_name, + module_mac, module_mac_len, + enable_conditional_errors, + enable_security_checks, + install_mac, install_mac_len)) + goto end; + if (!quiet) + BIO_printf(bio_err, "INSTALL PASSED\n"); + } + + ret = 0; +end: + if (ret == 1) { + if (!quiet) + BIO_printf(bio_err, "%s FAILED\n", verify ? "VERIFY" : "INSTALL"); + ERR_print_errors(bio_err); + } + +cleanup: + OPENSSL_free(module_path); + BIO_free(fout); + BIO_free(mem_bio); + BIO_free(module_bio); + sk_OPENSSL_STRING_free(opts); + EVP_MAC_free(mac); + EVP_MAC_CTX_free(ctx2); + EVP_MAC_CTX_free(ctx); + OPENSSL_free(read_buffer); + free_config_and_unload(conf); + return ret; +} + +static int self_test_events(const OSSL_PARAM params[], void *arg) +{ + const OSSL_PARAM *p = NULL; + const char *phase = NULL, *type = NULL, *desc = NULL; + int ret = 0; + + p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_PHASE); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + phase = (const char *)p->data; + + p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_DESC); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + desc = (const char *)p->data; + + p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_TYPE); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + type = (const char *)p->data; + + if (self_test_log) { + if (strcmp(phase, OSSL_SELF_TEST_PHASE_START) == 0) + BIO_printf(bio_err, "%s : (%s) : ", desc, type); + else if (strcmp(phase, OSSL_SELF_TEST_PHASE_PASS) == 0 + || strcmp(phase, OSSL_SELF_TEST_PHASE_FAIL) == 0) + BIO_printf(bio_err, "%s\n", phase); + } + /* + * The self test code will internally corrupt the KAT test result if an + * error is returned during the corrupt phase. + */ + if (strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0 + && (self_test_corrupt_desc != NULL + || self_test_corrupt_type != NULL)) { + if (self_test_corrupt_desc != NULL + && strcmp(self_test_corrupt_desc, desc) != 0) + goto end; + if (self_test_corrupt_type != NULL + && strcmp(self_test_corrupt_type, type) != 0) + goto end; + BIO_printf(bio_err, "%s ", phase); + goto err; + } +end: + ret = 1; +err: + return ret; +} diff --git a/apps/gendsa.c b/apps/gendsa.c index ec57c92a9492..27feb793fed2 100644 --- a/apps/gendsa.c +++ b/apps/gendsa.c @@ -1,13 +1,14 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include <stdio.h> #include <string.h> #include <sys/types.h> @@ -22,22 +23,30 @@ #include <openssl/pem.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_OUT, OPT_PASSOUT, OPT_ENGINE, OPT_CIPHER, - OPT_R_ENUM + OPT_COMMON, + OPT_OUT, OPT_PASSOUT, OPT_ENGINE, OPT_CIPHER, OPT_VERBOSE, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS gendsa_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [args] dsaparam-file\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] dsaparam-file\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Output"), {"out", OPT_OUT, '>', "Output the key to the specified file"}, {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, OPT_R_OPTIONS, + OPT_PROV_OPTIONS, {"", OPT_CIPHER, '-', "Encrypt the output with any supported cipher"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + {"verbose", OPT_VERBOSE, '-', "Verbose output"}, + + OPT_PARAMETERS(), + {"dsaparam-file", 0, 0, "File containing DSA parameters"}, {NULL} }; @@ -45,13 +54,13 @@ int gendsa_main(int argc, char **argv) { ENGINE *e = NULL; BIO *out = NULL, *in = NULL; - DSA *dsa = NULL; - const EVP_CIPHER *enc = NULL; - char *dsaparams = NULL; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_CIPHER *enc = NULL; + char *dsaparams = NULL, *ciphername = NULL; char *outfile = NULL, *passoutarg = NULL, *passout = NULL, *prog; OPTION_CHOICE o; - int ret = 1, private = 0; - const BIGNUM *p = NULL; + int ret = 1, private = 0, verbose = 0, nbits; prog = opt_init(argc, argv, gendsa_options); while ((o = opt_next()) != OPT_EOF) { @@ -78,55 +87,71 @@ int gendsa_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; - case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &enc)) + case OPT_PROV_CASES: + if (!opt_provider(o)) goto end; break; + case OPT_CIPHER: + ciphername = opt_unknown(); + break; + case OPT_VERBOSE: + verbose = 1; + break; } } + + /* One argument, the params file. */ argc = opt_num_rest(); argv = opt_rest(); - private = 1; - if (argc != 1) goto opthelp; - dsaparams = *argv; + dsaparams = argv[0]; - if (!app_passwd(NULL, passoutarg, NULL, &passout)) { - BIO_printf(bio_err, "Error getting password\n"); + if (!app_RAND_load()) goto end; - } - in = bio_open_default(dsaparams, 'r', FORMAT_PEM); - if (in == NULL) - goto end2; + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &enc)) + goto end; + } + private = 1; - if ((dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL)) == NULL) { - BIO_printf(bio_err, "unable to load DSA parameter file\n"); + if (!app_passwd(NULL, passoutarg, NULL, &passout)) { + BIO_printf(bio_err, "Error getting password\n"); goto end; } - BIO_free(in); - in = NULL; + + pkey = load_keyparams(dsaparams, FORMAT_UNDEF, 1, "DSA", "DSA parameters"); out = bio_open_owner(outfile, FORMAT_PEM, private); if (out == NULL) goto end2; - DSA_get0_pqg(dsa, &p, NULL, NULL); - - if (BN_num_bits(p) > OPENSSL_DSA_MAX_MODULUS_BITS) + nbits = EVP_PKEY_get_bits(pkey); + if (nbits > OPENSSL_DSA_MAX_MODULUS_BITS) BIO_printf(bio_err, "Warning: It is not recommended to use more than %d bit for DSA keys.\n" " Your key size is %d! Larger key size may behave not as expected.\n", - OPENSSL_DSA_MAX_MODULUS_BITS, BN_num_bits(p)); + OPENSSL_DSA_MAX_MODULUS_BITS, EVP_PKEY_get_bits(pkey)); - BIO_printf(bio_err, "Generating DSA key, %d bits\n", BN_num_bits(p)); - if (!DSA_generate_key(dsa)) + ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), pkey, app_get0_propq()); + if (ctx == NULL) { + BIO_printf(bio_err, "unable to create PKEY context\n"); goto end; + } + EVP_PKEY_free(pkey); + pkey = NULL; + if (EVP_PKEY_keygen_init(ctx) <= 0) { + BIO_printf(bio_err, "unable to set up for key generation\n"); + goto end; + } + pkey = app_keygen(ctx, "DSA", nbits, verbose); assert(private); - if (!PEM_write_bio_DSAPrivateKey(out, dsa, enc, NULL, 0, NULL, passout)) + if (!PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, passout)) { + BIO_printf(bio_err, "unable to output generated key\n"); goto end; + } ret = 0; end: if (ret != 0) @@ -134,7 +159,9 @@ int gendsa_main(int argc, char **argv) end2: BIO_free(in); BIO_free_all(out); - DSA_free(dsa); + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + EVP_CIPHER_free(enc); release_engine(e); OPENSSL_free(passout); return ret; diff --git a/apps/genpkey.c b/apps/genpkey.c index 3fe87e853c57..d00754eeaca0 100644 --- a/apps/genpkey.c +++ b/apps/genpkey.c @@ -1,7 +1,7 @@ /* - * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,34 +14,44 @@ #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/evp.h> -#ifndef OPENSSL_NO_ENGINE -# include <openssl/engine.h> -#endif -static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e); +static int quiet; + +static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e, + OSSL_LIB_CTX *libctx, const char *propq); static int genpkey_cb(EVP_PKEY_CTX *ctx); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE, - OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER + OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER, + OPT_QUIET, OPT_CONFIG, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS genpkey_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"out", OPT_OUT, '>', "Output file"}, - {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"}, - {"pass", OPT_PASS, 's', "Output file pass phrase source"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif {"paramfile", OPT_PARAMFILE, '<', "Parameters file"}, {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"}, + {"quiet", OPT_QUIET, '-', "Do not output status while generating keys"}, {"pkeyopt", OPT_PKEYOPT, 's', "Set the public key algorithm option as opt:value"}, + OPT_CONFIG_OPTION, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"}, + {"pass", OPT_PASS, 's', "Output file pass phrase source"}, {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"}, {"text", OPT_TEXT, '-', "Print the in text"}, {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + + OPT_PROV_OPTIONS, + /* This is deliberately last. */ {OPT_HELP_STR, 1, 1, "Order of options may be important! See the documentation.\n"}, @@ -50,17 +60,24 @@ const OPTIONS genpkey_options[] = { int genpkey_main(int argc, char **argv) { + CONF *conf = NULL; BIO *in = NULL, *out = NULL; ENGINE *e = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; - char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog; - const EVP_CIPHER *cipher = NULL; + char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p; + const char *ciphername = NULL, *paramfile = NULL, *algname = NULL; + EVP_CIPHER *cipher = NULL; OPTION_CHOICE o; int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0; - int private = 0; + int private = 0, i; + OSSL_LIB_CTX *libctx = app_get0_libctx(); + STACK_OF(OPENSSL_STRING) *keyopt = NULL; prog = opt_init(argc, argv, genpkey_options); + keyopt = sk_OPENSSL_STRING_new_null(); + if (keyopt == NULL) + goto end; while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_EOF: @@ -88,56 +105,70 @@ int genpkey_main(int argc, char **argv) case OPT_PARAMFILE: if (do_param == 1) goto opthelp; - if (!init_keygen_file(&ctx, opt_arg(), e)) - goto end; + paramfile = opt_arg(); break; case OPT_ALGORITHM: - if (!init_gen_str(&ctx, opt_arg(), e, do_param)) - goto end; + algname = opt_arg(); break; case OPT_PKEYOPT: - if (ctx == NULL) { - BIO_printf(bio_err, "%s: No keytype specified.\n", prog); - goto opthelp; - } - if (pkey_ctrl_string(ctx, opt_arg()) <= 0) { - BIO_printf(bio_err, - "%s: Error setting %s parameter:\n", - prog, opt_arg()); - ERR_print_errors(bio_err); + if (!sk_OPENSSL_STRING_push(keyopt, opt_arg())) goto end; - } + break; + case OPT_QUIET: + quiet = 1; break; case OPT_GENPARAM: - if (ctx != NULL) - goto opthelp; do_param = 1; break; case OPT_TEXT: text = 1; break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &cipher) - || do_param == 1) - goto opthelp; - if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE || - EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE || - EVP_CIPHER_mode(cipher) == EVP_CIPH_XTS_MODE || - EVP_CIPHER_mode(cipher) == EVP_CIPH_OCB_MODE) { - BIO_printf(bio_err, "%s: cipher mode not supported\n", prog); + ciphername = opt_unknown(); + break; + case OPT_CONFIG: + conf = app_load_config_modules(opt_arg()); + if (conf == NULL) goto end; - } + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; - private = do_param ? 0 : 1; - + /* Fetch cipher, etc. */ + if (paramfile != NULL) { + if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq())) + goto end; + } + if (algname != NULL) { + if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq())) + goto end; + } if (ctx == NULL) goto opthelp; + for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) { + p = sk_OPENSSL_STRING_value(keyopt, i); + if (pkey_ctrl_string(ctx, p) <= 0) { + BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p); + ERR_print_errors(bio_err); + goto end; + } + } + if (ciphername != NULL) + if (!opt_cipher(ciphername, &cipher) || do_param == 1) + goto opthelp; + + private = do_param ? 0 : 1; + if (!app_passwd(passarg, NULL, &pass, NULL)) { BIO_puts(bio_err, "Error getting password\n"); goto end; @@ -150,19 +181,8 @@ int genpkey_main(int argc, char **argv) EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); EVP_PKEY_CTX_set_app_data(ctx, bio_err); - if (do_param) { - if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { - BIO_puts(bio_err, "Error generating parameters\n"); - ERR_print_errors(bio_err); - goto end; - } - } else { - if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { - BIO_puts(bio_err, "Error generating key\n"); - ERR_print_errors(bio_err); - goto end; - } - } + pkey = do_param ? app_paramgen(ctx, algname) + : app_keygen(ctx, algname, 0, 0 /* not verbose */); if (do_param) { rv = PEM_write_bio_Parameters(out, pkey); @@ -181,7 +201,6 @@ int genpkey_main(int argc, char **argv) if (rv <= 0) { BIO_puts(bio_err, "Error writing key\n"); - ERR_print_errors(bio_err); ret = 1; } @@ -193,22 +212,27 @@ int genpkey_main(int argc, char **argv) if (rv <= 0) { BIO_puts(bio_err, "Error printing key\n"); - ERR_print_errors(bio_err); ret = 1; } } end: + sk_OPENSSL_STRING_free(keyopt); + if (ret != 0) + ERR_print_errors(bio_err); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(ctx); + EVP_CIPHER_free(cipher); BIO_free_all(out); BIO_free(in); release_engine(e); OPENSSL_free(pass); + NCONF_free(conf); return ret; } -static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e) +static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e, + OSSL_LIB_CTX *libctx, const char *propq) { BIO *pbio; EVP_PKEY *pkey = NULL; @@ -219,20 +243,23 @@ static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e) } pbio = BIO_new_file(file, "r"); - if (!pbio) { + if (pbio == NULL) { BIO_printf(bio_err, "Can't open parameter file %s\n", file); return 0; } - pkey = PEM_read_bio_Parameters(pbio, NULL); + pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq); BIO_free(pbio); - if (!pkey) { + if (pkey == NULL) { BIO_printf(bio_err, "Error reading parameter file %s\n", file); return 0; } - ctx = EVP_PKEY_CTX_new(pkey, e); + if (e != NULL) + ctx = EVP_PKEY_CTX_new(pkey, e); + else + ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); if (ctx == NULL) goto err; if (EVP_PKEY_keygen_init(ctx) <= 0) @@ -251,11 +278,10 @@ static int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e) } int init_gen_str(EVP_PKEY_CTX **pctx, - const char *algname, ENGINE *e, int do_param) + const char *algname, ENGINE *e, int do_param, + OSSL_LIB_CTX *libctx, const char *propq) { EVP_PKEY_CTX *ctx = NULL; - const EVP_PKEY_ASN1_METHOD *ameth; - ENGINE *tmpeng = NULL; int pkey_id; if (*pctx) { @@ -263,27 +289,13 @@ int init_gen_str(EVP_PKEY_CTX **pctx, return 0; } - ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); - -#ifndef OPENSSL_NO_ENGINE - if (!ameth && e) - ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); -#endif - - if (!ameth) { - BIO_printf(bio_err, "Algorithm %s not found\n", algname); - return 0; - } - - ERR_clear_error(); + pkey_id = get_legacy_pkey_id(libctx, algname, e); + if (pkey_id != NID_undef) + ctx = EVP_PKEY_CTX_new_id(pkey_id, e); + else + ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq); - EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); -#ifndef OPENSSL_NO_ENGINE - ENGINE_finish(tmpeng); -#endif - ctx = EVP_PKEY_CTX_new_id(pkey_id, e); - - if (!ctx) + if (ctx == NULL) goto err; if (do_param) { if (EVP_PKEY_paramgen_init(ctx) <= 0) @@ -308,16 +320,22 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx) { char c = '*'; BIO *b = EVP_PKEY_CTX_get_app_data(ctx); - int p; - p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); - if (p == 0) + + if (quiet) + return 1; + + switch (EVP_PKEY_CTX_get_keygen_info(ctx, 0)) { + case 0: c = '.'; - if (p == 1) + break; + case 1: c = '+'; - if (p == 2) - c = '*'; - if (p == 3) + break; + case 3: c = '\n'; + break; + } + BIO_write(b, &c, 1); (void)BIO_flush(b); return 1; diff --git a/apps/genrsa.c b/apps/genrsa.c index e34a2f7ab9e8..4436b7fa1745 100644 --- a/apps/genrsa.c +++ b/apps/genrsa.c @@ -1,13 +1,14 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include <stdio.h> #include <string.h> #include <sys/types.h> @@ -26,52 +27,72 @@ #define DEFBITS 2048 #define DEFPRIMES 2 -static int genrsa_cb(int p, int n, BN_GENCB *cb); +static int verbose = 0; + +static int genrsa_cb(EVP_PKEY_CTX *ctx); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_3, OPT_F4, OPT_ENGINE, - OPT_OUT, OPT_PASSOUT, OPT_CIPHER, OPT_PRIMES, - OPT_R_ENUM + OPT_COMMON, +#ifndef OPENSSL_NO_DEPRECATED_3_0 + OPT_3, +#endif + OPT_F4, OPT_ENGINE, + OPT_OUT, OPT_PASSOUT, OPT_CIPHER, OPT_PRIMES, OPT_VERBOSE, + OPT_R_ENUM, OPT_PROV_ENUM, OPT_TRADITIONAL } OPTION_CHOICE; const OPTIONS genrsa_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] numbits\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"3", OPT_3, '-', "Use 3 for the E value"}, - {"F4", OPT_F4, '-', "Use F4 (0x10001) for the E value"}, - {"f4", OPT_F4, '-', "Use F4 (0x10001) for the E value"}, - {"out", OPT_OUT, '>', "Output the key to specified file"}, - OPT_R_OPTIONS, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - {"", OPT_CIPHER, '-', "Encrypt the output with any supported cipher"}, #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif + + OPT_SECTION("Input"), +#ifndef OPENSSL_NO_DEPRECATED_3_0 + {"3", OPT_3, '-', "(deprecated) Use 3 for the E value"}, +#endif + {"F4", OPT_F4, '-', "Use the Fermat number F4 (0x10001) for the E value"}, + {"f4", OPT_F4, '-', "Use the Fermat number F4 (0x10001) for the E value"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output the key to specified file"}, + {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, {"primes", OPT_PRIMES, 'p', "Specify number of primes"}, + {"verbose", OPT_VERBOSE, '-', "Verbose output"}, + {"traditional", OPT_TRADITIONAL, '-', + "Use traditional format for private keys"}, + {"", OPT_CIPHER, '-', "Encrypt the output with any supported cipher"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"numbits", 0, 0, "Size of key in bits"}, {NULL} }; int genrsa_main(int argc, char **argv) { BN_GENCB *cb = BN_GENCB_new(); - PW_CB_DATA cb_data; ENGINE *eng = NULL; BIGNUM *bn = BN_new(); BIO *out = NULL; - const BIGNUM *e; - RSA *rsa = NULL; - const EVP_CIPHER *enc = NULL; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_CIPHER *enc = NULL; int ret = 1, num = DEFBITS, private = 0, primes = DEFPRIMES; unsigned long f4 = RSA_F4; char *outfile = NULL, *passoutarg = NULL, *passout = NULL; - char *prog, *hexe, *dece; + char *prog, *hexe, *dece, *ciphername = NULL; OPTION_CHOICE o; + int traditional = 0; if (bn == NULL || cb == NULL) goto end; - BN_GENCB_set(cb, genrsa_cb, bio_err); - prog = opt_init(argc, argv, genrsa_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { @@ -84,9 +105,11 @@ opthelp: ret = 0; opt_help(genrsa_options); goto end; +#ifndef OPENSSL_NO_DEPRECATED_3_0 case OPT_3: - f4 = 3; + f4 = RSA_3; break; +#endif case OPT_F4: f4 = RSA_F4; break; @@ -100,19 +123,29 @@ opthelp: if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_PASSOUT: passoutarg = opt_arg(); break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &enc)) - goto end; + ciphername = opt_unknown(); break; case OPT_PRIMES: - if (!opt_int(opt_arg(), &primes)) - goto end; + primes = opt_int_arg(); + break; + case OPT_VERBOSE: + verbose = 1; + break; + case OPT_TRADITIONAL: + traditional = 1; break; } } + + /* One optional argument, the bitsize. */ argc = opt_num_rest(); argv = opt_rest(); @@ -129,7 +162,14 @@ opthelp: goto opthelp; } + if (!app_RAND_load()) + goto end; + private = 1; + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &enc)) + goto end; + } if (!app_passwd(NULL, passoutarg, NULL, &passout)) { BIO_printf(bio_err, "Error getting password\n"); goto end; @@ -139,37 +179,65 @@ opthelp: if (out == NULL) goto end; - BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus (%d primes)\n", - num, primes); - rsa = eng ? RSA_new_method(eng) : RSA_new(); - if (rsa == NULL) + if (!init_gen_str(&ctx, "RSA", eng, 0, app_get0_libctx(), + app_get0_propq())) goto end; - if (!BN_set_word(bn, f4) - || !RSA_generate_multi_prime_key(rsa, num, primes, bn, cb)) - goto end; + EVP_PKEY_CTX_set_cb(ctx, genrsa_cb); + EVP_PKEY_CTX_set_app_data(ctx, bio_err); - RSA_get0_key(rsa, NULL, &e, NULL); - hexe = BN_bn2hex(e); - dece = BN_bn2dec(e); - if (hexe && dece) { - BIO_printf(bio_err, "e is %s (0x%s)\n", dece, hexe); + if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, num) <= 0) { + BIO_printf(bio_err, "Error setting RSA length\n"); + goto end; + } + if (!BN_set_word(bn, f4)) { + BIO_printf(bio_err, "Error allocating RSA public exponent\n"); + goto end; + } + if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bn) <= 0) { + BIO_printf(bio_err, "Error setting RSA public exponent\n"); + goto end; } - OPENSSL_free(hexe); - OPENSSL_free(dece); - cb_data.password = passout; - cb_data.prompt_info = outfile; - assert(private); - if (!PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, - (pem_password_cb *)password_callback, - &cb_data)) + if (EVP_PKEY_CTX_set_rsa_keygen_primes(ctx, primes) <= 0) { + BIO_printf(bio_err, "Error setting number of primes\n"); goto end; + } + pkey = app_keygen(ctx, "RSA", num, verbose); + + if (verbose) { + BIGNUM *e = NULL; + + /* Every RSA key has an 'e' */ + EVP_PKEY_get_bn_param(pkey, "e", &e); + if (e == NULL) { + BIO_printf(bio_err, "Error cannot access RSA e\n"); + goto end; + } + hexe = BN_bn2hex(e); + dece = BN_bn2dec(e); + if (hexe && dece) { + BIO_printf(bio_err, "e is %s (0x%s)\n", dece, hexe); + } + OPENSSL_free(hexe); + OPENSSL_free(dece); + BN_free(e); + } + if (traditional) { + if (!PEM_write_bio_PrivateKey_traditional(out, pkey, enc, NULL, 0, + NULL, passout)) + goto end; + } else { + if (!PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, passout)) + goto end; + } ret = 0; end: BN_free(bn); BN_GENCB_free(cb); - RSA_free(rsa); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + EVP_CIPHER_free(enc); BIO_free_all(out); release_engine(eng); OPENSSL_free(passout); @@ -178,9 +246,14 @@ opthelp: return ret; } -static int genrsa_cb(int p, int n, BN_GENCB *cb) +static int genrsa_cb(EVP_PKEY_CTX *ctx) { char c = '*'; + BIO *b = EVP_PKEY_CTX_get_app_data(ctx); + int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + + if (!verbose) + return 1; if (p == 0) c = '.'; @@ -190,7 +263,7 @@ static int genrsa_cb(int p, int n, BN_GENCB *cb) c = '*'; if (p == 3) c = '\n'; - BIO_write(BN_GENCB_get_arg(cb), &c, 1); - (void)BIO_flush(BN_GENCB_get_arg(cb)); + BIO_write(b, &c, 1); + (void)BIO_flush(b); return 1; } diff --git a/apps/include/__DECC_INCLUDE_EPILOGUE.H b/apps/include/__DECC_INCLUDE_EPILOGUE.H new file mode 100644 index 000000000000..2ab493330675 --- /dev/null +++ b/apps/include/__DECC_INCLUDE_EPILOGUE.H @@ -0,0 +1,22 @@ +/* + * Copyright 2016-2021 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 + */ + +/* + * This file is only used by HP C/C++ on VMS, and is included automatically + * after each header file from this directory + */ + +/* + * The C++ compiler doesn't understand these pragmas, even though it + * understands the corresponding command line qualifier. + */ +#ifndef __cplusplus +/* restore state. Must correspond to the save in __decc_include_prologue.h */ +# pragma names restore +#endif diff --git a/apps/include/__DECC_INCLUDE_PROLOGUE.H b/apps/include/__DECC_INCLUDE_PROLOGUE.H new file mode 100644 index 000000000000..8e95fa975488 --- /dev/null +++ b/apps/include/__DECC_INCLUDE_PROLOGUE.H @@ -0,0 +1,26 @@ +/* + * Copyright 2016-2021 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 + */ + +/* + * This file is only used by HP C/C++ on VMS, and is included automatically + * after each header file from this directory + */ + +/* + * The C++ compiler doesn't understand these pragmas, even though it + * understands the corresponding command line qualifier. + */ +#ifndef __cplusplus +/* save state */ +# pragma names save +/* have the compiler shorten symbols larger than 31 chars to 23 chars + * followed by a 8 hex char CRC + */ +# pragma names as_is,shortened +#endif diff --git a/apps/include/app_libctx.h b/apps/include/app_libctx.h new file mode 100644 index 000000000000..17c0afc713d2 --- /dev/null +++ b/apps/include/app_libctx.h @@ -0,0 +1,20 @@ +/* + * Copyright 2021 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 OSSL_APPS_LIBCTX_H +# define OSSL_APPS_LIBCTX_H + +# include <openssl/types.h> + +OSSL_LIB_CTX *app_create_libctx(void); +OSSL_LIB_CTX *app_get0_libctx(void); +int app_set_propq(const char *arg); +const char *app_get0_propq(void); + +#endif diff --git a/apps/include/app_params.h b/apps/include/app_params.h new file mode 100644 index 000000000000..79f8f58b3122 --- /dev/null +++ b/apps/include/app_params.h @@ -0,0 +1,14 @@ +/* + * Copyright 2019-2020 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 <openssl/core.h> + +int print_param_types(const char *thing, const OSSL_PARAM *pdefs, int indent); +void print_param_value(const OSSL_PARAM *p, int indent); + diff --git a/apps/include/apps.h b/apps/include/apps.h new file mode 100644 index 000000000000..baacd0025d68 --- /dev/null +++ b/apps/include/apps.h @@ -0,0 +1,348 @@ +/* + * Copyright 1995-2022 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 OSSL_APPS_H +# define OSSL_APPS_H + +# include "e_os.h" /* struct timeval for DTLS */ +# include "internal/nelem.h" +# include "internal/sockets.h" /* for openssl_fdset() */ +# include "internal/cryptlib.h" /* ossl_assert() */ +# include <assert.h> + +# include <stdarg.h> +# include <sys/types.h> +# ifndef OPENSSL_NO_POSIX_IO +# include <sys/stat.h> +# include <fcntl.h> +# endif + +# include <openssl/e_os2.h> +# include <openssl/types.h> +# include <openssl/bio.h> +# include <openssl/x509.h> +# include <openssl/conf.h> +# include <openssl/txt_db.h> +# include <openssl/engine.h> +# include <openssl/ocsp.h> +# include <openssl/http.h> +# include <signal.h> +# include "apps_ui.h" +# include "opt.h" +# include "fmt.h" +# include "platform.h" +# include "engine_loader.h" +# include "app_libctx.h" + +/* + * quick macro when you need to pass an unsigned char instead of a char. + * this is true for some implementations of the is*() functions, for + * example. + */ +# define _UC(c) ((unsigned char)(c)) + +void app_RAND_load_conf(CONF *c, const char *section); +int app_RAND_write(void); +int app_RAND_load(void); + +extern char *default_config_file; /* may be "" */ +extern BIO *bio_in; +extern BIO *bio_out; +extern BIO *bio_err; +extern const unsigned char tls13_aes128gcmsha256_id[]; +extern const unsigned char tls13_aes256gcmsha384_id[]; +extern BIO_ADDR *ourpeer; + +BIO *dup_bio_in(int format); +BIO *dup_bio_out(int format); +BIO *dup_bio_err(int format); +BIO *bio_open_owner(const char *filename, int format, int private); +BIO *bio_open_default(const char *filename, char mode, int format); +BIO *bio_open_default_quiet(const char *filename, char mode, int format); +CONF *app_load_config_bio(BIO *in, const char *filename); +#define app_load_config(filename) app_load_config_internal(filename, 0) +#define app_load_config_quiet(filename) app_load_config_internal(filename, 1) +CONF *app_load_config_internal(const char *filename, int quiet); +CONF *app_load_config_verbose(const char *filename, int verbose); +int app_load_modules(const CONF *config); +CONF *app_load_config_modules(const char *configfile); +void unbuffer(FILE *fp); +void wait_for_async(SSL *s); +# if defined(OPENSSL_SYS_MSDOS) +int has_stdin_waiting(void); +# endif + +void corrupt_signature(const ASN1_STRING *signature); +int set_cert_times(X509 *x, const char *startdate, const char *enddate, + int days); +int set_crl_lastupdate(X509_CRL *crl, const char *lastupdate); +int set_crl_nextupdate(X509_CRL *crl, const char *nextupdate, + long days, long hours, long secs); + +typedef struct args_st { + int size; + int argc; + char **argv; +} ARGS; + +/* We need both wrap and the "real" function because libcrypto uses both. */ +int wrap_password_callback(char *buf, int bufsiz, int verify, void *cb_data); + +int chopup_args(ARGS *arg, char *buf); +void dump_cert_text(BIO *out, X509 *x); +void print_name(BIO *out, const char *title, const X509_NAME *nm); +void print_bignum_var(BIO *, const BIGNUM *, const char*, + int, unsigned char *); +void print_array(BIO *, const char *, int, const unsigned char *); +int set_nameopt(const char *arg); +unsigned long get_nameopt(void); +int set_dateopt(unsigned long *dateopt, const char *arg); +int set_cert_ex(unsigned long *flags, const char *arg); +int set_name_ex(unsigned long *flags, const char *arg); +int set_ext_copy(int *copy_type, const char *arg); +int copy_extensions(X509 *x, X509_REQ *req, int copy_type); +char *get_passwd(const char *pass, const char *desc); +int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2); +int add_oid_section(CONF *conf); +X509_REQ *load_csr(const char *file, int format, const char *desc); +X509 *load_cert_pass(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc); +#define load_cert(uri, format, desc) load_cert_pass(uri, format, 1, NULL, desc) +X509_CRL *load_crl(const char *uri, int format, int maybe_stdin, + const char *desc); +void cleanse(char *str); +void clear_free(char *str); +EVP_PKEY *load_key(const char *uri, int format, int maybe_stdin, + const char *pass, ENGINE *e, const char *desc); +EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, + const char *pass, ENGINE *e, const char *desc); +EVP_PKEY *load_keyparams(const char *uri, int format, int maybe_stdin, + const char *keytype, const char *desc); +EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin, + const char *keytype, const char *desc, + int suppress_decode_errors); +char *next_item(char *opt); /* in list separated by comma and/or space */ +int load_cert_certs(const char *uri, + X509 **pcert, STACK_OF(X509) **pcerts, + int exclude_http, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm); +STACK_OF(X509) *load_certs_multifile(char *files, const char *pass, + const char *desc, X509_VERIFY_PARAM *vpm); +X509_STORE *load_certstore(char *input, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm); +int load_certs(const char *uri, int maybe_stdin, STACK_OF(X509) **certs, + const char *pass, const char *desc); +int load_crls(const char *uri, STACK_OF(X509_CRL) **crls, + const char *pass, const char *desc); +int load_key_certs_crls(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc, + EVP_PKEY **ppkey, EVP_PKEY **ppubkey, + EVP_PKEY **pparams, + X509 **pcert, STACK_OF(X509) **pcerts, + X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls); +int load_key_cert_crl(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc, + EVP_PKEY **ppkey, EVP_PKEY **ppubkey, + X509 **pcert, X509_CRL **pcrl); +X509_STORE *setup_verify(const char *CAfile, int noCAfile, + const char *CApath, int noCApath, + const char *CAstore, int noCAstore); +__owur int ctx_set_verify_locations(SSL_CTX *ctx, + const char *CAfile, int noCAfile, + const char *CApath, int noCApath, + const char *CAstore, int noCAstore); + +# ifndef OPENSSL_NO_CT + +/* + * Sets the file to load the Certificate Transparency log list from. + * If path is NULL, loads from the default file path. + * Returns 1 on success, 0 otherwise. + */ +__owur int ctx_set_ctlog_list_file(SSL_CTX *ctx, const char *path); + +# endif + +ENGINE *setup_engine_methods(const char *id, unsigned int methods, int debug); +# define setup_engine(e, debug) setup_engine_methods(e, (unsigned int)-1, debug) +void release_engine(ENGINE *e); +int init_engine(ENGINE *e); +int finish_engine(ENGINE *e); +char *make_engine_uri(ENGINE *e, const char *key_id, const char *desc); + +int get_legacy_pkey_id(OSSL_LIB_CTX *libctx, const char *algname, ENGINE *e); +const EVP_MD *get_digest_from_engine(const char *name); +const EVP_CIPHER *get_cipher_from_engine(const char *name); + +# ifndef OPENSSL_NO_OCSP +OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, const char *host, + const char *port, const char *path, + const char *proxy, const char *no_proxy, + int use_ssl, STACK_OF(CONF_VALUE) *headers, + int req_timeout); +# endif + +/* Functions defined in ca.c and also used in ocsp.c */ +int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, + ASN1_GENERALIZEDTIME **pinvtm, const char *str); + +# define DB_type 0 +# define DB_exp_date 1 +# define DB_rev_date 2 +# define DB_serial 3 /* index - unique */ +# define DB_file 4 +# define DB_name 5 /* index - unique when active and not + * disabled */ +# define DB_NUMBER 6 + +# define DB_TYPE_REV 'R' /* Revoked */ +# define DB_TYPE_EXP 'E' /* Expired */ +# define DB_TYPE_VAL 'V' /* Valid ; inserted with: ca ... -valid */ +# define DB_TYPE_SUSP 'S' /* Suspended */ + +typedef struct db_attr_st { + int unique_subject; +} DB_ATTR; +typedef struct ca_db_st { + DB_ATTR attributes; + TXT_DB *db; + char *dbfname; +# ifndef OPENSSL_NO_POSIX_IO + struct stat dbst; +# endif +} CA_DB; + +void app_bail_out(char *fmt, ...); +void *app_malloc(size_t sz, const char *what); + +/* load_serial, save_serial, and rotate_serial are also used for CRL numbers */ +BIGNUM *load_serial(const char *serialfile, int *exists, int create, + ASN1_INTEGER **retai); +int save_serial(const char *serialfile, const char *suffix, + const BIGNUM *serial, ASN1_INTEGER **retai); +int rotate_serial(const char *serialfile, const char *new_suffix, + const char *old_suffix); +int rand_serial(BIGNUM *b, ASN1_INTEGER *ai); + +CA_DB *load_index(const char *dbfile, DB_ATTR *dbattr); +int index_index(CA_DB *db); +int save_index(const char *dbfile, const char *suffix, CA_DB *db); +int rotate_index(const char *dbfile, const char *new_suffix, + const char *old_suffix); +void free_index(CA_DB *db); +# define index_name_cmp_noconst(a, b) \ + index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \ + (const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b)) +int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b); +int parse_yesno(const char *str, int def); + +X509_NAME *parse_name(const char *str, int chtype, int multirdn, + const char *desc); +void policies_print(X509_STORE_CTX *ctx); +int bio_to_mem(unsigned char **out, int maxlen, BIO *in); +int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value); +int x509_ctrl_string(X509 *x, const char *value); +int x509_req_ctrl_string(X509_REQ *x, const char *value); +int init_gen_str(EVP_PKEY_CTX **pctx, + const char *algname, ENGINE *e, int do_param, + OSSL_LIB_CTX *libctx, const char *propq); +int do_X509_sign(X509 *x, EVP_PKEY *pkey, const char *md, + STACK_OF(OPENSSL_STRING) *sigopts, X509V3_CTX *ext_ctx); +int do_X509_verify(X509 *x, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *vfyopts); +int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const char *md, + STACK_OF(OPENSSL_STRING) *sigopts); +int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey, + STACK_OF(OPENSSL_STRING) *vfyopts); +int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const char *md, + STACK_OF(OPENSSL_STRING) *sigopts); + +extern char *psk_key; + + +unsigned char *next_protos_parse(size_t *outlen, const char *in); + +void print_cert_checks(BIO *bio, X509 *x, + const char *checkhost, + const char *checkemail, const char *checkip); + +void store_setup_crl_download(X509_STORE *st); + +typedef struct app_http_tls_info_st { + const char *server; + const char *port; + int use_proxy; + long timeout; + SSL_CTX *ssl_ctx; +} APP_HTTP_TLS_INFO; +BIO *app_http_tls_cb(BIO *hbio, /* APP_HTTP_TLS_INFO */ void *arg, + int connect, int detail); +void APP_HTTP_TLS_INFO_free(APP_HTTP_TLS_INFO *info); +# ifndef OPENSSL_NO_SOCK +ASN1_VALUE *app_http_get_asn1(const char *url, const char *proxy, + const char *no_proxy, SSL_CTX *ssl_ctx, + const STACK_OF(CONF_VALUE) *headers, + long timeout, const char *expected_content_type, + const ASN1_ITEM *it); +ASN1_VALUE *app_http_post_asn1(const char *host, const char *port, + const char *path, const char *proxy, + const char *no_proxy, SSL_CTX *ctx, + const STACK_OF(CONF_VALUE) *headers, + const char *content_type, + ASN1_VALUE *req, const ASN1_ITEM *req_it, + const char *expected_content_type, + long timeout, const ASN1_ITEM *rsp_it); +# endif + +# define EXT_COPY_NONE 0 +# define EXT_COPY_ADD 1 +# define EXT_COPY_ALL 2 + +# define NETSCAPE_CERT_HDR "certificate" + +# define APP_PASS_LEN 1024 + +/* + * IETF RFC 5280 says serial number must be <= 20 bytes. Use 159 bits + * so that the first bit will never be one, so that the DER encoding + * rules won't force a leading octet. + */ +# define SERIAL_RAND_BITS 159 + +int app_isdir(const char *); +int app_access(const char *, int flag); +int fileno_stdin(void); +int fileno_stdout(void); +int raw_read_stdin(void *, int); +int raw_write_stdout(const void *, int); + +# define TM_START 0 +# define TM_STOP 1 +double app_tminterval(int stop, int usertime); + +void make_uppercase(char *string); + +typedef struct verify_options_st { + int depth; + int quiet; + int error; + int return_error; +} VERIFY_CB_ARGS; + +extern VERIFY_CB_ARGS verify_args; + +OSSL_PARAM *app_params_new_from_opts(STACK_OF(OPENSSL_STRING) *opts, + const OSSL_PARAM *paramdefs); +void app_params_free(OSSL_PARAM *params); +int app_provider_load(OSSL_LIB_CTX *libctx, const char *provider_name); +void app_providers_cleanup(void); + +EVP_PKEY *app_keygen(EVP_PKEY_CTX *ctx, const char *alg, int bits, int verbose); +EVP_PKEY *app_paramgen(EVP_PKEY_CTX *ctx, const char *alg); + +#endif diff --git a/apps/include/apps_ui.h b/apps/include/apps_ui.h new file mode 100644 index 000000000000..6875b7c372d9 --- /dev/null +++ b/apps/include/apps_ui.h @@ -0,0 +1,29 @@ +/* + * Copyright 2018-2020 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 OSSL_APPS_UI_H +# define OSSL_APPS_UI_H + + +# define PW_MIN_LENGTH 4 +typedef struct pw_cb_data { + const void *password; + const char *prompt_info; +} PW_CB_DATA; + +int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data); + +int setup_ui_method(void); +void destroy_ui_method(void); +int set_base_ui_method(const UI_METHOD *ui_method); +const UI_METHOD *get_ui_method(void); + +extern BIO *bio_err; + +#endif diff --git a/apps/include/cmp_mock_srv.h b/apps/include/cmp_mock_srv.h new file mode 100644 index 000000000000..6beba1473590 --- /dev/null +++ b/apps/include/cmp_mock_srv.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Siemens AG 2018-2020 + * + * 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 OSSL_APPS_CMP_MOCK_SRV_H +# define OSSL_APPS_CMP_MOCK_SRV_H + +# include <openssl/opensslconf.h> +# ifndef OPENSSL_NO_CMP + +# include <openssl/cmp.h> + +OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, + const char *propq); +void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx); + +int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert); +int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *chain); +int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *caPubs); +int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, + int fail_info, const char *text); +int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val); +int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count); +int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec); + +# endif /* !defined(OPENSSL_NO_CMP) */ +#endif /* !defined(OSSL_APPS_CMP_MOCK_SRV_H) */ diff --git a/apps/include/ec_common.h b/apps/include/ec_common.h new file mode 100644 index 000000000000..f5711657a299 --- /dev/null +++ b/apps/include/ec_common.h @@ -0,0 +1,23 @@ +/* + * Copyright 2020-2021 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 OPENSSL_NO_EC +static const char *point_format_options[] = { + "uncompressed", + "compressed", + "hybrid", + NULL +}; + +static const char *asn1_encoding_options[] = { + "named_curve", + "explicit", + NULL +}; +#endif diff --git a/apps/include/engine_loader.h b/apps/include/engine_loader.h new file mode 100644 index 000000000000..fa80fc96567c --- /dev/null +++ b/apps/include/engine_loader.h @@ -0,0 +1,21 @@ +/* + * Copyright 2018-2022 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_ENGINE_LOADER_H +# define HEADER_ENGINE_LOADER_H + +# include <openssl/store.h> + +/* this is a private URI scheme */ +# define ENGINE_SCHEME "org.openssl.engine" +# define ENGINE_SCHEME_COLON (ENGINE_SCHEME ":") + +int setup_engine_loader(void); +void destroy_engine_loader(void); + +#endif diff --git a/apps/include/fmt.h b/apps/include/fmt.h new file mode 100644 index 000000000000..98dfed7dc0a2 --- /dev/null +++ b/apps/include/fmt.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018-2021 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 + */ + +/* + * Options are shared by apps (see apps.h) and the test system + * (see test/testutil.h'). + * In order to remove the dependency between apps and options, the following + * shared fields have been moved into this file. + */ + +#ifndef OSSL_APPS_FMT_H +#define OSSL_APPS_FMT_H + +/* + * On some platforms, it's important to distinguish between text and binary + * files. On some, there might even be specific file formats for different + * contents. The FORMAT_xxx macros are meant to express an intent with the + * file being read or created. + */ +# define B_FORMAT_TEXT 0x8000 +# define FORMAT_UNDEF 0 +# define FORMAT_TEXT (1 | B_FORMAT_TEXT) /* Generic text */ +# define FORMAT_BINARY 2 /* Generic binary */ +# define FORMAT_BASE64 (3 | B_FORMAT_TEXT) /* Base64 */ +# define FORMAT_ASN1 4 /* ASN.1/DER */ +# define FORMAT_PEM (5 | B_FORMAT_TEXT) +# define FORMAT_PKCS12 6 +# define FORMAT_SMIME (7 | B_FORMAT_TEXT) +# define FORMAT_ENGINE 8 /* Not really a file format */ +# define FORMAT_PEMRSA (9 | B_FORMAT_TEXT) /* PEM RSAPublicKey format */ +# define FORMAT_ASN1RSA 10 /* DER RSAPublicKey format */ +# define FORMAT_MSBLOB 11 /* MS Key blob format */ +# define FORMAT_PVK 12 /* MS PVK file format */ +# define FORMAT_HTTP 13 /* Download using HTTP */ +# define FORMAT_NSS 14 /* NSS keylog format */ + +int FMT_istext(int format); + +#endif /* OSSL_APPS_FMT_H_ */ diff --git a/apps/include/function.h b/apps/include/function.h new file mode 100644 index 000000000000..14e8dd388670 --- /dev/null +++ b/apps/include/function.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2020 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 OSSL_APPS_FUNCTION_H +# define OSSL_APPS_FUNCTION_H + +# include <openssl/lhash.h> +# include "opt.h" + +#define DEPRECATED_NO_ALTERNATIVE "unknown" + +typedef enum FUNC_TYPE { + FT_none, FT_general, FT_md, FT_cipher, FT_pkey, + FT_md_alg, FT_cipher_alg +} FUNC_TYPE; + +typedef struct function_st { + FUNC_TYPE type; + const char *name; + int (*func)(int argc, char *argv[]); + const OPTIONS *help; + const char *deprecated_alternative; + const char *deprecated_version; +} FUNCTION; + +DEFINE_LHASH_OF(FUNCTION); + +/* Structure to hold the number of columns to be displayed and the + * field width used to display them. + */ +typedef struct { + int columns; + int width; +} DISPLAY_COLUMNS; + +void calculate_columns(FUNCTION *functions, DISPLAY_COLUMNS *dc); + +#endif diff --git a/apps/include/http_server.h b/apps/include/http_server.h new file mode 100644 index 000000000000..8c339660a65e --- /dev/null +++ b/apps/include/http_server.h @@ -0,0 +1,125 @@ +/* + * Copyright 1995-2021 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 OSSL_HTTP_SERVER_H +# define OSSL_HTTP_SERVER_H + +# include "apps.h" + +# ifndef HAVE_FORK +# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS) +# define HAVE_FORK 0 +# else +# define HAVE_FORK 1 +# endif +# endif + +# if HAVE_FORK +# undef NO_FORK +# else +# define NO_FORK +# endif + +# if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \ + && !defined(OPENSSL_NO_POSIX_IO) +# define HTTP_DAEMON +# include <sys/types.h> +# include <sys/wait.h> +# include <syslog.h> +# include <signal.h> +# define MAXERRLEN 1000 /* limit error text sent to syslog to 1000 bytes */ +# else +# undef LOG_DEBUG +# undef LOG_INFO +# undef LOG_WARNING +# undef LOG_ERR +# define LOG_DEBUG 7 +# define LOG_INFO 6 +# define LOG_WARNING 4 +# define LOG_ERR 3 +# endif + +/*- + * Log a message to syslog if multi-threaded HTTP_DAEMON, else to bio_err + * prog: the name of the current app + * level: the severity of the message, e.g., LOG_ERR + * fmt: message with potential extra parameters like with printf() + * returns nothing + */ +void log_message(const char *prog, int level, const char *fmt, ...); + +# ifndef OPENSSL_NO_SOCK +/*- + * Initialize an HTTP server by setting up its listening BIO + * prog: the name of the current app + * port: the port to listen on + * returns a BIO for accepting requests, NULL on error + */ +BIO *http_server_init_bio(const char *prog, const char *port); + +/*- + * Accept an ASN.1-formatted HTTP request + * it: the expected request ASN.1 type + * preq: pointer to variable where to place the parsed request + * ppath: pointer to variable where to place the request path, or NULL + * pcbio: pointer to variable where to place the BIO for sending the response to + * acbio: the listening bio (typically as returned by http_server_init_bio()) + * found_keep_alive: for returning flag if client requests persistent connection + * prog: the name of the current app, for diagnostics only + * port: the local port listening to, for diagnostics only + * accept_get: whether to accept GET requests (in addition to POST requests) + * timeout: connection timeout (in seconds), or 0 for none/infinite + * returns 0 in case caller should retry, then *preq == *ppath == *pcbio == NULL + * returns -1 on fatal error; also then holds *preq == *ppath == *pcbio == NULL + * returns 1 otherwise. In this case it is guaranteed that *pcbio != NULL while + * *ppath == NULL and *preq == NULL if and only if the request is invalid, + * On return value 1 the caller is responsible for sending an HTTP response, + * using http_server_send_asn1_resp() or http_server_send_status(). + * The caller must free any non-NULL *preq, *ppath, and *pcbio pointers. + */ +int http_server_get_asn1_req(const ASN1_ITEM *it, ASN1_VALUE **preq, + char **ppath, BIO **pcbio, BIO *acbio, + int *found_keep_alive, + const char *prog, const char *port, + int accept_get, int timeout); + +/*- + * Send an ASN.1-formatted HTTP response + * cbio: destination BIO (typically as returned by http_server_get_asn1_req()) + * note: cbio should not do an encoding that changes the output length + * keep_alive: grant persistent connnection + * content_type: string identifying the type of the response + * it: the response ASN.1 type + * resp: the response to send + * returns 1 on success, 0 on failure + */ +int http_server_send_asn1_resp(BIO *cbio, int keep_alive, + const char *content_type, + const ASN1_ITEM *it, const ASN1_VALUE *resp); + +/*- + * Send a trivial HTTP response, typically to report an error or OK + * cbio: destination BIO (typically as returned by http_server_get_asn1_req()) + * status: the status code to send + * reason: the corresponding human-readable string + * returns 1 on success, 0 on failure + */ +int http_server_send_status(BIO *cbio, int status, const char *reason); + +# endif + +# ifdef HTTP_DAEMON +extern int multi; +extern int acfd; + +void socket_timeout(int signum); +void spawn_loop(const char *prog); +# endif + +#endif diff --git a/apps/include/names.h b/apps/include/names.h new file mode 100644 index 000000000000..f4d6f6a9a333 --- /dev/null +++ b/apps/include/names.h @@ -0,0 +1,17 @@ +/* + * 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 <openssl/safestack.h> + +/* Standard comparing function for names */ +int name_cmp(const char * const *a, const char * const *b); +/* collect_names is meant to be used with EVP_{type}_doall_names */ +void collect_names(const char *name, void *vdata); +/* Sorts and prints a stack of names to |out| */ +void print_names(BIO *out, STACK_OF(OPENSSL_CSTRING) *names); diff --git a/apps/apps.h b/apps/include/opt.h index 3e8f50fda87b..4f83a0ed53c9 100644 --- a/apps/apps.h +++ b/apps/include/opt.h @@ -1,92 +1,20 @@ /* - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 OSSL_APPS_OPT_H +#define OSSL_APPS_OPT_H -#ifndef OSSL_APPS_H -# define OSSL_APPS_H - -# include "e_os.h" /* struct timeval for DTLS */ -# include "internal/nelem.h" -# include <assert.h> - -# include <sys/types.h> -# ifndef OPENSSL_NO_POSIX_IO -# include <sys/stat.h> -# include <fcntl.h> -# endif - -# include <openssl/e_os2.h> -# include <openssl/ossl_typ.h> -# include <openssl/bio.h> -# include <openssl/x509.h> -# include <openssl/conf.h> -# include <openssl/txt_db.h> -# include <openssl/engine.h> -# include <openssl/ocsp.h> -# include <signal.h> - -# if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINCE) -# define openssl_fdset(a,b) FD_SET((unsigned int)a, b) -# else -# define openssl_fdset(a,b) FD_SET(a, b) -# endif +#include <sys/types.h> +#include <openssl/e_os2.h> +#include <openssl/types.h> +#include <stdarg.h> -/* - * quick macro when you need to pass an unsigned char instead of a char. - * this is true for some implementations of the is*() functions, for - * example. - */ -#define _UC(c) ((unsigned char)(c)) - -void app_RAND_load_conf(CONF *c, const char *section); -void app_RAND_write(void); - -extern char *default_config_file; -extern BIO *bio_in; -extern BIO *bio_out; -extern BIO *bio_err; -extern const unsigned char tls13_aes128gcmsha256_id[]; -extern const unsigned char tls13_aes256gcmsha384_id[]; -extern BIO_ADDR *ourpeer; - -BIO_METHOD *apps_bf_prefix(void); -/* - * The control used to set the prefix with BIO_ctrl() - * We make it high enough so the chance of ever clashing with the BIO library - * remains unlikely for the foreseeable future and beyond. - */ -#define PREFIX_CTRL_SET_PREFIX (1 << 15) -/* - * apps_bf_prefix() returns a dynamically created BIO_METHOD, which we - * need to destroy at some point. When created internally, it's stored - * in an internal pointer which can be freed with the following function - */ -void destroy_prefix_method(void); - -BIO *dup_bio_in(int format); -BIO *dup_bio_out(int format); -BIO *dup_bio_err(int format); -BIO *bio_open_owner(const char *filename, int format, int private); -BIO *bio_open_default(const char *filename, char mode, int format); -BIO *bio_open_default_quiet(const char *filename, char mode, int format); -CONF *app_load_config_bio(BIO *in, const char *filename); -CONF *app_load_config(const char *filename); -CONF *app_load_config_quiet(const char *filename); -int app_load_modules(const CONF *config); -void unbuffer(FILE *fp); -void wait_for_async(SSL *s); -# if defined(OPENSSL_SYS_MSDOS) -int has_stdin_waiting(void); -# endif - -void corrupt_signature(const ASN1_STRING *signature); -int set_cert_times(X509 *x, const char *startdate, const char *enddate, - int days); +#define OPT_COMMON OPT_ERR = -1, OPT_EOF = 0, OPT_HELP /* * Common verification options. @@ -106,6 +34,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, OPT_V__LAST # define OPT_V_OPTIONS \ + OPT_SECTION("Validation"), \ { "policy", OPT_V_POLICY, 's', "adds policy to the acceptable policy set"}, \ { "purpose", OPT_V_PURPOSE, 's', \ "certificate chain purpose"}, \ @@ -198,15 +127,16 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, OPT_X__LAST # define OPT_X_OPTIONS \ + OPT_SECTION("Extended certificate"), \ { "xkey", OPT_X_KEY, '<', "key for Extended certificates"}, \ { "xcert", OPT_X_CERT, '<', "cert for Extended certificates"}, \ { "xchain", OPT_X_CHAIN, '<', "chain for Extended certificates"}, \ { "xchain_build", OPT_X_CHAIN_BUILD, '-', \ "build certificate chain for the extended certificates"}, \ { "xcertform", OPT_X_CERTFORM, 'F', \ - "format of Extended certificate (PEM or DER) PEM default " }, \ + "format of Extended certificate (PEM/DER/P12); has no effect" }, \ { "xkeyform", OPT_X_KEYFORM, 'F', \ - "format of Extended certificate's key (PEM or DER) PEM default"} + "format of Extended certificate's key (DER/PEM/P12); has no effect"} # define OPT_X_CASES \ OPT_X__FIRST: case OPT_X__LAST: break; \ @@ -225,16 +155,18 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, OPT_S__FIRST=3000, \ OPT_S_NOSSL3, OPT_S_NOTLS1, OPT_S_NOTLS1_1, OPT_S_NOTLS1_2, \ OPT_S_NOTLS1_3, OPT_S_BUGS, OPT_S_NO_COMP, OPT_S_NOTICKET, \ - OPT_S_SERVERPREF, OPT_S_LEGACYRENEG, OPT_S_LEGACYCONN, \ + OPT_S_SERVERPREF, OPT_S_LEGACYRENEG, OPT_S_CLIENTRENEG, \ + OPT_S_LEGACYCONN, \ OPT_S_ONRESUMP, OPT_S_NOLEGACYCONN, OPT_S_ALLOW_NO_DHE_KEX, \ OPT_S_PRIORITIZE_CHACHA, \ OPT_S_STRICT, OPT_S_SIGALGS, OPT_S_CLIENTSIGALGS, OPT_S_GROUPS, \ OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, OPT_S_CIPHERSUITES, \ OPT_S_RECORD_PADDING, OPT_S_DEBUGBROKE, OPT_S_COMP, \ OPT_S_MINPROTO, OPT_S_MAXPROTO, \ - OPT_S_NO_RENEGOTIATION, OPT_S_NO_MIDDLEBOX, OPT_S__LAST + OPT_S_NO_RENEGOTIATION, OPT_S_NO_MIDDLEBOX, OPT_S_NO_ETM, OPT_S__LAST # define OPT_S_OPTIONS \ + OPT_SECTION("TLS/SSL"), \ {"no_ssl3", OPT_S_NOSSL3, '-',"Just disable SSLv3" }, \ {"no_tls1", OPT_S_NOTLS1, '-', "Just disable TLSv1"}, \ {"no_tls1_1", OPT_S_NOTLS1_1, '-', "Just disable TLSv1.1" }, \ @@ -248,6 +180,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, {"serverpref", OPT_S_SERVERPREF, '-', "Use server's cipher preferences"}, \ {"legacy_renegotiation", OPT_S_LEGACYRENEG, '-', \ "Enable use of legacy renegotiation (dangerous)"}, \ + {"client_renegotiation", OPT_S_CLIENTRENEG, '-', \ + "Allow client-initiated renegotiation" }, \ {"no_renegotiation", OPT_S_NO_RENEGOTIATION, '-', \ "Disable all renegotiation."}, \ {"legacy_server_connect", OPT_S_LEGACYCONN, '-', \ @@ -282,7 +216,9 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, {"debug_broken_protocol", OPT_S_DEBUGBROKE, '-', \ "Perform all sorts of protocol violations for testing purposes"}, \ {"no_middlebox", OPT_S_NO_MIDDLEBOX, '-', \ - "Disable TLSv1.3 middlebox compat mode" } + "Disable TLSv1.3 middlebox compat mode" }, \ + {"no_etm", OPT_S_NO_ETM, '-', \ + "Disable Encrypt-then-Mac extension"} # define OPT_S_CASES \ OPT_S__FIRST: case OPT_S__LAST: break; \ @@ -297,6 +233,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, case OPT_S_NOTICKET: \ case OPT_S_SERVERPREF: \ case OPT_S_LEGACYRENEG: \ + case OPT_S_CLIENTRENEG: \ case OPT_S_LEGACYCONN: \ case OPT_S_ONRESUMP: \ case OPT_S_NOLEGACYCONN: \ @@ -315,7 +252,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, case OPT_S_MINPROTO: \ case OPT_S_MAXPROTO: \ case OPT_S_DEBUGBROKE: \ - case OPT_S_NO_MIDDLEBOX + case OPT_S_NO_MIDDLEBOX: \ + case OPT_S_NO_ETM #define IS_NO_PROT_FLAG(o) \ (o == OPT_S_NOSSL3 || o == OPT_S_NOTLS1 || o == OPT_S_NOTLS1_1 \ @@ -328,7 +266,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, OPT_R__FIRST=1500, OPT_R_RAND, OPT_R_WRITERAND, OPT_R__LAST # define OPT_R_OPTIONS \ - {"rand", OPT_R_RAND, 's', "Load the file(s) into the random number generator"}, \ + OPT_SECTION("Random state"), \ + {"rand", OPT_R_RAND, 's', "Load the given file(s) into the random number generator"}, \ {"writerand", OPT_R_WRITERAND, '>', "Write random data to the specified file"} # define OPT_R_CASES \ @@ -336,10 +275,36 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, case OPT_R_RAND: case OPT_R_WRITERAND /* + * Provider options. + */ +# define OPT_PROV_ENUM \ + OPT_PROV__FIRST=1600, \ + OPT_PROV_PROVIDER, OPT_PROV_PROVIDER_PATH, OPT_PROV_PROPQUERY, \ + OPT_PROV__LAST + +# define OPT_CONFIG_OPTION \ + { "config", OPT_CONFIG, '<', "Load a configuration file (this may load modules)" } + +# define OPT_PROV_OPTIONS \ + OPT_SECTION("Provider"), \ + { "provider-path", OPT_PROV_PROVIDER_PATH, 's', "Provider load path (must be before 'provider' argument if required)" }, \ + { "provider", OPT_PROV_PROVIDER, 's', "Provider to load (can be specified multiple times)" }, \ + { "propquery", OPT_PROV_PROPQUERY, 's', "Property query used when fetching algorithms" } + +# define OPT_PROV_CASES \ + OPT_PROV__FIRST: case OPT_PROV__LAST: break; \ + case OPT_PROV_PROVIDER: \ + case OPT_PROV_PROVIDER_PATH: \ + case OPT_PROV_PROPQUERY + +/* * Option parsing. */ extern const char OPT_HELP_STR[]; extern const char OPT_MORE_STR[]; +extern const char OPT_SECTION_STR[]; +extern const char OPT_PARAM_STR[]; + typedef struct options_st { const char *name; int retval; @@ -352,6 +317,9 @@ typedef struct options_st { int valtype; const char *helpstr; } OPTIONS; +/* Special retval values: */ +#define OPT_PARAM 0 /* same as OPT_EOF usually defined in apps */ +#define OPT_DUP -2 /* marks duplicate occurrence of option in help output */ /* * A string/int pairing; widely use for option value lookup, hence the @@ -381,255 +349,52 @@ typedef struct string_int_pair_st { OPT_FMT_ENGINE | OPT_FMT_MSBLOB | OPT_FMT_NSS | \ OPT_FMT_TEXT | OPT_FMT_HTTP | OPT_FMT_PVK) +/* Divide options into sections when displaying usage */ +#define OPT_SECTION(sec) { OPT_SECTION_STR, 1, '-', sec " options:\n" } +#define OPT_PARAMETERS() { OPT_PARAM_STR, 1, '-', "Parameters:\n" } + +const char *opt_path_end(const char *filename); +char *opt_init(int ac, char **av, const OPTIONS * o); char *opt_progname(const char *argv0); +char *opt_appname(const char *argv0); char *opt_getprog(void); -char *opt_init(int ac, char **av, const OPTIONS * o); +void opt_help(const OPTIONS * list); + +void opt_begin(void); int opt_next(void); -int opt_format(const char *s, unsigned long flags, int *result); -int opt_int(const char *arg, int *result); -int opt_ulong(const char *arg, unsigned long *result); -int opt_long(const char *arg, long *result); -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ - defined(INTMAX_MAX) && defined(UINTMAX_MAX) -int opt_imax(const char *arg, intmax_t *result); -int opt_umax(const char *arg, uintmax_t *result); -#else -# define opt_imax opt_long -# define opt_umax opt_ulong -# define intmax_t long -# define uintmax_t unsigned long -#endif -int opt_pair(const char *arg, const OPT_PAIR * pairs, int *result); -int opt_cipher(const char *name, const EVP_CIPHER **cipherp); -int opt_md(const char *name, const EVP_MD **mdp); -char *opt_arg(void); char *opt_flag(void); +char *opt_arg(void); char *opt_unknown(void); -char **opt_rest(void); -int opt_num_rest(void); -int opt_verify(int i, X509_VERIFY_PARAM *vpm); -int opt_rand(int i); -void opt_help(const OPTIONS * list); -int opt_format_error(const char *s, unsigned long flags); +int opt_cipher(const char *name, EVP_CIPHER **cipherp); +int opt_cipher_any(const char *name, EVP_CIPHER **cipherp); +int opt_cipher_silent(const char *name, EVP_CIPHER **cipherp); +int opt_md(const char *name, EVP_MD **mdp); +int opt_md_silent(const char *name, EVP_MD **mdp); -typedef struct args_st { - int size; - int argc; - char **argv; -} ARGS; - -/* - * VMS C only for now, implemented in vms_decc_init.c - * If other C compilers forget to terminate argv with NULL, this function - * can be re-used. - */ -char **copy_argv(int *argc, char *argv[]); -/* - * Win32-specific argv initialization that splits OS-supplied UNICODE - * command line string to array of UTF8-encoded strings. - */ -void win32_utf8argv(int *argc, char **argv[]); - - -# define PW_MIN_LENGTH 4 -typedef struct pw_cb_data { - const void *password; - const char *prompt_info; -} PW_CB_DATA; - -int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data); - -int setup_ui_method(void); -void destroy_ui_method(void); -const UI_METHOD *get_ui_method(void); - -int chopup_args(ARGS *arg, char *buf); -int dump_cert_text(BIO *out, X509 *x); -void print_name(BIO *out, const char *title, X509_NAME *nm, - unsigned long lflags); -void print_bignum_var(BIO *, const BIGNUM *, const char*, - int, unsigned char *); -void print_array(BIO *, const char *, int, const unsigned char *); -int set_nameopt(const char *arg); -unsigned long get_nameopt(void); -int set_cert_ex(unsigned long *flags, const char *arg); -int set_name_ex(unsigned long *flags, const char *arg); -int set_ext_copy(int *copy_type, const char *arg); -int copy_extensions(X509 *x, X509_REQ *req, int copy_type); -int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2); -int add_oid_section(CONF *conf); -X509 *load_cert(const char *file, int format, const char *cert_descrip); -X509_CRL *load_crl(const char *infile, int format); -EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip); -EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip); -int load_certs(const char *file, STACK_OF(X509) **certs, int format, - const char *pass, const char *cert_descrip); -int load_crls(const char *file, STACK_OF(X509_CRL) **crls, int format, - const char *pass, const char *cert_descrip); -X509_STORE *setup_verify(const char *CAfile, const char *CApath, - int noCAfile, int noCApath); -__owur int ctx_set_verify_locations(SSL_CTX *ctx, const char *CAfile, - const char *CApath, int noCAfile, - int noCApath); - -#ifndef OPENSSL_NO_CT - -/* - * Sets the file to load the Certificate Transparency log list from. - * If path is NULL, loads from the default file path. - * Returns 1 on success, 0 otherwise. - */ -__owur int ctx_set_ctlog_list_file(SSL_CTX *ctx, const char *path); - -#endif - -ENGINE *setup_engine(const char *engine, int debug); -void release_engine(ENGINE *e); - -# ifndef OPENSSL_NO_OCSP -OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, - const char *host, const char *path, - const char *port, int use_ssl, - STACK_OF(CONF_VALUE) *headers, - int req_timeout); -# endif - -/* Functions defined in ca.c and also used in ocsp.c */ -int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, - ASN1_GENERALIZEDTIME **pinvtm, const char *str); - -# define DB_type 0 -# define DB_exp_date 1 -# define DB_rev_date 2 -# define DB_serial 3 /* index - unique */ -# define DB_file 4 -# define DB_name 5 /* index - unique when active and not - * disabled */ -# define DB_NUMBER 6 - -# define DB_TYPE_REV 'R' /* Revoked */ -# define DB_TYPE_EXP 'E' /* Expired */ -# define DB_TYPE_VAL 'V' /* Valid ; inserted with: ca ... -valid */ -# define DB_TYPE_SUSP 'S' /* Suspended */ - -typedef struct db_attr_st { - int unique_subject; -} DB_ATTR; -typedef struct ca_db_st { - DB_ATTR attributes; - TXT_DB *db; - char *dbfname; -# ifndef OPENSSL_NO_POSIX_IO - struct stat dbst; -# endif -} CA_DB; - -void* app_malloc(int sz, const char *what); - -/* load_serial, save_serial, and rotate_serial are also used for CRL numbers */ -BIGNUM *load_serial(const char *serialfile, int *exists, int create, - ASN1_INTEGER **retai); -int save_serial(const char *serialfile, const char *suffix, - const BIGNUM *serial, ASN1_INTEGER **retai); -int rotate_serial(const char *serialfile, const char *new_suffix, - const char *old_suffix); -int rand_serial(BIGNUM *b, ASN1_INTEGER *ai); -CA_DB *load_index(const char *dbfile, DB_ATTR *dbattr); -int index_index(CA_DB *db); -int save_index(const char *dbfile, const char *suffix, CA_DB *db); -int rotate_index(const char *dbfile, const char *new_suffix, - const char *old_suffix); -void free_index(CA_DB *db); -# define index_name_cmp_noconst(a, b) \ - index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \ - (const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b)) -int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b); -int parse_yesno(const char *str, int def); - -X509_NAME *parse_name(const char *str, long chtype, int multirdn); -void policies_print(X509_STORE_CTX *ctx); -int bio_to_mem(unsigned char **out, int maxlen, BIO *in); -int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value); -int init_gen_str(EVP_PKEY_CTX **pctx, - const char *algname, ENGINE *e, int do_param); -int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md, - STACK_OF(OPENSSL_STRING) *sigopts); -int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, - STACK_OF(OPENSSL_STRING) *sigopts); -int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, - STACK_OF(OPENSSL_STRING) *sigopts); - -extern char *psk_key; - - -unsigned char *next_protos_parse(size_t *outlen, const char *in); - -void print_cert_checks(BIO *bio, X509 *x, - const char *checkhost, - const char *checkemail, const char *checkip); - -void store_setup_crl_download(X509_STORE *st); - -/* See OPT_FMT_xxx, above. */ -/* On some platforms, it's important to distinguish between text and binary - * files. On some, there might even be specific file formats for different - * contents. The FORMAT_xxx macros are meant to express an intent with the - * file being read or created. - */ -# define B_FORMAT_TEXT 0x8000 -# define FORMAT_UNDEF 0 -# define FORMAT_TEXT (1 | B_FORMAT_TEXT) /* Generic text */ -# define FORMAT_BINARY 2 /* Generic binary */ -# define FORMAT_BASE64 (3 | B_FORMAT_TEXT) /* Base64 */ -# define FORMAT_ASN1 4 /* ASN.1/DER */ -# define FORMAT_PEM (5 | B_FORMAT_TEXT) -# define FORMAT_PKCS12 6 -# define FORMAT_SMIME (7 | B_FORMAT_TEXT) -# define FORMAT_ENGINE 8 /* Not really a file format */ -# define FORMAT_PEMRSA (9 | B_FORMAT_TEXT) /* PEM RSAPubicKey format */ -# define FORMAT_ASN1RSA 10 /* DER RSAPubicKey format */ -# define FORMAT_MSBLOB 11 /* MS Key blob format */ -# define FORMAT_PVK 12 /* MS PVK file format */ -# define FORMAT_HTTP 13 /* Download using HTTP */ -# define FORMAT_NSS 14 /* NSS keylog format */ - -# define EXT_COPY_NONE 0 -# define EXT_COPY_ADD 1 -# define EXT_COPY_ALL 2 - -# define NETSCAPE_CERT_HDR "certificate" - -# define APP_PASS_LEN 1024 - -/* - * IETF RFC 5280 says serial number must be <= 20 bytes. Use 159 bits - * so that the first bit will never be one, so that the DER encoding - * rules won't force a leading octet. - */ -# define SERIAL_RAND_BITS 159 +int opt_int(const char *arg, int *result); +int opt_int_arg(void); +int opt_long(const char *arg, long *result); +int opt_ulong(const char *arg, unsigned long *result); +int opt_intmax(const char *arg, ossl_intmax_t *result); +int opt_uintmax(const char *arg, ossl_uintmax_t *result); -int app_isdir(const char *); -int app_access(const char *, int flag); -int fileno_stdin(void); -int fileno_stdout(void); -int raw_read_stdin(void *, int); -int raw_write_stdout(const void *, int); +int opt_isdir(const char *name); +int opt_format(const char *s, unsigned long flags, int *result); +void print_format_error(int format, unsigned long flags); +int opt_printf_stderr(const char *fmt, ...); +int opt_string(const char *name, const char **options); +int opt_pair(const char *arg, const OPT_PAIR * pairs, int *result); -# define TM_START 0 -# define TM_STOP 1 -double app_tminterval(int stop, int usertime); +int opt_verify(int i, X509_VERIFY_PARAM *vpm); +int opt_rand(int i); +int opt_provider(int i); +int opt_provider_option_given(void); -void make_uppercase(char *string); +char **opt_rest(void); +int opt_num_rest(void); -typedef struct verify_options_st { - int depth; - int quiet; - int error; - int return_error; -} VERIFY_CB_ARGS; +/* Returns non-zero if legacy paths are still available */ +int opt_legacy_okay(void); -extern VERIFY_CB_ARGS verify_args; -#endif +#endif /* OSSL_APPS_OPT_H */ diff --git a/apps/include/platform.h b/apps/include/platform.h new file mode 100644 index 000000000000..491559df3152 --- /dev/null +++ b/apps/include/platform.h @@ -0,0 +1,32 @@ +/* + * 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 + */ + +#ifndef OSSL_APPS_PLATFORM_H +# define OSSL_APPS_PLATFORM_H + +# include <openssl/e_os2.h> + +# if defined(OPENSSL_SYS_VMS) && defined(__DECC) +/* + * VMS C only for now, implemented in vms_decc_init.c + * If other C compilers forget to terminate argv with NULL, this function + * can be re-used. + */ +char **copy_argv(int *argc, char *argv[]); +# endif + +# ifdef _WIN32 +/* + * Win32-specific argv initialization that splits OS-supplied UNICODE + * command line string to array of UTF8-encoded strings. + */ +void win32_utf8argv(int *argc, char **argv[]); +# endif + +#endif diff --git a/apps/s_apps.h b/apps/include/s_apps.h index f94e659e71e3..d610df40be3f 100644 --- a/apps/s_apps.h +++ b/apps/include/s_apps.h @@ -1,7 +1,7 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -10,11 +10,13 @@ #include <openssl/opensslconf.h> #include <openssl/ssl.h> +#include <openssl/srp.h> #define PORT "4433" #define PROTOCOL "tcp" typedef int (*do_server_cb)(int s, int stype, int prot, unsigned char *context); +int report_server_accept(BIO *out, int asock, int with_address, int with_pid); int do_server(int *accept_sock, const char *host, const char *port, int family, int type, int protocol, do_server_cb cb, unsigned char *context, int naccept, BIO *bio_s_out); @@ -32,9 +34,10 @@ int init_client(int *sock, const char *host, const char *port, const char *bindhost, const char *bindport, int family, int type, int protocol); int should_retry(int i); +void do_ssl_shutdown(SSL *ssl); -long bio_dump_callback(BIO *bio, int cmd, const char *argp, - int argi, long argl, long ret); +long bio_dump_callback(BIO *bio, int cmd, const char *argp, size_t len, + int argi, long argl, int ret, size_t *processed); void apps_ssl_info_callback(const SSL *s, int where, int ret); void msg_cb(int write_p, int version, int content_type, const void *buf, @@ -69,9 +72,37 @@ int config_ctx(SSL_CONF_CTX *cctx, STACK_OF(OPENSSL_STRING) *str, SSL_CTX *ctx); int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, int crl_download); int ssl_load_stores(SSL_CTX *ctx, const char *vfyCApath, - const char *vfyCAfile, const char *chCApath, - const char *chCAfile, STACK_OF(X509_CRL) *crls, + const char *vfyCAfile, const char *vfyCAstore, + const char *chCApath, const char *chCAfile, + const char *chCAstore, STACK_OF(X509_CRL) *crls, int crl_download); void ssl_ctx_security_debug(SSL_CTX *ctx, int verbose); int set_keylog_file(SSL_CTX *ctx, const char *keylog_file); void print_ca_names(BIO *bio, SSL *s); + +#ifndef OPENSSL_NO_SRP +/* The client side SRP context that we pass to all SRP related callbacks */ +typedef struct srp_arg_st { + char *srppassin; + char *srplogin; + int msg; /* copy from c_msg */ + int debug; /* copy from c_debug */ + int amp; /* allow more groups */ + int strength; /* minimal size for N */ +} SRP_ARG; + +int set_up_srp_arg(SSL_CTX *ctx, SRP_ARG *srp_arg, int srp_lateuser, int c_msg, + int c_debug); +void set_up_dummy_srp(SSL_CTX *ctx); + +/* The server side SRP context that we pass to all SRP related callbacks */ +typedef struct srpsrvparm_st { + char *login; + SRP_VBASE *vb; + SRP_user_pwd *user; +} srpsrvparm; + +int set_up_srp_verifier_file(SSL_CTX *ctx, srpsrvparm *srp_callback_parm, + char *srpuserseed, char *srp_verifier_file); +void lookup_srp_user(srpsrvparm *srp_callback_parm, BIO *bio_s_out); +#endif /* OPENSSL_NO_SRP */ diff --git a/apps/include/vms_term_sock.h b/apps/include/vms_term_sock.h new file mode 100644 index 000000000000..eae37b1af931 --- /dev/null +++ b/apps/include/vms_term_sock.h @@ -0,0 +1,31 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016 VMS Software, Inc. 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 OSSL_APPS_VMS_TERM_SOCK_H +# define OSSL_APPS_VMS_TERM_SOCK_H + +/* +** Terminal Socket Function Codes +*/ +# define TERM_SOCK_CREATE 1 +# define TERM_SOCK_DELETE 2 + +/* +** Terminal Socket Status Codes +*/ +# define TERM_SOCK_FAILURE 0 +# define TERM_SOCK_SUCCESS 1 + +/* +** Terminal Socket Prototype +*/ +int TerminalSocket (int FunctionCode, int *ReturnSocket); + +#endif diff --git a/apps/info.c b/apps/info.c new file mode 100644 index 000000000000..c68603652f21 --- /dev/null +++ b/apps/info.c @@ -0,0 +1,104 @@ +/* + * Copyright 2019-2021 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 <openssl/crypto.h> +#include "apps.h" +#include "progs.h" + +typedef enum OPTION_choice { + OPT_COMMON, + OPT_CONFIGDIR, OPT_ENGINESDIR, OPT_MODULESDIR, OPT_DSOEXT, OPT_DIRNAMESEP, + OPT_LISTSEP, OPT_SEEDS, OPT_CPUSETTINGS +} OPTION_CHOICE; + +const OPTIONS info_options[] = { + + OPT_SECTION("General"), + {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_SECTION("Output"), + {"configdir", OPT_CONFIGDIR, '-', "Default configuration file directory"}, + {"enginesdir", OPT_ENGINESDIR, '-', "Default engine module directory"}, + {"modulesdir", OPT_MODULESDIR, '-', + "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"}, + {"seeds", OPT_SEEDS, '-', "Seed sources"}, + {"cpusettings", OPT_CPUSETTINGS, '-', "CPU settings info"}, + {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) { + default: +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; + case OPT_SEEDS: + type = OPENSSL_INFO_SEED_SOURCE; + dirty++; + break; + case OPT_CPUSETTINGS: + type = OPENSSL_INFO_CPU_SETTINGS; + dirty++; + break; + } + } + if (opt_num_rest() != 0) + 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/insta.ca.crt b/apps/insta.ca.crt Binary files differnew file mode 100644 index 000000000000..6aea6d4f9794 --- /dev/null +++ b/apps/insta.ca.crt diff --git a/apps/kdf.c b/apps/kdf.c new file mode 100644 index 000000000000..89ee1f69c766 --- /dev/null +++ b/apps/kdf.c @@ -0,0 +1,211 @@ +/* + * Copyright 2019-2021 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 <string.h> + +#include "apps.h" +#include "progs.h" +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include <openssl/params.h> + +typedef enum OPTION_choice { + OPT_COMMON, + OPT_KDFOPT, OPT_BIN, OPT_KEYLEN, OPT_OUT, + OPT_CIPHER, OPT_DIGEST, OPT_MAC, + OPT_PROV_ENUM +} OPTION_CHOICE; + +const OPTIONS kdf_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] kdf_name\n"}, + + OPT_SECTION("General"), + {"help", OPT_HELP, '-', "Display this summary"}, + {"kdfopt", OPT_KDFOPT, 's', "KDF algorithm control parameters in n:v form"}, + {"cipher", OPT_CIPHER, 's', "Cipher"}, + {"digest", OPT_DIGEST, 's', "Digest"}, + {"mac", OPT_MAC, 's', "MAC"}, + {OPT_MORE_STR, 1, '-', "See 'Supported Controls' in the EVP_KDF_ docs\n"}, + {"keylen", OPT_KEYLEN, 's', "The size of the output derived key"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, + {"binary", OPT_BIN, '-', + "Output in binary format (default is hexadecimal)"}, + + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"kdf_name", 0, 0, "Name of the KDF algorithm"}, + {NULL} +}; + +static char *alloc_kdf_algorithm_name(STACK_OF(OPENSSL_STRING) **optp, + const char *name, const char *arg) +{ + size_t len = strlen(name) + strlen(arg) + 2; + char *res; + + if (*optp == NULL) + *optp = sk_OPENSSL_STRING_new_null(); + if (*optp == NULL) + return NULL; + + res = app_malloc(len, "algorithm name"); + BIO_snprintf(res, len, "%s:%s", name, arg); + if (sk_OPENSSL_STRING_push(*optp, res)) + return res; + OPENSSL_free(res); + return NULL; +} + +int kdf_main(int argc, char **argv) +{ + int ret = 1, 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 *kdf = NULL; + EVP_KDF_CTX *ctx = NULL; + char *digest = NULL, *cipher = NULL, *mac = 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; + case OPT_CIPHER: + OPENSSL_free(cipher); + cipher = alloc_kdf_algorithm_name(&opts, "cipher", opt_arg()); + if (cipher == NULL) + goto opthelp; + break; + case OPT_DIGEST: + OPENSSL_free(digest); + digest = alloc_kdf_algorithm_name(&opts, "digest", opt_arg()); + if (digest == NULL) + goto opthelp; + break; + case OPT_MAC: + OPENSSL_free(mac); + mac = alloc_kdf_algorithm_name(&opts, "mac", opt_arg()); + if (mac == NULL) + goto opthelp; + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto err; + break; + } + } + + /* One argument, the KDF name. */ + argc = opt_num_rest(); + argv = opt_rest(); + if (argc != 1) + goto opthelp; + + if ((kdf = EVP_KDF_fetch(app_get0_libctx(), argv[0], + app_get0_propq())) == NULL) { + BIO_printf(bio_err, "Invalid KDF name %s\n", argv[0]); + goto opthelp; + } + + ctx = EVP_KDF_CTX_new(kdf); + if (ctx == NULL) + goto err; + + if (opts != NULL) { + int ok = 1; + OSSL_PARAM *params = + app_params_new_from_opts(opts, EVP_KDF_settable_ctx_params(kdf)); + + if (params == NULL) + goto err; + + if (!EVP_KDF_CTX_set_params(ctx, params)) { + BIO_printf(bio_err, "KDF parameter error\n"); + ERR_print_errors(bio_err); + ok = 0; + } + app_params_free(params); + if (!ok) + 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, NULL)) { + 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); + if (hexout == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + 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_free(kdf); + EVP_KDF_CTX_free(ctx); + BIO_free(out); + OPENSSL_free(hexout); + OPENSSL_free(cipher); + OPENSSL_free(digest); + OPENSSL_free(mac); + return ret; +} diff --git a/apps/lib/app_libctx.c b/apps/lib/app_libctx.c new file mode 100644 index 000000000000..4b9ec40e8527 --- /dev/null +++ b/apps/lib/app_libctx.c @@ -0,0 +1,48 @@ +/* + * Copyright 1995-2021 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 "app_libctx.h" +#include "apps.h" + +static OSSL_LIB_CTX *app_libctx = NULL; +static const char *app_propq = NULL; + +int app_set_propq(const char *arg) +{ + app_propq = arg; + return 1; +} + +const char *app_get0_propq(void) +{ + return app_propq; +} + +OSSL_LIB_CTX *app_get0_libctx(void) +{ + return app_libctx; +} + +OSSL_LIB_CTX *app_create_libctx(void) +{ + /* + * Load the NULL provider into the default library context and create a + * library context which will then be used for any OPT_PROV options. + */ + if (app_libctx == NULL) { + if (!app_provider_load(NULL, "null")) { + opt_printf_stderr( "Failed to create null provider\n"); + return NULL; + } + app_libctx = OSSL_LIB_CTX_new(); + } + if (app_libctx == NULL) + opt_printf_stderr("Failed to create library context\n"); + return app_libctx; +} + diff --git a/apps/lib/app_params.c b/apps/lib/app_params.c new file mode 100644 index 000000000000..95e1298ee926 --- /dev/null +++ b/apps/lib/app_params.c @@ -0,0 +1,132 @@ +/* + * Copyright 2019-2020 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 "apps.h" +#include "app_params.h" + +static int describe_param_type(char *buf, size_t bufsz, const OSSL_PARAM *param) +{ + const char *type_mod = ""; + const char *type = NULL; + int show_type_number = 0; + int printed_len; + + switch (param->data_type) { + case OSSL_PARAM_UNSIGNED_INTEGER: + type_mod = "unsigned "; + /* FALLTHRU */ + case OSSL_PARAM_INTEGER: + type = "integer"; + break; + case OSSL_PARAM_UTF8_PTR: + type_mod = "pointer to a "; + /* FALLTHRU */ + case OSSL_PARAM_UTF8_STRING: + type = "UTF8 encoded string"; + break; + case OSSL_PARAM_OCTET_PTR: + type_mod = "pointer to an "; + /* FALLTHRU */ + case OSSL_PARAM_OCTET_STRING: + type = "octet string"; + break; + default: + type = "unknown type"; + show_type_number = 1; + break; + } + + printed_len = BIO_snprintf(buf, bufsz, "%s: ", param->key); + if (printed_len > 0) { + buf += printed_len; + bufsz -= printed_len; + } + printed_len = BIO_snprintf(buf, bufsz, "%s%s", type_mod, type); + if (printed_len > 0) { + buf += printed_len; + bufsz -= printed_len; + } + if (show_type_number) { + printed_len = BIO_snprintf(buf, bufsz, " [%d]", param->data_type); + if (printed_len > 0) { + buf += printed_len; + bufsz -= printed_len; + } + } + if (param->data_size == 0) + printed_len = BIO_snprintf(buf, bufsz, " (arbitrary size)"); + else + printed_len = BIO_snprintf(buf, bufsz, " (max %zu bytes large)", + param->data_size); + if (printed_len > 0) { + buf += printed_len; + bufsz -= printed_len; + } + *buf = '\0'; + return 1; +} + +int print_param_types(const char *thing, const OSSL_PARAM *pdefs, int indent) +{ + if (pdefs == NULL) { + return 1; + } else if (pdefs->key == NULL) { + /* + * An empty list? This shouldn't happen, but let's just make sure to + * say something if there's a badly written provider... + */ + BIO_printf(bio_out, "%*sEmpty list of %s (!!!)\n", indent, "", thing); + } else { + BIO_printf(bio_out, "%*s%s:\n", indent, "", thing); + for (; pdefs->key != NULL; pdefs++) { + char buf[200]; /* This should be ample space */ + + describe_param_type(buf, sizeof(buf), pdefs); + BIO_printf(bio_out, "%*s %s\n", indent, "", buf); + } + } + return 1; +} + +void print_param_value(const OSSL_PARAM *p, int indent) +{ + int64_t i; + uint64_t u; + + printf("%*s%s: ", indent, "", p->key); + switch (p->data_type) { + case OSSL_PARAM_UNSIGNED_INTEGER: + if (OSSL_PARAM_get_uint64(p, &u)) + BIO_printf(bio_out, "%llu\n", (unsigned long long int)u); + else + BIO_printf(bio_out, "error getting value\n"); + break; + case OSSL_PARAM_INTEGER: + if (OSSL_PARAM_get_int64(p, &i)) + BIO_printf(bio_out, "%lld\n", (long long int)i); + else + BIO_printf(bio_out, "error getting value\n"); + break; + case OSSL_PARAM_UTF8_PTR: + BIO_printf(bio_out, "'%s'\n", *(char **)(p->data)); + break; + case OSSL_PARAM_UTF8_STRING: + BIO_printf(bio_out, "'%s'\n", (char *)p->data); + break; + case OSSL_PARAM_OCTET_PTR: + case OSSL_PARAM_OCTET_STRING: + BIO_printf(bio_out, "<%zu bytes>\n", p->data_size); + break; + default: + BIO_printf(bio_out, "unknown type (%u) of %zu bytes\n", + p->data_type, p->data_size); + break; + } +} + diff --git a/apps/lib/app_provider.c b/apps/lib/app_provider.c new file mode 100644 index 000000000000..63f78ae07d80 --- /dev/null +++ b/apps/lib/app_provider.c @@ -0,0 +1,92 @@ +/* + * Copyright 2020-2021 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 "apps.h" +#include <string.h> +#include <openssl/err.h> +#include <openssl/provider.h> +#include <openssl/safestack.h> + +/* Non-zero if any of the provider options have been seen */ +static int provider_option_given = 0; + +DEFINE_STACK_OF(OSSL_PROVIDER) + +/* + * See comments in opt_verify for explanation of this. + */ +enum prov_range { OPT_PROV_ENUM }; + +static STACK_OF(OSSL_PROVIDER) *app_providers = NULL; + +static void provider_free(OSSL_PROVIDER *prov) +{ + OSSL_PROVIDER_unload(prov); +} + +int app_provider_load(OSSL_LIB_CTX *libctx, const char *provider_name) +{ + OSSL_PROVIDER *prov; + + prov = OSSL_PROVIDER_load(libctx, provider_name); + if (prov == NULL) { + opt_printf_stderr("%s: unable to load provider %s\n" + "Hint: use -provider-path option or OPENSSL_MODULES environment variable.\n", + opt_getprog(), provider_name); + ERR_print_errors(bio_err); + return 0; + } + if (app_providers == NULL) + app_providers = sk_OSSL_PROVIDER_new_null(); + if (app_providers == NULL + || !sk_OSSL_PROVIDER_push(app_providers, prov)) { + app_providers_cleanup(); + return 0; + } + return 1; +} + +void app_providers_cleanup(void) +{ + sk_OSSL_PROVIDER_pop_free(app_providers, provider_free); + app_providers = NULL; +} + +static int opt_provider_path(const char *path) +{ + if (path != NULL && *path == '\0') + path = NULL; + return OSSL_PROVIDER_set_default_search_path(app_get0_libctx(), path); +} + +int opt_provider(int opt) +{ + const int given = provider_option_given; + + provider_option_given = 1; + switch ((enum prov_range)opt) { + case OPT_PROV__FIRST: + case OPT_PROV__LAST: + return 1; + case OPT_PROV_PROVIDER: + return app_provider_load(app_get0_libctx(), opt_arg()); + case OPT_PROV_PROVIDER_PATH: + return opt_provider_path(opt_arg()); + case OPT_PROV_PROPQUERY: + return app_set_propq(opt_arg()); + } + /* Should never get here but if we do, undo what we did earlier */ + provider_option_given = given; + return 0; +} + +int opt_provider_option_given(void) +{ + return provider_option_given; +} diff --git a/apps/app_rand.c b/apps/lib/app_rand.c index 2b0bbde03423..713792ead40a 100644 --- a/apps/app_rand.c +++ b/apps/lib/app_rand.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,6 +14,7 @@ #include <openssl/conf.h> static char *save_rand_file; +static STACK_OF(OPENSSL_STRING) *randfiles; void app_RAND_load_conf(CONF *c, const char *section) { @@ -27,8 +28,14 @@ void app_RAND_load_conf(CONF *c, const char *section) BIO_printf(bio_err, "Can't load %s into RNG\n", randfile); ERR_print_errors(bio_err); } - if (save_rand_file == NULL) + if (save_rand_file == NULL) { save_rand_file = OPENSSL_strdup(randfile); + /* If some internal memory errors have occurred */ + if (save_rand_file == NULL) { + BIO_printf(bio_err, "Can't duplicate %s\n", randfile); + ERR_print_errors(bio_err); + } + } } static int loadfiles(char *name) @@ -57,16 +64,34 @@ static int loadfiles(char *name) return ret; } -void app_RAND_write(void) +int app_RAND_load(void) { + char *p; + int i, ret = 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(randfiles); i++) { + p = sk_OPENSSL_STRING_value(randfiles, i); + if (!loadfiles(p)) + ret = 0; + } + sk_OPENSSL_STRING_free(randfiles); + return ret; +} + +int app_RAND_write(void) +{ + int ret = 1; + if (save_rand_file == NULL) - return; + return 1; if (RAND_write_file(save_rand_file) == -1) { BIO_printf(bio_err, "Cannot write random bytes:\n"); ERR_print_errors(bio_err); + ret = 0; } OPENSSL_free(save_rand_file); save_rand_file = NULL; + return ret; } @@ -82,11 +107,17 @@ int opt_rand(int opt) case OPT_R__LAST: break; case OPT_R_RAND: - return loadfiles(opt_arg()); + if (randfiles == NULL + && (randfiles = sk_OPENSSL_STRING_new_null()) == NULL) + return 0; + if (!sk_OPENSSL_STRING_push(randfiles, opt_arg())) + return 0; break; case OPT_R_WRITERAND: OPENSSL_free(save_rand_file); save_rand_file = OPENSSL_strdup(opt_arg()); + if (save_rand_file == NULL) + return 0; break; } return 1; diff --git a/apps/lib/app_x509.c b/apps/lib/app_x509.c new file mode 100644 index 000000000000..f2c22948f201 --- /dev/null +++ b/apps/lib/app_x509.c @@ -0,0 +1,137 @@ +/* + * Copyright 2020-2021 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 <string.h> +#include "apps.h" + +/* + * X509_ctrl_str() is sorely lacking in libcrypto, but is still needed to + * allow the application to process verification options in a manner similar + * to signature or other options that pass through EVP_PKEY_CTX_ctrl_str(), + * for uniformity. + * + * As soon as more stuff is added, the code will need serious rework. For + * the moment, it only handles the FIPS 196 / SM2 distinguishing ID. + */ +#ifdef EVP_PKEY_CTRL_SET1_ID +static ASN1_OCTET_STRING *mk_octet_string(void *value, size_t value_n) +{ + ASN1_OCTET_STRING *v = ASN1_OCTET_STRING_new(); + + if (v == NULL) { + BIO_printf(bio_err, "error: allocation failed\n"); + } else if (!ASN1_OCTET_STRING_set(v, value, (int)value_n)) { + ASN1_OCTET_STRING_free(v); + v = NULL; + } + return v; +} +#endif + +static int x509_ctrl(void *object, int cmd, void *value, size_t value_n) +{ + switch (cmd) { +#ifdef EVP_PKEY_CTRL_SET1_ID + case EVP_PKEY_CTRL_SET1_ID: + { + ASN1_OCTET_STRING *v = mk_octet_string(value, value_n); + + if (v == NULL) { + BIO_printf(bio_err, + "error: setting distinguishing ID in certificate failed\n"); + return 0; + } + + X509_set0_distinguishing_id(object, v); + return 1; + } +#endif + default: + break; + } + return -2; /* typical EVP_PKEY return for "unsupported" */ +} + +static int x509_req_ctrl(void *object, int cmd, void *value, size_t value_n) +{ + switch (cmd) { +#ifdef EVP_PKEY_CTRL_SET1_ID + case EVP_PKEY_CTRL_SET1_ID: + { + ASN1_OCTET_STRING *v = mk_octet_string(value, value_n); + + if (v == NULL) { + BIO_printf(bio_err, + "error: setting distinguishing ID in certificate signing request failed\n"); + return 0; + } + + X509_REQ_set0_distinguishing_id(object, v); + return 1; + } +#endif + default: + break; + } + return -2; /* typical EVP_PKEY return for "unsupported" */ +} + +static int do_x509_ctrl_string(int (*ctrl)(void *object, int cmd, + void *value, size_t value_n), + void *object, const char *value) +{ + int rv = 0; + char *stmp, *vtmp = NULL; + size_t vtmp_len = 0; + int cmd = 0; /* Will get command values that make sense somehow */ + + stmp = OPENSSL_strdup(value); + if (stmp == NULL) + return -1; + vtmp = strchr(stmp, ':'); + if (vtmp != NULL) { + *vtmp = 0; + vtmp++; + vtmp_len = strlen(vtmp); + } + + if (strcmp(stmp, "distid") == 0) { +#ifdef EVP_PKEY_CTRL_SET1_ID + cmd = EVP_PKEY_CTRL_SET1_ID; /* ... except we put it in X509 */ +#endif + } else if (strcmp(stmp, "hexdistid") == 0) { + if (vtmp != NULL) { + void *hexid; + long hexid_len = 0; + + hexid = OPENSSL_hexstr2buf((const char *)vtmp, &hexid_len); + OPENSSL_free(stmp); + stmp = vtmp = hexid; + vtmp_len = (size_t)hexid_len; + } +#ifdef EVP_PKEY_CTRL_SET1_ID + cmd = EVP_PKEY_CTRL_SET1_ID; /* ... except we put it in X509 */ +#endif + } + + rv = ctrl(object, cmd, vtmp, vtmp_len); + + OPENSSL_free(stmp); + return rv; +} + +int x509_ctrl_string(X509 *x, const char *value) +{ + return do_x509_ctrl_string(x509_ctrl, x, value); +} + +int x509_req_ctrl_string(X509_REQ *x, const char *value) +{ + return do_x509_ctrl_string(x509_req_ctrl, x, value); +} diff --git a/apps/apps.c b/apps/lib/apps.c index f2447fb0bef8..0d7a20b52afc 100644 --- a/apps/apps.c +++ b/apps/lib/apps.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -15,6 +15,12 @@ # define _POSIX_C_SOURCE 2 #endif +#ifndef OPENSSL_NO_ENGINE +/* We need to use some deprecated APIs */ +# define OPENSSL_SUPPRESS_DEPRECATED +# include <openssl/engine.h> +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -28,18 +34,19 @@ #include <openssl/err.h> #include <openssl/x509.h> #include <openssl/x509v3.h> +#include <openssl/http.h> #include <openssl/pem.h> +#include <openssl/store.h> #include <openssl/pkcs12.h> #include <openssl/ui.h> #include <openssl/safestack.h> -#ifndef OPENSSL_NO_ENGINE -# include <openssl/engine.h> -#endif -#ifndef OPENSSL_NO_RSA -# include <openssl/rsa.h> -#endif +#include <openssl/rsa.h> +#include <openssl/rand.h> #include <openssl/bn.h> #include <openssl/ssl.h> +#include <openssl/store.h> +#include <openssl/core_names.h> +#include "s_apps.h" #include "apps.h" #ifdef _WIN32 @@ -51,23 +58,35 @@ static int WIN32_rename(const char *from, const char *to); # include <conio.h> #endif -#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) +#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) || defined(__BORLANDC__) # define _kbhit kbhit #endif +static BIO *bio_open_default_(const char *filename, char mode, int format, + int quiet); + +#define PASS_SOURCE_SIZE_MAX 4 + +DEFINE_STACK_OF(CONF) + typedef struct { const char *name; unsigned long flag; unsigned long mask; } NAME_EX_TBL; -static UI_METHOD *ui_method = NULL; -static const UI_METHOD *ui_fallback_method = NULL; - static int set_table_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL * in_tbl); static int set_multi_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL * in_tbl); +static +int load_key_certs_crls_suppress(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc, + EVP_PKEY **ppkey, EVP_PKEY **ppubkey, + EVP_PKEY **pparams, + X509 **pcert, STACK_OF(X509) **pcerts, + X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls, + int suppress_decode_errors); int app_init(long mesgwin); @@ -86,7 +105,7 @@ int chopup_args(ARGS *arg, char *buf) /* Skip whitespace. */ while (*p && isspace(_UC(*p))) p++; - if (!*p) + if (*p == '\0') break; /* The start of something good :-) */ @@ -126,18 +145,29 @@ int app_init(long mesgwin) } #endif -int ctx_set_verify_locations(SSL_CTX *ctx, const char *CAfile, - const char *CApath, int noCAfile, int noCApath) +int ctx_set_verify_locations(SSL_CTX *ctx, + const char *CAfile, int noCAfile, + const char *CApath, int noCApath, + const char *CAstore, int noCAstore) { - if (CAfile == NULL && CApath == NULL) { + if (CAfile == NULL && CApath == NULL && CAstore == NULL) { if (!noCAfile && SSL_CTX_set_default_verify_file(ctx) <= 0) return 0; if (!noCApath && SSL_CTX_set_default_verify_dir(ctx) <= 0) return 0; + if (!noCAstore && SSL_CTX_set_default_verify_store(ctx) <= 0) + return 0; return 1; } - return SSL_CTX_load_verify_locations(ctx, CAfile, CApath); + + if (CAfile != NULL && !SSL_CTX_load_verify_file(ctx, CAfile)) + return 0; + if (CApath != NULL && !SSL_CTX_load_verify_dir(ctx, CApath)) + return 0; + if (CAstore != NULL && !SSL_CTX_load_verify_store(ctx, CAstore)) + return 0; + return 1; } #ifndef OPENSSL_NO_CT @@ -170,201 +200,42 @@ unsigned long get_nameopt(void) return (nmflag_set) ? nmflag : XN_FLAG_ONELINE; } -int dump_cert_text(BIO *out, X509 *x) -{ - print_name(out, "subject=", X509_get_subject_name(x), get_nameopt()); - BIO_puts(out, "\n"); - print_name(out, "issuer=", X509_get_issuer_name(x), get_nameopt()); - BIO_puts(out, "\n"); - - return 0; -} - -static int ui_open(UI *ui) -{ - int (*opener)(UI *ui) = UI_method_get_opener(ui_fallback_method); - - if (opener) - return opener(ui); - return 1; -} - -static int ui_read(UI *ui, UI_STRING *uis) +void dump_cert_text(BIO *out, X509 *x) { - int (*reader)(UI *ui, UI_STRING *uis) = NULL; - - if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD - && UI_get0_user_data(ui)) { - switch (UI_get_string_type(uis)) { - case UIT_PROMPT: - case UIT_VERIFY: - { - const char *password = - ((PW_CB_DATA *)UI_get0_user_data(ui))->password; - if (password && password[0] != '\0') { - UI_set_result(ui, uis, password); - return 1; - } - } - break; - case UIT_NONE: - case UIT_BOOLEAN: - case UIT_INFO: - case UIT_ERROR: - break; - } - } - - reader = UI_method_get_reader(ui_fallback_method); - if (reader) - return reader(ui, uis); - return 1; + print_name(out, "subject=", X509_get_subject_name(x)); + print_name(out, "issuer=", X509_get_issuer_name(x)); } -static int ui_write(UI *ui, UI_STRING *uis) +int wrap_password_callback(char *buf, int bufsiz, int verify, void *userdata) { - int (*writer)(UI *ui, UI_STRING *uis) = NULL; - - if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD - && UI_get0_user_data(ui)) { - switch (UI_get_string_type(uis)) { - case UIT_PROMPT: - case UIT_VERIFY: - { - const char *password = - ((PW_CB_DATA *)UI_get0_user_data(ui))->password; - if (password && password[0] != '\0') - return 1; - } - break; - case UIT_NONE: - case UIT_BOOLEAN: - case UIT_INFO: - case UIT_ERROR: - break; - } - } - - writer = UI_method_get_writer(ui_fallback_method); - if (writer) - return writer(ui, uis); - return 1; + return password_callback(buf, bufsiz, verify, (PW_CB_DATA *)userdata); } -static int ui_close(UI *ui) -{ - int (*closer)(UI *ui) = UI_method_get_closer(ui_fallback_method); - if (closer) - return closer(ui); - return 1; -} - -int setup_ui_method(void) -{ - ui_fallback_method = UI_null(); -#ifndef OPENSSL_NO_UI_CONSOLE - ui_fallback_method = UI_OpenSSL(); -#endif - ui_method = UI_create_method("OpenSSL application user interface"); - UI_method_set_opener(ui_method, ui_open); - UI_method_set_reader(ui_method, ui_read); - UI_method_set_writer(ui_method, ui_write); - UI_method_set_closer(ui_method, ui_close); - return 0; -} - -void destroy_ui_method(void) -{ - if (ui_method) { - UI_destroy_method(ui_method); - ui_method = NULL; - } -} - -const UI_METHOD *get_ui_method(void) -{ - return ui_method; -} +static char *app_get_pass(const char *arg, int keepbio); -int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_tmp) +char *get_passwd(const char *pass, const char *desc) { - int res = 0; - UI *ui = NULL; - PW_CB_DATA *cb_data = (PW_CB_DATA *)cb_tmp; - - ui = UI_new_method(ui_method); - if (ui) { - int ok = 0; - char *buff = NULL; - int ui_flags = 0; - const char *prompt_info = NULL; - char *prompt; - int pw_min_len = PW_MIN_LENGTH; - - if (cb_data != NULL && cb_data->prompt_info != NULL) - prompt_info = cb_data->prompt_info; - if (cb_data != NULL && cb_data->password != NULL - && *(const char*)cb_data->password != '\0') - pw_min_len = 1; - else if (!verify) - pw_min_len = 0; - prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); - if (!prompt) { - BIO_printf(bio_err, "Out of memory\n"); - UI_free(ui); - return 0; - } - - ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD; - UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); + char *result = NULL; - /* We know that there is no previous user data to return to us */ - (void)UI_add_user_data(ui, cb_data); - - ok = UI_add_input_string(ui, prompt, ui_flags, buf, - pw_min_len, bufsiz - 1); - - if (ok >= 0 && verify) { - buff = app_malloc(bufsiz, "password buffer"); - ok = UI_add_verify_string(ui, prompt, ui_flags, buff, - pw_min_len, bufsiz - 1, buf); - } - if (ok >= 0) - do { - ok = UI_process(ui); - } while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); - - OPENSSL_clear_free(buff, (unsigned int)bufsiz); - - if (ok >= 0) - res = strlen(buf); - if (ok == -1) { - BIO_printf(bio_err, "User interface error\n"); - ERR_print_errors(bio_err); - OPENSSL_cleanse(buf, (unsigned int)bufsiz); - res = 0; - } - if (ok == -2) { - BIO_printf(bio_err, "aborted!\n"); - OPENSSL_cleanse(buf, (unsigned int)bufsiz); - res = 0; - } - UI_free(ui); - OPENSSL_free(prompt); + if (desc == NULL) + desc = "<unknown>"; + if (!app_passwd(pass, NULL, &result, NULL)) + BIO_printf(bio_err, "Error getting password for %s\n", desc); + if (pass != NULL && result == NULL) { + BIO_printf(bio_err, + "Trying plain input string (better precede with 'pass:')\n"); + result = OPENSSL_strdup(pass); + if (result == NULL) + BIO_printf(bio_err, "Out of memory getting password for %s\n", desc); } - return res; + return result; } -static char *app_get_pass(const char *arg, int keepbio); - int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2) { - int same; - if (arg2 == NULL || arg1 == NULL || strcmp(arg1, arg2)) - same = 0; - else - same = 1; + int same = arg1 != NULL && arg2 != NULL && strcmp(arg1, arg2) == 0; + if (arg1 != NULL) { *pass1 = app_get_pass(arg1, same); if (*pass1 == NULL) @@ -384,16 +255,17 @@ int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2) static char *app_get_pass(const char *arg, int keepbio) { - char *tmp, tpass[APP_PASS_LEN]; static BIO *pwdbio = NULL; + char *tmp, tpass[APP_PASS_LEN]; int i; + /* PASS_SOURCE_SIZE_MAX = max number of chars before ':' in below strings */ if (strncmp(arg, "pass:", 5) == 0) return OPENSSL_strdup(arg + 5); if (strncmp(arg, "env:", 4) == 0) { tmp = getenv(arg + 4); if (tmp == NULL) { - BIO_printf(bio_err, "Can't read environment variable %s\n", arg + 4); + BIO_printf(bio_err, "No environment variable %s\n", arg + 4); return NULL; } return OPENSSL_strdup(tmp); @@ -419,7 +291,7 @@ static char *app_get_pass(const char *arg, int keepbio) i = atoi(arg + 3); if (i >= 0) pwdbio = BIO_new_fd(i, BIO_NOCLOSE); - if ((i < 0) || !pwdbio) { + if ((i < 0) || pwdbio == NULL) { BIO_printf(bio_err, "Can't access file descriptor %s\n", arg + 3); return NULL; } @@ -427,16 +299,32 @@ static char *app_get_pass(const char *arg, int keepbio) * Can't do BIO_gets on an fd BIO so add a buffering BIO */ btmp = BIO_new(BIO_f_buffer()); + if (btmp == NULL) { + BIO_free_all(pwdbio); + pwdbio = NULL; + BIO_printf(bio_err, "Out of memory\n"); + return NULL; + } pwdbio = BIO_push(btmp, pwdbio); #endif } else if (strcmp(arg, "stdin") == 0) { + unbuffer(stdin); pwdbio = dup_bio_in(FORMAT_TEXT); - if (!pwdbio) { + if (pwdbio == NULL) { BIO_printf(bio_err, "Can't open BIO for stdin\n"); return NULL; } } else { - BIO_printf(bio_err, "Invalid password argument \"%s\"\n", arg); + /* argument syntax error; do not reveal too much about arg */ + tmp = strchr(arg, ':'); + if (tmp == NULL || tmp - arg > PASS_SOURCE_SIZE_MAX) + BIO_printf(bio_err, + "Invalid password argument, missing ':' within the first %d chars\n", + PASS_SOURCE_SIZE_MAX + 1); + else + BIO_printf(bio_err, + "Invalid password argument, starting with \"%.*s\"\n", + (int)(tmp - arg + 1), arg); return NULL; } } @@ -461,7 +349,7 @@ CONF *app_load_config_bio(BIO *in, const char *filename) CONF *conf; int i; - conf = NCONF_new(NULL); + conf = NCONF_new_ex(app_get0_libctx(), NULL); i = NCONF_load_bio(conf, in, &errorline); if (i > 0) return conf; @@ -481,31 +369,31 @@ CONF *app_load_config_bio(BIO *in, const char *filename) return NULL; } -CONF *app_load_config(const char *filename) +CONF *app_load_config_verbose(const char *filename, int verbose) { - BIO *in; - CONF *conf; - - in = bio_open_default(filename, 'r', FORMAT_TEXT); - if (in == NULL) - return NULL; - - conf = app_load_config_bio(in, filename); - BIO_free(in); - return conf; + if (verbose) { + if (*filename == '\0') + BIO_printf(bio_err, "No configuration used\n"); + else + BIO_printf(bio_err, "Using configuration from %s\n", filename); + } + return app_load_config_internal(filename, 0); } -CONF *app_load_config_quiet(const char *filename) +CONF *app_load_config_internal(const char *filename, int quiet) { BIO *in; CONF *conf; - in = bio_open_default_quiet(filename, 'r', FORMAT_TEXT); - if (in == NULL) - return NULL; - - conf = app_load_config_bio(in, filename); - BIO_free(in); + if (filename == NULL || *filename != '\0') { + if ((in = bio_open_default_(filename, 'r', FORMAT_TEXT, quiet)) == NULL) + return NULL; + conf = app_load_config_bio(in, filename); + BIO_free(in); + } else { + /* Return empty config if filename is empty string. */ + conf = NCONF_new_ex(app_get0_libctx(), NULL); + } return conf; } @@ -554,439 +442,663 @@ int add_oid_section(CONF *conf) return 1; } -static int load_pkcs12(BIO *in, const char *desc, - pem_password_cb *pem_cb, void *cb_data, - EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) +CONF *app_load_config_modules(const char *configfile) { - const char *pass; - char tpass[PEM_BUFSIZE]; - int len, ret = 0; - PKCS12 *p12; - p12 = d2i_PKCS12_bio(in, NULL); - if (p12 == NULL) { - BIO_printf(bio_err, "Error loading PKCS12 file for %s\n", desc); - goto die; - } - /* See if an empty password will do */ - if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0)) { - pass = ""; - } else { - if (!pem_cb) - pem_cb = (pem_password_cb *)password_callback; - len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data); - if (len < 0) { - BIO_printf(bio_err, "Passphrase callback error for %s\n", desc); - goto die; - } - if (len < PEM_BUFSIZE) - tpass[len] = 0; - if (!PKCS12_verify_mac(p12, tpass, len)) { - BIO_printf(bio_err, - "Mac verify error (wrong password?) in PKCS12 file for %s\n", - desc); - goto die; + CONF *conf = NULL; + + if (configfile != NULL) { + if ((conf = app_load_config_verbose(configfile, 1)) == NULL) + return NULL; + if (configfile != default_config_file && !app_load_modules(conf)) { + NCONF_free(conf); + conf = NULL; } - pass = tpass; } - ret = PKCS12_parse(p12, pass, pkey, cert, ca); - die: - PKCS12_free(p12); - return ret; + return conf; } -#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) -static int load_cert_crl_http(const char *url, X509 **pcert, X509_CRL **pcrl) +#define IS_HTTP(uri) ((uri) != NULL \ + && strncmp(uri, OSSL_HTTP_PREFIX, strlen(OSSL_HTTP_PREFIX)) == 0) +#define IS_HTTPS(uri) ((uri) != NULL \ + && strncmp(uri, OSSL_HTTPS_PREFIX, strlen(OSSL_HTTPS_PREFIX)) == 0) + +X509 *load_cert_pass(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc) { - char *host = NULL, *port = NULL, *path = NULL; - BIO *bio = NULL; - OCSP_REQ_CTX *rctx = NULL; - int use_ssl, rv = 0; - if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) - goto err; - if (use_ssl) { - BIO_puts(bio_err, "https not supported\n"); - goto err; - } - bio = BIO_new_connect(host); - if (!bio || !BIO_set_conn_port(bio, port)) - goto err; - rctx = OCSP_REQ_CTX_new(bio, 1024); - if (rctx == NULL) - goto err; - if (!OCSP_REQ_CTX_http(rctx, "GET", path)) - goto err; - if (!OCSP_REQ_CTX_add1_header(rctx, "Host", host)) - goto err; - if (pcert) { - do { - rv = X509_http_nbio(rctx, pcert); - } while (rv == -1); - } else { - do { - rv = X509_CRL_http_nbio(rctx, pcrl); - } while (rv == -1); - } + X509 *cert = NULL; - err: - OPENSSL_free(host); - OPENSSL_free(path); - OPENSSL_free(port); - BIO_free_all(bio); - OCSP_REQ_CTX_free(rctx); - if (rv != 1) { - BIO_printf(bio_err, "Error loading %s from %s\n", - pcert ? "certificate" : "CRL", url); + if (desc == NULL) + desc = "certificate"; + if (IS_HTTPS(uri)) + BIO_printf(bio_err, "Loading %s over HTTPS is unsupported\n", desc); + else if (IS_HTTP(uri)) + cert = X509_load_http(uri, NULL, NULL, 0 /* timeout */); + else + (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, + NULL, NULL, NULL, &cert, NULL, NULL, NULL); + if (cert == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); ERR_print_errors(bio_err); } - return rv; + return cert; } -#endif -X509 *load_cert(const char *file, int format, const char *cert_descrip) +X509_CRL *load_crl(const char *uri, int format, int maybe_stdin, + const char *desc) { - X509 *x = NULL; - BIO *cert; - - if (format == FORMAT_HTTP) { -#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) - load_cert_crl_http(file, &x, NULL); -#endif - return x; - } - - if (file == NULL) { - unbuffer(stdin); - cert = dup_bio_in(format); - } else { - cert = bio_open_default(file, 'r', format); - } - if (cert == NULL) - goto end; + X509_CRL *crl = NULL; - if (format == FORMAT_ASN1) { - x = d2i_X509_bio(cert, NULL); - } else if (format == FORMAT_PEM) { - x = PEM_read_bio_X509_AUX(cert, NULL, - (pem_password_cb *)password_callback, NULL); - } else if (format == FORMAT_PKCS12) { - if (!load_pkcs12(cert, cert_descrip, NULL, NULL, NULL, &x, NULL)) - goto end; - } else { - BIO_printf(bio_err, "bad input format specified for %s\n", cert_descrip); - goto end; - } - end: - if (x == NULL) { - BIO_printf(bio_err, "unable to load certificate\n"); + if (desc == NULL) + desc = "CRL"; + if (IS_HTTPS(uri)) + BIO_printf(bio_err, "Loading %s over HTTPS is unsupported\n", desc); + else if (IS_HTTP(uri)) + crl = X509_CRL_load_http(uri, NULL, NULL, 0 /* timeout */); + else + (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc, + NULL, NULL, NULL, NULL, NULL, &crl, NULL); + if (crl == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); ERR_print_errors(bio_err); } - BIO_free(cert); - return x; + return crl; } -X509_CRL *load_crl(const char *infile, int format) +X509_REQ *load_csr(const char *file, int format, const char *desc) { - X509_CRL *x = NULL; - BIO *in = NULL; - - if (format == FORMAT_HTTP) { -#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) - load_cert_crl_http(infile, NULL, &x); -#endif - return x; - } + X509_REQ *req = NULL; + BIO *in; - in = bio_open_default(infile, 'r', format); + if (format == FORMAT_UNDEF) + format = FORMAT_PEM; + if (desc == NULL) + desc = "CSR"; + in = bio_open_default(file, 'r', format); if (in == NULL) goto end; - if (format == FORMAT_ASN1) { - x = d2i_X509_CRL_bio(in, NULL); - } else if (format == FORMAT_PEM) { - x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); - } else { - BIO_printf(bio_err, "bad input format specified for input crl\n"); - goto end; - } - if (x == NULL) { - BIO_printf(bio_err, "unable to load CRL\n"); - ERR_print_errors(bio_err); - goto end; - } + + if (format == FORMAT_ASN1) + req = d2i_X509_REQ_bio(in, NULL); + else if (format == FORMAT_PEM) + req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); + else + print_format_error(format, OPT_FMT_PEMDER); end: + if (req == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); + ERR_print_errors(bio_err); + } BIO_free(in); - return x; + return req; +} + +void cleanse(char *str) +{ + if (str != NULL) + OPENSSL_cleanse(str, strlen(str)); } -EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip) +void clear_free(char *str) +{ + if (str != NULL) + OPENSSL_clear_free(str, strlen(str)); +} + +EVP_PKEY *load_key(const char *uri, int format, int may_stdin, + const char *pass, ENGINE *e, const char *desc) { - BIO *key = NULL; EVP_PKEY *pkey = NULL; - PW_CB_DATA cb_data; + char *allocated_uri = NULL; - cb_data.password = pass; - cb_data.prompt_info = file; + if (desc == NULL) + desc = "private key"; - if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { - BIO_printf(bio_err, "no keyfile specified\n"); - goto end; - } if (format == FORMAT_ENGINE) { - if (e == NULL) { - BIO_printf(bio_err, "no engine specified\n"); - } else { -#ifndef OPENSSL_NO_ENGINE - if (ENGINE_init(e)) { - pkey = ENGINE_load_private_key(e, file, ui_method, &cb_data); - ENGINE_finish(e); - } - if (pkey == NULL) { - BIO_printf(bio_err, "cannot load %s from engine\n", key_descrip); - ERR_print_errors(bio_err); - } -#else - BIO_printf(bio_err, "engines not supported\n"); -#endif - } - goto end; - } - if (file == NULL && maybe_stdin) { - unbuffer(stdin); - key = dup_bio_in(format); - } else { - key = bio_open_default(file, 'r', format); - } - if (key == NULL) - goto end; - if (format == FORMAT_ASN1) { - pkey = d2i_PrivateKey_bio(key, NULL); - } else if (format == FORMAT_PEM) { - pkey = PEM_read_bio_PrivateKey(key, NULL, - (pem_password_cb *)password_callback, - &cb_data); - } else if (format == FORMAT_PKCS12) { - if (!load_pkcs12(key, key_descrip, - (pem_password_cb *)password_callback, &cb_data, - &pkey, NULL, NULL)) - goto end; -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4) - } else if (format == FORMAT_MSBLOB) { - pkey = b2i_PrivateKey_bio(key); - } else if (format == FORMAT_PVK) { - pkey = b2i_PVK_bio(key, (pem_password_cb *)password_callback, - &cb_data); -#endif - } else { - BIO_printf(bio_err, "bad input format specified for key file\n"); - goto end; - } - end: - BIO_free(key); - if (pkey == NULL) { - BIO_printf(bio_err, "unable to load %s\n", key_descrip); - ERR_print_errors(bio_err); + uri = allocated_uri = make_engine_uri(e, uri, desc); } + (void)load_key_certs_crls(uri, format, may_stdin, pass, desc, + &pkey, NULL, NULL, NULL, NULL, NULL, NULL); + + OPENSSL_free(allocated_uri); return pkey; } -EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip) +EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, + const char *pass, ENGINE *e, const char *desc) { - BIO *key = NULL; EVP_PKEY *pkey = NULL; - PW_CB_DATA cb_data; + char *allocated_uri = NULL; - cb_data.password = pass; - cb_data.prompt_info = file; + if (desc == NULL) + desc = "public key"; - if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { - BIO_printf(bio_err, "no keyfile specified\n"); - goto end; - } if (format == FORMAT_ENGINE) { - if (e == NULL) { - BIO_printf(bio_err, "no engine specified\n"); - } else { -#ifndef OPENSSL_NO_ENGINE - pkey = ENGINE_load_public_key(e, file, ui_method, &cb_data); - if (pkey == NULL) { - BIO_printf(bio_err, "cannot load %s from engine\n", key_descrip); - ERR_print_errors(bio_err); - } -#else - BIO_printf(bio_err, "engines not supported\n"); -#endif - } - goto end; - } - if (file == NULL && maybe_stdin) { - unbuffer(stdin); - key = dup_bio_in(format); - } else { - key = bio_open_default(file, 'r', format); - } - if (key == NULL) - goto end; - if (format == FORMAT_ASN1) { - pkey = d2i_PUBKEY_bio(key, NULL); - } else if (format == FORMAT_ASN1RSA) { -#ifndef OPENSSL_NO_RSA - RSA *rsa; - rsa = d2i_RSAPublicKey_bio(key, NULL); - if (rsa) { - pkey = EVP_PKEY_new(); - if (pkey != NULL) - EVP_PKEY_set1_RSA(pkey, rsa); - RSA_free(rsa); - } else -#else - BIO_printf(bio_err, "RSA keys not supported\n"); -#endif - pkey = NULL; - } else if (format == FORMAT_PEMRSA) { -#ifndef OPENSSL_NO_RSA - RSA *rsa; - rsa = PEM_read_bio_RSAPublicKey(key, NULL, - (pem_password_cb *)password_callback, - &cb_data); - if (rsa != NULL) { - pkey = EVP_PKEY_new(); - if (pkey != NULL) - EVP_PKEY_set1_RSA(pkey, rsa); - RSA_free(rsa); - } else -#else - BIO_printf(bio_err, "RSA keys not supported\n"); -#endif - pkey = NULL; - } else if (format == FORMAT_PEM) { - pkey = PEM_read_bio_PUBKEY(key, NULL, - (pem_password_cb *)password_callback, - &cb_data); -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) - } else if (format == FORMAT_MSBLOB) { - pkey = b2i_PublicKey_bio(key); -#endif + uri = allocated_uri = make_engine_uri(e, uri, desc); } - end: - BIO_free(key); - if (pkey == NULL) - BIO_printf(bio_err, "unable to load %s\n", key_descrip); + (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc, + NULL, &pkey, NULL, NULL, NULL, NULL, NULL); + + OPENSSL_free(allocated_uri); return pkey; } -static int load_certs_crls(const char *file, int format, - const char *pass, const char *desc, - STACK_OF(X509) **pcerts, - STACK_OF(X509_CRL) **pcrls) +EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin, + const char *keytype, const char *desc, + int suppress_decode_errors) { - int i; - BIO *bio; - STACK_OF(X509_INFO) *xis = NULL; - X509_INFO *xi; - PW_CB_DATA cb_data; - int rv = 0; + EVP_PKEY *params = NULL; - cb_data.password = pass; - cb_data.prompt_info = file; + if (desc == NULL) + desc = "key parameters"; - if (format != FORMAT_PEM) { - BIO_printf(bio_err, "bad input format specified for %s\n", desc); - return 0; + (void)load_key_certs_crls_suppress(uri, format, maybe_stdin, NULL, desc, + NULL, NULL, ¶ms, NULL, NULL, NULL, + NULL, suppress_decode_errors); + if (params != NULL && keytype != NULL && !EVP_PKEY_is_a(params, keytype)) { + if (!suppress_decode_errors) { + BIO_printf(bio_err, + "Unable to load %s from %s (unexpected parameters type)\n", + desc, uri); + ERR_print_errors(bio_err); + } + EVP_PKEY_free(params); + params = NULL; } + return params; +} - bio = bio_open_default(file, 'r', FORMAT_PEM); - if (bio == NULL) - return 0; +EVP_PKEY *load_keyparams(const char *uri, int format, int maybe_stdin, + const char *keytype, const char *desc) +{ + return load_keyparams_suppress(uri, format, maybe_stdin, keytype, desc, 0); +} - xis = PEM_X509_INFO_read_bio(bio, NULL, - (pem_password_cb *)password_callback, - &cb_data); +void app_bail_out(char *fmt, ...) +{ + va_list args; - BIO_free(bio); + va_start(args, fmt); + BIO_vprintf(bio_err, fmt, args); + va_end(args); + ERR_print_errors(bio_err); + exit(EXIT_FAILURE); +} - if (pcerts != NULL && *pcerts == NULL) { - *pcerts = sk_X509_new_null(); - if (*pcerts == NULL) - goto end; - } +void *app_malloc(size_t sz, const char *what) +{ + void *vp = OPENSSL_malloc(sz); - if (pcrls != NULL && *pcrls == NULL) { - *pcrls = sk_X509_CRL_new_null(); - if (*pcrls == NULL) - goto end; - } + if (vp == NULL) + app_bail_out("%s: Could not allocate %zu bytes for %s\n", + opt_getprog(), sz, what); + return vp; +} - for (i = 0; i < sk_X509_INFO_num(xis); i++) { - xi = sk_X509_INFO_value(xis, i); - if (xi->x509 != NULL && pcerts != NULL) { - if (!sk_X509_push(*pcerts, xi->x509)) - goto end; - xi->x509 = NULL; - } - if (xi->crl != NULL && pcrls != NULL) { - if (!sk_X509_CRL_push(*pcrls, xi->crl)) - goto end; - xi->crl = NULL; - } +char *next_item(char *opt) /* in list separated by comma and/or space */ +{ + /* advance to separator (comma or whitespace), if any */ + while (*opt != ',' && !isspace(*opt) && *opt != '\0') + opt++; + if (*opt != '\0') { + /* terminate current item */ + *opt++ = '\0'; + /* skip over any whitespace after separator */ + while (isspace(*opt)) + opt++; } + return *opt == '\0' ? NULL : opt; /* NULL indicates end of input */ +} - if (pcerts != NULL && sk_X509_num(*pcerts) > 0) - rv = 1; +static void warn_cert_msg(const char *uri, X509 *cert, const char *msg) +{ + char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - if (pcrls != NULL && sk_X509_CRL_num(*pcrls) > 0) - rv = 1; + BIO_printf(bio_err, "Warning: certificate from '%s' with subject '%s' %s\n", + uri, subj, msg); + OPENSSL_free(subj); +} - end: +static void warn_cert(const char *uri, X509 *cert, int warn_EE, + X509_VERIFY_PARAM *vpm) +{ + uint32_t ex_flags = X509_get_extension_flags(cert); + int res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert), + X509_get0_notAfter(cert)); + + if (res != 0) + warn_cert_msg(uri, cert, res > 0 ? "has expired" : "not yet valid"); + if (warn_EE && (ex_flags & EXFLAG_V1) == 0 && (ex_flags & EXFLAG_CA) == 0) + warn_cert_msg(uri, cert, "is not a CA cert"); +} + +static void warn_certs(const char *uri, STACK_OF(X509) *certs, int warn_EE, + X509_VERIFY_PARAM *vpm) +{ + int i; - sk_X509_INFO_pop_free(xis, X509_INFO_free); + for (i = 0; i < sk_X509_num(certs); i++) + warn_cert(uri, sk_X509_value(certs, i), warn_EE, vpm); +} - if (rv == 0) { +int load_cert_certs(const char *uri, + X509 **pcert, STACK_OF(X509) **pcerts, + int exclude_http, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm) +{ + int ret = 0; + char *pass_string; + + if (exclude_http && (OPENSSL_strncasecmp(uri, "http://", 7) == 0 + || OPENSSL_strncasecmp(uri, "https://", 8) == 0)) { + BIO_printf(bio_err, "error: HTTP retrieval not allowed for %s\n", desc); + return ret; + } + pass_string = get_passwd(pass, desc); + ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass_string, desc, + NULL, NULL, NULL, + pcert, pcerts, NULL, NULL); + clear_free(pass_string); + + if (ret) { + if (pcert != NULL) + warn_cert(uri, *pcert, 0, vpm); + if (pcerts != NULL) + warn_certs(uri, *pcerts, 1, vpm); + } else { if (pcerts != NULL) { sk_X509_pop_free(*pcerts, X509_free); *pcerts = NULL; } - if (pcrls != NULL) { - sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); - *pcrls = NULL; + } + return ret; +} + +STACK_OF(X509) *load_certs_multifile(char *files, const char *pass, + const char *desc, X509_VERIFY_PARAM *vpm) +{ + STACK_OF(X509) *certs = NULL; + STACK_OF(X509) *result = sk_X509_new_null(); + + if (files == NULL) + goto err; + if (result == NULL) + goto oom; + + while (files != NULL) { + char *next = next_item(files); + + if (!load_cert_certs(files, NULL, &certs, 0, pass, desc, vpm)) + goto err; + if (!X509_add_certs(result, certs, + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) + goto oom; + sk_X509_pop_free(certs, X509_free); + certs = NULL; + files = next; + } + return result; + + oom: + BIO_printf(bio_err, "out of memory\n"); + err: + sk_X509_pop_free(certs, X509_free); + sk_X509_pop_free(result, X509_free); + return NULL; +} + +static X509_STORE *sk_X509_to_store(X509_STORE *store /* may be NULL */, + const STACK_OF(X509) *certs /* may NULL */) +{ + int i; + + if (store == NULL) + store = X509_STORE_new(); + if (store == NULL) + return NULL; + for (i = 0; i < sk_X509_num(certs); i++) { + if (!X509_STORE_add_cert(store, sk_X509_value(certs, i))) { + X509_STORE_free(store); + return NULL; } - BIO_printf(bio_err, "unable to load %s\n", - pcerts ? "certificates" : "CRLs"); - ERR_print_errors(bio_err); } - return rv; + return store; } -void* app_malloc(int sz, const char *what) +/* + * Create cert store structure with certificates read from given file(s). + * Returns pointer to created X509_STORE on success, NULL on error. + */ +X509_STORE *load_certstore(char *input, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm) { - void *vp = OPENSSL_malloc(sz); + X509_STORE *store = NULL; + STACK_OF(X509) *certs = NULL; - if (vp == NULL) { - BIO_printf(bio_err, "%s: Could not allocate %d bytes for %s\n", - opt_getprog(), sz, what); - ERR_print_errors(bio_err); - exit(1); + while (input != NULL) { + char *next = next_item(input); + int ok; + + if (!load_cert_certs(input, NULL, &certs, 1, pass, desc, vpm)) { + X509_STORE_free(store); + return NULL; + } + ok = (store = sk_X509_to_store(store, certs)) != NULL; + sk_X509_pop_free(certs, X509_free); + certs = NULL; + if (!ok) + return NULL; + input = next; } - return vp; + return store; } /* * Initialize or extend, if *certs != NULL, a certificate stack. + * The caller is responsible for freeing *certs if its value is left not NULL. */ -int load_certs(const char *file, STACK_OF(X509) **certs, int format, +int load_certs(const char *uri, int maybe_stdin, STACK_OF(X509) **certs, const char *pass, const char *desc) { - return load_certs_crls(file, format, pass, desc, certs, NULL); + int was_NULL = *certs == NULL; + int ret = load_key_certs_crls(uri, FORMAT_UNDEF, maybe_stdin, + pass, desc, NULL, NULL, + NULL, NULL, certs, NULL, NULL); + + if (!ret && was_NULL) { + sk_X509_pop_free(*certs, X509_free); + *certs = NULL; + } + return ret; } /* * Initialize or extend, if *crls != NULL, a certificate stack. + * The caller is responsible for freeing *crls if its value is left not NULL. */ -int load_crls(const char *file, STACK_OF(X509_CRL) **crls, int format, +int load_crls(const char *uri, STACK_OF(X509_CRL) **crls, const char *pass, const char *desc) { - return load_certs_crls(file, format, pass, desc, NULL, crls); + int was_NULL = *crls == NULL; + int ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass, desc, + NULL, NULL, NULL, + NULL, NULL, NULL, crls); + + if (!ret && was_NULL) { + sk_X509_CRL_pop_free(*crls, X509_CRL_free); + *crls = NULL; + } + return ret; +} + +static const char *format2string(int format) +{ + switch(format) { + case FORMAT_PEM: + return "PEM"; + case FORMAT_ASN1: + return "DER"; + } + return NULL; +} + +/* Set type expectation, but clear it if objects of different types expected. */ +#define SET_EXPECT(expect, val) ((expect) = (expect) < 0 ? (val) : ((expect) == (val) ? (val) : 0)) +/* + * Load those types of credentials for which the result pointer is not NULL. + * Reads from stdio if uri is NULL and maybe_stdin is nonzero. + * For non-NULL ppkey, pcert, and pcrl the first suitable value found is loaded. + * If pcerts is non-NULL and *pcerts == NULL then a new cert list is allocated. + * If pcerts is non-NULL then all available certificates are appended to *pcerts + * except any certificate assigned to *pcert. + * If pcrls is non-NULL and *pcrls == NULL then a new list of CRLs is allocated. + * If pcrls is non-NULL then all available CRLs are appended to *pcerts + * except any CRL assigned to *pcrl. + * In any case (also on error) the caller is responsible for freeing all members + * of *pcerts and *pcrls (as far as they are not NULL). + */ +static +int load_key_certs_crls_suppress(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc, + EVP_PKEY **ppkey, EVP_PKEY **ppubkey, + EVP_PKEY **pparams, + X509 **pcert, STACK_OF(X509) **pcerts, + X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls, + int suppress_decode_errors) +{ + PW_CB_DATA uidata; + OSSL_STORE_CTX *ctx = NULL; + OSSL_LIB_CTX *libctx = app_get0_libctx(); + const char *propq = app_get0_propq(); + int ncerts = 0; + int ncrls = 0; + const char *failed = + ppkey != NULL ? "key" : ppubkey != NULL ? "public key" : + pparams != NULL ? "params" : pcert != NULL ? "cert" : + pcrl != NULL ? "CRL" : pcerts != NULL ? "certs" : + pcrls != NULL ? "CRLs" : NULL; + int cnt_expectations = 0; + int expect = -1; + const char *input_type; + OSSL_PARAM itp[2]; + const OSSL_PARAM *params = NULL; + + if (ppkey != NULL) { + *ppkey = NULL; + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_PKEY); + } + if (ppubkey != NULL) { + *ppubkey = NULL; + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_PUBKEY); + } + if (pparams != NULL) { + *pparams = NULL; + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_PARAMS); + } + if (pcert != NULL) { + *pcert = NULL; + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_CERT); + } + if (pcerts != NULL) { + if (*pcerts == NULL && (*pcerts = sk_X509_new_null()) == NULL) { + BIO_printf(bio_err, "Out of memory loading"); + goto end; + } + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_CERT); + } + if (pcrl != NULL) { + *pcrl = NULL; + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_CRL); + } + if (pcrls != NULL) { + if (*pcrls == NULL && (*pcrls = sk_X509_CRL_new_null()) == NULL) { + BIO_printf(bio_err, "Out of memory loading"); + goto end; + } + cnt_expectations++; + SET_EXPECT(expect, OSSL_STORE_INFO_CRL); + } + if (cnt_expectations == 0) { + BIO_printf(bio_err, "Internal error: nothing to load from %s\n", + uri != NULL ? uri : "<stdin>"); + return 0; + } + + uidata.password = pass; + uidata.prompt_info = uri; + + if ((input_type = format2string(format)) != NULL) { + itp[0] = OSSL_PARAM_construct_utf8_string(OSSL_STORE_PARAM_INPUT_TYPE, + (char *)input_type, 0); + itp[1] = OSSL_PARAM_construct_end(); + params = itp; + } + + if (uri == NULL) { + BIO *bio; + + if (!maybe_stdin) { + BIO_printf(bio_err, "No filename or uri specified for loading"); + goto end; + } + uri = "<stdin>"; + unbuffer(stdin); + bio = BIO_new_fp(stdin, 0); + if (bio != NULL) { + ctx = OSSL_STORE_attach(bio, "file", libctx, propq, + get_ui_method(), &uidata, params, + NULL, NULL); + BIO_free(bio); + } + } else { + ctx = OSSL_STORE_open_ex(uri, libctx, propq, get_ui_method(), &uidata, + params, NULL, NULL); + } + if (ctx == NULL) { + BIO_printf(bio_err, "Could not open file or uri for loading"); + goto end; + } + if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) + goto end; + + failed = NULL; + while (cnt_expectations > 0 && !OSSL_STORE_eof(ctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(ctx); + int type, ok = 1; + + /* + * This can happen (for example) if we attempt to load a file with + * multiple different types of things in it - but the thing we just + * tried to load wasn't one of the ones we wanted, e.g. if we're trying + * to load a certificate but the file has both the private key and the + * certificate in it. We just retry until eof. + */ + if (info == NULL) { + continue; + } + + type = OSSL_STORE_INFO_get_type(info); + switch (type) { + case OSSL_STORE_INFO_PKEY: + if (ppkey != NULL && *ppkey == NULL) { + ok = (*ppkey = OSSL_STORE_INFO_get1_PKEY(info)) != NULL; + cnt_expectations -= ok; + } + /* + * An EVP_PKEY with private parts also holds the public parts, + * so if the caller asked for a public key, and we got a private + * key, we can still pass it back. + */ + if (ok && ppubkey != NULL && *ppubkey == NULL) { + ok = ((*ppubkey = OSSL_STORE_INFO_get1_PKEY(info)) != NULL); + cnt_expectations -= ok; + } + break; + case OSSL_STORE_INFO_PUBKEY: + if (ppubkey != NULL && *ppubkey == NULL) { + ok = ((*ppubkey = OSSL_STORE_INFO_get1_PUBKEY(info)) != NULL); + cnt_expectations -= ok; + } + break; + case OSSL_STORE_INFO_PARAMS: + if (pparams != NULL && *pparams == NULL) { + ok = ((*pparams = OSSL_STORE_INFO_get1_PARAMS(info)) != NULL); + cnt_expectations -= ok; + } + break; + case OSSL_STORE_INFO_CERT: + if (pcert != NULL && *pcert == NULL) { + ok = (*pcert = OSSL_STORE_INFO_get1_CERT(info)) != NULL; + cnt_expectations -= ok; + } + else if (pcerts != NULL) + ok = X509_add_cert(*pcerts, + OSSL_STORE_INFO_get1_CERT(info), + X509_ADD_FLAG_DEFAULT); + ncerts += ok; + break; + case OSSL_STORE_INFO_CRL: + if (pcrl != NULL && *pcrl == NULL) { + ok = (*pcrl = OSSL_STORE_INFO_get1_CRL(info)) != NULL; + cnt_expectations -= ok; + } + else if (pcrls != NULL) + ok = sk_X509_CRL_push(*pcrls, OSSL_STORE_INFO_get1_CRL(info)); + ncrls += ok; + break; + default: + /* skip any other type */ + break; + } + OSSL_STORE_INFO_free(info); + if (!ok) { + failed = info == NULL ? NULL : OSSL_STORE_INFO_type_string(type); + BIO_printf(bio_err, "Error reading"); + break; + } + } + + end: + OSSL_STORE_close(ctx); + if (failed == NULL) { + int any = 0; + + if ((ppkey != NULL && *ppkey == NULL) + || (ppubkey != NULL && *ppubkey == NULL)) { + failed = "key"; + } else if (pparams != NULL && *pparams == NULL) { + failed = "params"; + } else if ((pcert != NULL || pcerts != NULL) && ncerts == 0) { + if (pcert == NULL) + any = 1; + failed = "cert"; + } else if ((pcrl != NULL || pcrls != NULL) && ncrls == 0) { + if (pcrl == NULL) + any = 1; + failed = "CRL"; + } + if (!suppress_decode_errors) { + if (failed != NULL) + BIO_printf(bio_err, "Could not read"); + if (any) + BIO_printf(bio_err, " any"); + } + } + if (!suppress_decode_errors && failed != NULL) { + if (desc != NULL && strstr(desc, failed) != NULL) { + BIO_printf(bio_err, " %s", desc); + } else { + BIO_printf(bio_err, " %s", failed); + if (desc != NULL) + BIO_printf(bio_err, " of %s", desc); + } + if (uri != NULL) + BIO_printf(bio_err, " from %s", uri); + BIO_printf(bio_err, "\n"); + ERR_print_errors(bio_err); + } + if (suppress_decode_errors || failed == NULL) + /* clear any spurious errors */ + ERR_clear_error(); + return failed == NULL; +} + +int load_key_certs_crls(const char *uri, int format, int maybe_stdin, + const char *pass, const char *desc, + EVP_PKEY **ppkey, EVP_PKEY **ppubkey, + EVP_PKEY **pparams, + X509 **pcert, STACK_OF(X509) **pcerts, + X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls) +{ + return load_key_certs_crls_suppress(uri, format, maybe_stdin, pass, desc, + ppkey, ppubkey, pparams, pcert, pcerts, + pcrl, pcrls, 0); } #define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) @@ -1069,13 +1181,24 @@ int set_name_ex(unsigned long *flags, const char *arg) return 1; } +int set_dateopt(unsigned long *dateopt, const char *arg) +{ + if (OPENSSL_strcasecmp(arg, "rfc_822") == 0) + *dateopt = ASN1_DTFLGS_RFC822; + else if (OPENSSL_strcasecmp(arg, "iso_8601") == 0) + *dateopt = ASN1_DTFLGS_ISO8601; + else + return 0; + return 1; +} + int set_ext_copy(int *copy_type, const char *arg) { - if (strcasecmp(arg, "none") == 0) + if (OPENSSL_strcasecmp(arg, "none") == 0) *copy_type = EXT_COPY_NONE; - else if (strcasecmp(arg, "copy") == 0) + else if (OPENSSL_strcasecmp(arg, "copy") == 0) *copy_type = EXT_COPY_ADD; - else if (strcasecmp(arg, "copyall") == 0) + else if (OPENSSL_strcasecmp(arg, "copyall") == 0) *copy_type = EXT_COPY_ALL; else return 0; @@ -1084,41 +1207,38 @@ int set_ext_copy(int *copy_type, const char *arg) int copy_extensions(X509 *x, X509_REQ *req, int copy_type) { - STACK_OF(X509_EXTENSION) *exts = NULL; - X509_EXTENSION *ext, *tmpext; - ASN1_OBJECT *obj; - int i, idx, ret = 0; - if (!x || !req || (copy_type == EXT_COPY_NONE)) + STACK_OF(X509_EXTENSION) *exts; + int i, ret = 0; + + if (x == NULL || req == NULL) + return 0; + if (copy_type == EXT_COPY_NONE) return 1; exts = X509_REQ_get_extensions(req); for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { - ext = sk_X509_EXTENSION_value(exts, i); - obj = X509_EXTENSION_get_object(ext); - idx = X509_get_ext_by_OBJ(x, obj, -1); - /* Does extension exist? */ + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); + int idx = X509_get_ext_by_OBJ(x, obj, -1); + + /* Does extension exist in target? */ if (idx != -1) { /* If normal copy don't override existing extension */ if (copy_type == EXT_COPY_ADD) continue; /* Delete all extensions of same type */ do { - tmpext = X509_get_ext(x, idx); - X509_delete_ext(x, idx); - X509_EXTENSION_free(tmpext); + X509_EXTENSION_free(X509_delete_ext(x, idx)); idx = X509_get_ext_by_OBJ(x, obj, -1); } while (idx != -1); } if (!X509_add_ext(x, ext, -1)) goto end; } - ret = 1; end: - sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); - return ret; } @@ -1158,7 +1278,7 @@ static int set_table_opts(unsigned long *flags, const char *arg, } for (ptbl = in_tbl; ptbl->name; ptbl++) { - if (strcasecmp(arg, ptbl->name) == 0) { + if (OPENSSL_strcasecmp(arg, ptbl->name) == 0) { *flags &= ~ptbl->mask; if (c) *flags |= ptbl->flag; @@ -1170,14 +1290,16 @@ static int set_table_opts(unsigned long *flags, const char *arg, return 0; } -void print_name(BIO *out, const char *title, X509_NAME *nm, - unsigned long lflags) +void print_name(BIO *out, const char *title, const X509_NAME *nm) { char *buf; char mline = 0; int indent = 0; + unsigned long lflags = get_nameopt(); - if (title) + if (out == NULL) + return; + if (title != NULL) BIO_puts(out, title); if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { mline = 1; @@ -1233,10 +1355,14 @@ void print_array(BIO *out, const char* title, int len, const unsigned char* d) BIO_printf(out, "\n};\n"); } -X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, int noCApath) +X509_STORE *setup_verify(const char *CAfile, int noCAfile, + const char *CApath, int noCApath, + const char *CAstore, int noCAstore) { X509_STORE *store = X509_STORE_new(); X509_LOOKUP *lookup; + OSSL_LIB_CTX *libctx = app_get0_libctx(); + const char *propq = app_get0_propq(); if (store == NULL) goto end; @@ -1245,13 +1371,15 @@ X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, i lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if (lookup == NULL) goto end; - if (CAfile) { - if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) { + if (CAfile != NULL) { + if (X509_LOOKUP_load_file_ex(lookup, CAfile, X509_FILETYPE_PEM, + libctx, propq) <= 0) { BIO_printf(bio_err, "Error loading file %s\n", CAfile); goto end; } } else { - X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); + X509_LOOKUP_load_file_ex(lookup, NULL, X509_FILETYPE_DEFAULT, + libctx, propq); } } @@ -1259,8 +1387,8 @@ X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, i lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if (lookup == NULL) goto end; - if (CApath) { - if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) { + if (CApath != NULL) { + if (X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM) <= 0) { BIO_printf(bio_err, "Error loading directory %s\n", CApath); goto end; } @@ -1269,72 +1397,25 @@ X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, i } } + if (CAstore != NULL || !noCAstore) { + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_store()); + if (lookup == NULL) + goto end; + if (!X509_LOOKUP_add_store_ex(lookup, CAstore, libctx, propq)) { + if (CAstore != NULL) + BIO_printf(bio_err, "Error loading store URI %s\n", CAstore); + goto end; + } + } + ERR_clear_error(); return store; end: + ERR_print_errors(bio_err); X509_STORE_free(store); return NULL; } -#ifndef OPENSSL_NO_ENGINE -/* Try to load an engine in a shareable library */ -static ENGINE *try_load_engine(const char *engine) -{ - ENGINE *e = ENGINE_by_id("dynamic"); - if (e) { - if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) - || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { - ENGINE_free(e); - e = NULL; - } - } - return e; -} -#endif - -ENGINE *setup_engine(const char *engine, int debug) -{ - ENGINE *e = NULL; - -#ifndef OPENSSL_NO_ENGINE - if (engine != NULL) { - if (strcmp(engine, "auto") == 0) { - BIO_printf(bio_err, "enabling auto ENGINE support\n"); - ENGINE_register_all_complete(); - return NULL; - } - if ((e = ENGINE_by_id(engine)) == NULL - && (e = try_load_engine(engine)) == NULL) { - BIO_printf(bio_err, "invalid engine \"%s\"\n", engine); - ERR_print_errors(bio_err); - return NULL; - } - if (debug) { - ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, bio_err, 0); - } - ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, ui_method, 0, 1); - if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { - BIO_printf(bio_err, "can't use that engine\n"); - ERR_print_errors(bio_err); - ENGINE_free(e); - return NULL; - } - - BIO_printf(bio_err, "engine \"%s\" set.\n", ENGINE_get_id(e)); - } -#endif - return e; -} - -void release_engine(ENGINE *e) -{ -#ifndef OPENSSL_NO_ENGINE - if (e != NULL) - /* Free our "structural" reference. */ - ENGINE_free(e); -#endif -} - static unsigned long index_serial_hash(const OPENSSL_CSTRING *a) { const char *n; @@ -1408,19 +1489,18 @@ BIGNUM *load_serial(const char *serialfile, int *exists, int create, } } else { if (!a2i_ASN1_INTEGER(in, ai, buf, 1024)) { - BIO_printf(bio_err, "unable to load number from %s\n", + BIO_printf(bio_err, "Unable to load number from %s\n", serialfile); goto err; } ret = ASN1_INTEGER_to_BN(ai, NULL); if (ret == NULL) { - BIO_printf(bio_err, - "error converting number from bin to BIGNUM\n"); + BIO_printf(bio_err, "Error converting number from bin to BIGNUM\n"); goto err; } } - if (ret && retai) { + if (ret != NULL && retai != NULL) { *retai = ai; ai = NULL; } @@ -1446,7 +1526,7 @@ int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial else j = strlen(serialfile) + strlen(suffix) + 1; if (j >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } @@ -1461,7 +1541,6 @@ int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial } out = BIO_new_file(buf[0], "w"); if (out == NULL) { - ERR_print_errors(bio_err); goto err; } @@ -1477,6 +1556,8 @@ int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial ai = NULL; } err: + if (!ret) + ERR_print_errors(bio_err); BIO_free_all(out); ASN1_INTEGER_free(ai); return ret; @@ -1493,7 +1574,7 @@ int rotate_serial(const char *serialfile, const char *new_suffix, if (i > j) j = i; if (j + 1 >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } #ifndef OPENSSL_SYS_VMS @@ -1509,19 +1590,20 @@ int rotate_serial(const char *serialfile, const char *new_suffix, #endif ) { BIO_printf(bio_err, - "unable to rename %s to %s\n", serialfile, buf[1]); + "Unable to rename %s to %s\n", serialfile, buf[1]); perror("reason"); goto err; } if (rename(buf[0], serialfile) < 0) { BIO_printf(bio_err, - "unable to rename %s to %s\n", buf[0], serialfile); + "Unable to rename %s to %s\n", buf[0], serialfile); perror("reason"); rename(buf[1], serialfile); goto err; } return 1; err: + ERR_print_errors(bio_err); return 0; } @@ -1562,17 +1644,14 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) #endif in = BIO_new_file(dbfile, "r"); - if (in == NULL) { - ERR_print_errors(bio_err); + if (in == NULL) goto err; - } #ifndef OPENSSL_NO_POSIX_IO BIO_get_fp(in, &dbfp); if (fstat(fileno(dbfp), &dbst) == -1) { - SYSerr(SYS_F_FSTAT, errno); - ERR_add_error_data(3, "fstat('", dbfile, "')"); - ERR_print_errors(bio_err); + ERR_raise_data(ERR_LIB_SYS, errno, + "calling fstat(%s)", dbfile); goto err; } #endif @@ -1609,6 +1688,7 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) #endif err: + ERR_print_errors(bio_err); NCONF_free(dbattr_conf); TXT_DB_free(tmpdb); BIO_free_all(in); @@ -1624,20 +1704,23 @@ int index_index(CA_DB *db) LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) { BIO_printf(bio_err, - "error creating serial number index:(%ld,%ld,%ld)\n", + "Error creating serial number index:(%ld,%ld,%ld)\n", db->db->error, db->db->arg1, db->db->arg2); - return 0; + goto err; } if (db->attributes.unique_subject && !TXT_DB_create_index(db->db, DB_name, index_name_qual, LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) { - BIO_printf(bio_err, "error creating name index:(%ld,%ld,%ld)\n", + BIO_printf(bio_err, "Error creating name index:(%ld,%ld,%ld)\n", db->db->error, db->db->arg1, db->db->arg2); - return 0; + goto err; } return 1; + err: + ERR_print_errors(bio_err); + return 0; } int save_index(const char *dbfile, const char *suffix, CA_DB *db) @@ -1648,7 +1731,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) j = strlen(dbfile) + strlen(suffix); if (j + 6 >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } #ifndef OPENSSL_SYS_VMS @@ -1663,7 +1746,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) out = BIO_new_file(buf[0], "w"); if (out == NULL) { perror(dbfile); - BIO_printf(bio_err, "unable to open '%s'\n", dbfile); + BIO_printf(bio_err, "Unable to open '%s'\n", dbfile); goto err; } j = TXT_DB_write(out, db->db); @@ -1674,7 +1757,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) out = BIO_new_file(buf[1], "w"); if (out == NULL) { perror(buf[2]); - BIO_printf(bio_err, "unable to open '%s'\n", buf[2]); + BIO_printf(bio_err, "Unable to open '%s'\n", buf[2]); goto err; } BIO_printf(out, "unique_subject = %s\n", @@ -1683,6 +1766,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) return 1; err: + ERR_print_errors(bio_err); return 0; } @@ -1697,7 +1781,7 @@ int rotate_index(const char *dbfile, const char *new_suffix, if (i > j) j = i; if (j + 6 >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } #ifndef OPENSSL_SYS_VMS @@ -1718,12 +1802,12 @@ int rotate_index(const char *dbfile, const char *new_suffix, && errno != ENOTDIR #endif ) { - BIO_printf(bio_err, "unable to rename %s to %s\n", dbfile, buf[1]); + BIO_printf(bio_err, "Unable to rename %s to %s\n", dbfile, buf[1]); perror("reason"); goto err; } if (rename(buf[0], dbfile) < 0) { - BIO_printf(bio_err, "unable to rename %s to %s\n", buf[0], dbfile); + BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[0], dbfile); perror("reason"); rename(buf[1], dbfile); goto err; @@ -1733,14 +1817,14 @@ int rotate_index(const char *dbfile, const char *new_suffix, && errno != ENOTDIR #endif ) { - BIO_printf(bio_err, "unable to rename %s to %s\n", buf[4], buf[3]); + BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[4], buf[3]); perror("reason"); rename(dbfile, buf[0]); rename(buf[1], dbfile); goto err; } if (rename(buf[2], buf[4]) < 0) { - BIO_printf(bio_err, "unable to rename %s to %s\n", buf[2], buf[4]); + BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[2], buf[4]); perror("reason"); rename(buf[3], buf[4]); rename(dbfile, buf[0]); @@ -1749,6 +1833,7 @@ int rotate_index(const char *dbfile, const char *new_suffix, } return 1; err: + ERR_print_errors(bio_err); return 0; } @@ -1784,9 +1869,11 @@ int parse_yesno(const char *str, int def) /* * name is expected to be in the format /type0=value0/type1=value1/type2=... - * where characters may be escaped by \ + * where + can be used instead of / to form multi-valued RDNs if canmulti + * and characters may be escaped by \ */ -X509_NAME *parse_name(const char *cp, long chtype, int canmulti) +X509_NAME *parse_name(const char *cp, int chtype, int canmulti, + const char *desc) { int nextismulti = 0; char *work; @@ -1794,21 +1881,26 @@ X509_NAME *parse_name(const char *cp, long chtype, int canmulti) if (*cp++ != '/') { BIO_printf(bio_err, - "name is expected to be in the format " + "%s: %s name is expected to be in the format " "/type0=value0/type1=value1/type2=... where characters may " "be escaped by \\. This name is not in that format: '%s'\n", - --cp); + opt_getprog(), desc, --cp); return NULL; } n = X509_NAME_new(); - if (n == NULL) + if (n == NULL) { + BIO_printf(bio_err, "%s: Out of memory\n", opt_getprog()); return NULL; + } work = OPENSSL_strdup(cp); - if (work == NULL) + if (work == NULL) { + BIO_printf(bio_err, "%s: Error copying %s name input\n", + opt_getprog(), desc); goto err; + } - while (*cp) { + while (*cp != '\0') { char *bp = work; char *typestr = bp; unsigned char *valstr; @@ -1817,54 +1909,64 @@ X509_NAME *parse_name(const char *cp, long chtype, int canmulti) nextismulti = 0; /* Collect the type */ - while (*cp && *cp != '=') + while (*cp != '\0' && *cp != '=') *bp++ = *cp++; + *bp++ = '\0'; if (*cp == '\0') { BIO_printf(bio_err, - "%s: Hit end of string before finding the equals.\n", - opt_getprog()); + "%s: Missing '=' after RDN type string '%s' in %s name string\n", + opt_getprog(), typestr, desc); goto err; } - *bp++ = '\0'; ++cp; /* Collect the value. */ valstr = (unsigned char *)bp; - for (; *cp && *cp != '/'; *bp++ = *cp++) { + for (; *cp != '\0' && *cp != '/'; *bp++ = *cp++) { + /* unescaped '+' symbol string signals further member of multiRDN */ if (canmulti && *cp == '+') { nextismulti = 1; break; } if (*cp == '\\' && *++cp == '\0') { BIO_printf(bio_err, - "%s: escape character at end of string\n", - opt_getprog()); + "%s: Escape character at end of %s name string\n", + opt_getprog(), desc); goto err; } } *bp++ = '\0'; /* If not at EOS (must be + or /), move forward. */ - if (*cp) + if (*cp != '\0') ++cp; /* Parse */ nid = OBJ_txt2nid(typestr); if (nid == NID_undef) { - BIO_printf(bio_err, "%s: Skipping unknown attribute \"%s\"\n", - opt_getprog(), typestr); + BIO_printf(bio_err, + "%s: Skipping unknown %s name attribute \"%s\"\n", + opt_getprog(), desc, typestr); + if (ismulti) + BIO_printf(bio_err, + "Hint: a '+' in a value string needs be escaped using '\\' else a new member of a multi-valued RDN is expected\n"); continue; } if (*valstr == '\0') { BIO_printf(bio_err, - "%s: No value provided for Subject Attribute %s, skipped\n", - opt_getprog(), typestr); + "%s: No value provided for %s name attribute \"%s\", skipped\n", + opt_getprog(), desc, typestr); continue; } if (!X509_NAME_add_entry_by_NID(n, nid, chtype, valstr, strlen((char *)valstr), - -1, ismulti ? -1 : 0)) + -1, ismulti ? -1 : 0)) { + ERR_print_errors(bio_err); + BIO_printf(bio_err, + "%s: Error adding %s name attribute \"/%s=%s\"\n", + opt_getprog(), desc, typestr ,valstr); goto err; + } } OPENSSL_free(work); @@ -1919,17 +2021,21 @@ int bio_to_mem(unsigned char **out, int maxlen, BIO *in) int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value) { - int rv; + int rv = 0; char *stmp, *vtmp = NULL; + stmp = OPENSSL_strdup(value); - if (!stmp) + if (stmp == NULL) return -1; vtmp = strchr(stmp, ':'); - if (vtmp) { - *vtmp = 0; - vtmp++; - } + if (vtmp == NULL) + goto err; + + *vtmp = 0; + vtmp++; rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp); + + err: OPENSSL_free(stmp); return rv; } @@ -2047,6 +2153,209 @@ void print_cert_checks(BIO *bio, X509 *x, } } +static int do_pkey_ctx_init(EVP_PKEY_CTX *pkctx, STACK_OF(OPENSSL_STRING) *opts) +{ + int i; + + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (pkey_ctrl_string(pkctx, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + return 0; + } + } + + return 1; +} + +static int do_x509_init(X509 *x, STACK_OF(OPENSSL_STRING) *opts) +{ + int i; + + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (x509_ctrl_string(x, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + return 0; + } + } + + return 1; +} + +static int do_x509_req_init(X509_REQ *x, STACK_OF(OPENSSL_STRING) *opts) +{ + int i; + + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (x509_req_ctrl_string(x, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + return 0; + } + } + + return 1; +} + +static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, + const char *md, STACK_OF(OPENSSL_STRING) *sigopts) +{ + EVP_PKEY_CTX *pkctx = NULL; + char def_md[80]; + + if (ctx == NULL) + return 0; + /* + * EVP_PKEY_get_default_digest_name() returns 2 if the digest is mandatory + * for this algorithm. + */ + if (EVP_PKEY_get_default_digest_name(pkey, def_md, sizeof(def_md)) == 2 + && strcmp(def_md, "UNDEF") == 0) { + /* The signing algorithm requires there to be no digest */ + md = NULL; + } + + return EVP_DigestSignInit_ex(ctx, &pkctx, md, app_get0_libctx(), + app_get0_propq(), pkey, NULL) + && do_pkey_ctx_init(pkctx, sigopts); +} + +static int adapt_keyid_ext(X509 *cert, X509V3_CTX *ext_ctx, + const char *name, const char *value, int add_default) +{ + const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert); + X509_EXTENSION *new_ext = X509V3_EXT_nconf(NULL, ext_ctx, name, value); + int idx, rv = 0; + + if (new_ext == NULL) + return rv; + + idx = X509v3_get_ext_by_OBJ(exts, X509_EXTENSION_get_object(new_ext), -1); + if (idx >= 0) { + X509_EXTENSION *found_ext = X509v3_get_ext(exts, idx); + ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(found_ext); + int disabled = ASN1_STRING_length(data) <= 2; /* config said "none" */ + + if (disabled) { + X509_delete_ext(cert, idx); + X509_EXTENSION_free(found_ext); + } /* else keep existing key identifier, which might be outdated */ + rv = 1; + } else { + rv = !add_default || X509_add_ext(cert, new_ext, -1); + } + X509_EXTENSION_free(new_ext); + return rv; +} + +/* Ensure RFC 5280 compliance, adapt keyIDs as needed, and sign the cert info */ +int do_X509_sign(X509 *cert, EVP_PKEY *pkey, const char *md, + STACK_OF(OPENSSL_STRING) *sigopts, X509V3_CTX *ext_ctx) +{ + const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert); + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + int self_sign; + int rv = 0; + + if (sk_X509_EXTENSION_num(exts /* may be NULL */) > 0) { + /* Prevent X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3 */ + if (!X509_set_version(cert, X509_VERSION_3)) + goto end; + + /* + * Add default SKID before such that default AKID can make use of it + * in case the certificate is self-signed + */ + /* Prevent X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER */ + if (!adapt_keyid_ext(cert, ext_ctx, "subjectKeyIdentifier", "hash", 1)) + goto end; + /* Prevent X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER */ + ERR_set_mark(); + self_sign = X509_check_private_key(cert, pkey); + ERR_pop_to_mark(); + if (!adapt_keyid_ext(cert, ext_ctx, "authorityKeyIdentifier", + "keyid, issuer", !self_sign)) + goto end; + } + + if (mctx != NULL && do_sign_init(mctx, pkey, md, sigopts) > 0) + rv = (X509_sign_ctx(cert, mctx) > 0); + end: + EVP_MD_CTX_free(mctx); + return rv; +} + +/* Sign the certificate request info */ +int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const char *md, + STACK_OF(OPENSSL_STRING) *sigopts) +{ + int rv = 0; + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + + if (do_sign_init(mctx, pkey, md, sigopts) > 0) + rv = (X509_REQ_sign_ctx(x, mctx) > 0); + EVP_MD_CTX_free(mctx); + return rv; +} + +/* Sign the CRL info */ +int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const char *md, + STACK_OF(OPENSSL_STRING) *sigopts) +{ + int rv = 0; + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + + if (do_sign_init(mctx, pkey, md, sigopts) > 0) + rv = (X509_CRL_sign_ctx(x, mctx) > 0); + EVP_MD_CTX_free(mctx); + return rv; +} + +/* + * do_X509_verify returns 1 if the signature is valid, + * 0 if the signature check fails, or -1 if error occurs. + */ +int do_X509_verify(X509 *x, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *vfyopts) +{ + int rv = 0; + + if (do_x509_init(x, vfyopts) > 0) + rv = X509_verify(x, pkey); + else + rv = -1; + return rv; +} + +/* + * do_X509_REQ_verify returns 1 if the signature is valid, + * 0 if the signature check fails, or -1 if error occurs. + */ +int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey, + STACK_OF(OPENSSL_STRING) *vfyopts) +{ + int rv = 0; + + if (do_x509_req_init(x, vfyopts) > 0) + rv = X509_REQ_verify_ex(x, pkey, + app_get0_libctx(), app_get0_propq()); + else + rv = -1; + return rv; +} + /* Get first http URL from a DIST_POINT structure */ static const char *get_dp_url(DIST_POINT *dp) @@ -2063,7 +2372,8 @@ static const char *get_dp_url(DIST_POINT *dp) uri = GENERAL_NAME_get0_value(gen, >ype); if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6) { const char *uptr = (const char *)ASN1_STRING_get0_data(uri); - if (strncmp(uptr, "http://", 7) == 0) + + if (IS_HTTP(uptr)) /* can/should not use HTTPS here */ return uptr; } } @@ -2082,19 +2392,19 @@ static X509_CRL *load_crl_crldp(STACK_OF(DIST_POINT) *crldp) for (i = 0; i < sk_DIST_POINT_num(crldp); i++) { DIST_POINT *dp = sk_DIST_POINT_value(crldp, i); urlptr = get_dp_url(dp); - if (urlptr) - return load_crl(urlptr, FORMAT_HTTP); + if (urlptr != NULL) + return load_crl(urlptr, FORMAT_UNDEF, 0, "CRL via CDP"); } return NULL; } /* - * Example of downloading CRLs from CRLDP: not usable for real world as it - * always downloads, doesn't support non-blocking I/O and doesn't cache - * anything. + * Example of downloading CRLs from CRLDP: + * not usable for real world as it always downloads and doesn't cache anything. */ -static STACK_OF(X509_CRL) *crls_http_cb(X509_STORE_CTX *ctx, X509_NAME *nm) +static STACK_OF(X509_CRL) *crls_http_cb(const X509_STORE_CTX *ctx, + const X509_NAME *nm) { X509 *x; STACK_OF(X509_CRL) *crls = NULL; @@ -2127,6 +2437,184 @@ void store_setup_crl_download(X509_STORE *st) X509_STORE_set_lookup_crls_cb(st, crls_http_cb); } +#ifndef OPENSSL_NO_SOCK +static const char *tls_error_hint(void) +{ + unsigned long err = ERR_peek_error(); + + if (ERR_GET_LIB(err) != ERR_LIB_SSL) + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) != ERR_LIB_SSL) + return NULL; + + switch (ERR_GET_REASON(err)) { + case SSL_R_WRONG_VERSION_NUMBER: + return "The server does not support (a suitable version of) TLS"; + case SSL_R_UNKNOWN_PROTOCOL: + return "The server does not support HTTPS"; + case SSL_R_CERTIFICATE_VERIFY_FAILED: + return "Cannot authenticate server via its TLS certificate, likely due to mismatch with our trusted TLS certs or missing revocation status"; + case SSL_AD_REASON_OFFSET + TLS1_AD_UNKNOWN_CA: + return "Server did not accept our TLS certificate, likely due to mismatch with server's trust anchor or missing revocation status"; + case SSL_AD_REASON_OFFSET + SSL3_AD_HANDSHAKE_FAILURE: + return "TLS handshake failure. Possibly the server requires our TLS certificate but did not receive it"; + default: /* no error or no hint available for error */ + return NULL; + } +} + +/* HTTP callback function that supports TLS connection also via HTTPS proxy */ +BIO *app_http_tls_cb(BIO *bio, void *arg, int connect, int detail) +{ + APP_HTTP_TLS_INFO *info = (APP_HTTP_TLS_INFO *)arg; + SSL_CTX *ssl_ctx = info->ssl_ctx; + + if (ssl_ctx == NULL) /* not using TLS */ + return bio; + if (connect) { + SSL *ssl; + BIO *sbio = NULL; + + /* adapt after fixing callback design flaw, see #17088 */ + if ((info->use_proxy + && !OSSL_HTTP_proxy_connect(bio, info->server, info->port, + NULL, NULL, /* no proxy credentials */ + info->timeout, bio_err, opt_getprog())) + || (sbio = BIO_new(BIO_f_ssl())) == NULL) { + return NULL; + } + if (ssl_ctx == NULL || (ssl = SSL_new(ssl_ctx)) == NULL) { + BIO_free(sbio); + return NULL; + } + + /* adapt after fixing callback design flaw, see #17088 */ + SSL_set_tlsext_host_name(ssl, info->server); /* not critical to do */ + + SSL_set_connect_state(ssl); + BIO_set_ssl(sbio, ssl, BIO_CLOSE); + + bio = BIO_push(sbio, bio); + } + if (!connect) { + const char *hint; + BIO *cbio; + + if (!detail) { /* disconnecting after error */ + hint = tls_error_hint(); + if (hint != NULL) + ERR_add_error_data(2, " : ", hint); + } + if (ssl_ctx != NULL) { + (void)ERR_set_mark(); + BIO_ssl_shutdown(bio); + cbio = BIO_pop(bio); /* connect+HTTP BIO */ + BIO_free(bio); /* SSL BIO */ + (void)ERR_pop_to_mark(); /* hide SSL_R_READ_BIO_NOT_SET etc. */ + bio = cbio; + } + } + return bio; +} + +void APP_HTTP_TLS_INFO_free(APP_HTTP_TLS_INFO *info) +{ + if (info != NULL) { + SSL_CTX_free(info->ssl_ctx); + OPENSSL_free(info); + } +} + +ASN1_VALUE *app_http_get_asn1(const char *url, const char *proxy, + const char *no_proxy, SSL_CTX *ssl_ctx, + const STACK_OF(CONF_VALUE) *headers, + long timeout, const char *expected_content_type, + const ASN1_ITEM *it) +{ + APP_HTTP_TLS_INFO info; + char *server; + char *port; + int use_ssl; + BIO *mem; + ASN1_VALUE *resp = NULL; + + if (url == NULL || it == NULL) { + ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (!OSSL_HTTP_parse_url(url, &use_ssl, NULL /* userinfo */, &server, &port, + NULL /* port_num, */, NULL, NULL, NULL)) + return NULL; + if (use_ssl && ssl_ctx == NULL) { + ERR_raise_data(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER, + "missing SSL_CTX"); + goto end; + } + if (!use_ssl && ssl_ctx != NULL) { + ERR_raise_data(ERR_LIB_HTTP, ERR_R_PASSED_INVALID_ARGUMENT, + "SSL_CTX given but use_ssl == 0"); + goto end; + } + + info.server = server; + info.port = port; + info.use_proxy = /* workaround for callback design flaw, see #17088 */ + OSSL_HTTP_adapt_proxy(proxy, no_proxy, server, use_ssl) != NULL; + info.timeout = timeout; + info.ssl_ctx = ssl_ctx; + mem = OSSL_HTTP_get(url, proxy, no_proxy, NULL /* bio */, NULL /* rbio */, + app_http_tls_cb, &info, 0 /* buf_size */, headers, + expected_content_type, 1 /* expect_asn1 */, + OSSL_HTTP_DEFAULT_MAX_RESP_LEN, timeout); + resp = ASN1_item_d2i_bio(it, mem, NULL); + BIO_free(mem); + + end: + OPENSSL_free(server); + OPENSSL_free(port); + return resp; + +} + +ASN1_VALUE *app_http_post_asn1(const char *host, const char *port, + const char *path, const char *proxy, + const char *no_proxy, SSL_CTX *ssl_ctx, + const STACK_OF(CONF_VALUE) *headers, + const char *content_type, + ASN1_VALUE *req, const ASN1_ITEM *req_it, + const char *expected_content_type, + long timeout, const ASN1_ITEM *rsp_it) +{ + int use_ssl = ssl_ctx != NULL; + APP_HTTP_TLS_INFO info; + BIO *rsp, *req_mem = ASN1_item_i2d_mem_bio(req_it, req); + ASN1_VALUE *res; + + if (req_mem == NULL) + return NULL; + + info.server = host; + info.port = port; + info.use_proxy = /* workaround for callback design flaw, see #17088 */ + OSSL_HTTP_adapt_proxy(proxy, no_proxy, host, use_ssl) != NULL; + info.timeout = timeout; + info.ssl_ctx = ssl_ctx; + rsp = OSSL_HTTP_transfer(NULL, host, port, path, use_ssl, + proxy, no_proxy, NULL /* bio */, NULL /* rbio */, + app_http_tls_cb, &info, + 0 /* buf_size */, headers, content_type, req_mem, + expected_content_type, 1 /* expect_asn1 */, + OSSL_HTTP_DEFAULT_MAX_RESP_LEN, timeout, + 0 /* keep_alive */); + BIO_free(req_mem); + res = ASN1_item_d2i_bio(rsp_it, rsp, NULL); + BIO_free(rsp); + return res; +} + +#endif + /* * Platform-specific sections */ @@ -2277,40 +2765,6 @@ double app_tminterval(int stop, int usertime) return ret; } -#elif defined(OPENSSL_SYSTEM_VMS) -# include <time.h> -# include <times.h> - -double app_tminterval(int stop, int usertime) -{ - static clock_t tmstart; - double ret = 0; - clock_t now; -# ifdef __TMS - struct tms rus; - - now = times(&rus); - if (usertime) - now = rus.tms_utime; -# else - if (usertime) - now = clock(); /* sum of user and kernel times */ - else { - struct timeval tv; - gettimeofday(&tv, NULL); - now = (clock_t)((unsigned long long)tv.tv_sec * CLK_TCK + - (unsigned long long)tv.tv_usec * (1000000 / CLK_TCK) - ); - } -# endif - if (stop == TM_START) - tmstart = now; - else - ret = (now - tmstart) / (double)(CLK_TCK); - - return ret; -} - #elif defined(_SC_CLK_TCK) /* by means of unistd.h */ # include <sys/times.h> @@ -2369,56 +2823,10 @@ int app_access(const char* name, int flag) #endif } -/* app_isdir section */ -#ifdef _WIN32 int app_isdir(const char *name) { - DWORD attr; -# if defined(UNICODE) || defined(_UNICODE) - size_t i, len_0 = strlen(name) + 1; - WCHAR tempname[MAX_PATH]; - - if (len_0 > MAX_PATH) - return -1; - -# if !defined(_WIN32_WCE) || _WIN32_WCE>=101 - if (!MultiByteToWideChar(CP_ACP, 0, name, len_0, tempname, MAX_PATH)) -# endif - for (i = 0; i < len_0; i++) - tempname[i] = (WCHAR)name[i]; - - attr = GetFileAttributes(tempname); -# else - attr = GetFileAttributes(name); -# endif - if (attr == INVALID_FILE_ATTRIBUTES) - return -1; - return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0); + return opt_isdir(name); } -#else -# include <sys/stat.h> -# ifndef S_ISDIR -# if defined(_S_IFMT) && defined(_S_IFDIR) -# define S_ISDIR(a) (((a) & _S_IFMT) == _S_IFDIR) -# else -# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) -# endif -# endif - -int app_isdir(const char *name) -{ -# if defined(S_ISDIR) - struct stat st; - - if (stat(name, &st) == 0) - return S_ISDIR(st.st_mode); - else - return -1; -# else - return -1; -# endif -} -#endif /* raw_read|write section */ #if defined(__VMS) @@ -2468,6 +2876,11 @@ int raw_read_stdin(void *buf, int siz) return recv(fileno_stdin(), buf, siz, 0); } #else +# if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_read)> +# endif +# endif int raw_read_stdin(void *buf, int siz) { return read(fileno_stdin(), buf, siz); @@ -2483,7 +2896,22 @@ int raw_write_stdout(const void *buf, int siz) else return -1; } +#elif defined(OPENSSL_SYS_TANDEM) && defined(OPENSSL_THREADS) && defined(_SPT_MODEL_) +# if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_write)> +# endif +# endif +int raw_write_stdout(const void *buf,int siz) +{ + return write(fileno(stdout),(void*)buf,siz); +} #else +# if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_write)> +# endif +# endif int raw_write_stdout(const void *buf, int siz) { return write(fileno_stdout(), buf, siz); @@ -2491,41 +2919,36 @@ int raw_write_stdout(const void *buf, int siz) #endif /* - * Centralized handling if input and output files with format specification + * Centralized handling of input and output files with format specification * The format is meant to show what the input and output is supposed to be, * and is therefore a show of intent more than anything else. However, it - * does impact behavior on some platform, such as differentiating between + * does impact behavior on some platforms, such as differentiating between * text and binary input/output on non-Unix platforms */ -static int istext(int format) -{ - return (format & B_FORMAT_TEXT) == B_FORMAT_TEXT; -} - BIO *dup_bio_in(int format) { return BIO_new_fp(stdin, - BIO_NOCLOSE | (istext(format) ? BIO_FP_TEXT : 0)); + BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0)); } -static BIO_METHOD *prefix_method = NULL; - BIO *dup_bio_out(int format) { BIO *b = BIO_new_fp(stdout, - BIO_NOCLOSE | (istext(format) ? BIO_FP_TEXT : 0)); + BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0)); void *prefix = NULL; + if (b == NULL) + return NULL; + #ifdef OPENSSL_SYS_VMS - if (istext(format)) + if (FMT_istext(format)) b = BIO_push(BIO_new(BIO_f_linebuffer()), b); #endif - if (istext(format) && (prefix = getenv("HARNESS_OSSL_PREFIX")) != NULL) { - if (prefix_method == NULL) - prefix_method = apps_bf_prefix(); - b = BIO_push(BIO_new(prefix_method), b); - BIO_ctrl(b, PREFIX_CTRL_SET_PREFIX, 0, prefix); + if (FMT_istext(format) + && (prefix = getenv("HARNESS_OSSL_PREFIX")) != NULL) { + b = BIO_push(BIO_new(BIO_f_prefix()), b); + BIO_set_prefix(b, prefix); } return b; @@ -2534,20 +2957,14 @@ BIO *dup_bio_out(int format) BIO *dup_bio_err(int format) { BIO *b = BIO_new_fp(stderr, - BIO_NOCLOSE | (istext(format) ? BIO_FP_TEXT : 0)); + BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0)); #ifdef OPENSSL_SYS_VMS - if (istext(format)) + if (b != NULL && FMT_istext(format)) b = BIO_push(BIO_new(BIO_f_linebuffer()), b); #endif return b; } -void destroy_prefix_method(void) -{ - BIO_meth_free(prefix_method); - prefix_method = NULL; -} - void unbuffer(FILE *fp) { /* @@ -2573,11 +2990,11 @@ static const char *modestr(char mode, int format) switch (mode) { case 'a': - return istext(format) ? "a" : "ab"; + return FMT_istext(format) ? "a" : "ab"; case 'r': - return istext(format) ? "r" : "rb"; + return FMT_istext(format) ? "r" : "rb"; case 'w': - return istext(format) ? "w" : "wb"; + return FMT_istext(format) ? "w" : "wb"; } /* The assert above should make sure we never reach this point */ return NULL; @@ -2603,28 +3020,32 @@ BIO *bio_open_owner(const char *filename, int format, int private) { FILE *fp = NULL; BIO *b = NULL; - int fd = -1, bflags, mode, textmode; + int textmode, bflags; +#ifndef OPENSSL_NO_POSIX_IO + int fd = -1, mode; +#endif if (!private || filename == NULL || strcmp(filename, "-") == 0) return bio_open_default(filename, 'w', format); + textmode = FMT_istext(format); +#ifndef OPENSSL_NO_POSIX_IO mode = O_WRONLY; -#ifdef O_CREAT +# ifdef O_CREAT mode |= O_CREAT; -#endif -#ifdef O_TRUNC +# endif +# ifdef O_TRUNC mode |= O_TRUNC; -#endif - textmode = istext(format); +# endif if (!textmode) { -#ifdef O_BINARY +# ifdef O_BINARY mode |= O_BINARY; -#elif defined(_O_BINARY) +# elif defined(_O_BINARY) mode |= _O_BINARY; -#endif +# endif } -#ifdef OPENSSL_SYS_VMS +# ifdef OPENSSL_SYS_VMS /* VMS doesn't have O_BINARY, it just doesn't make sense. But, * it still needs to know that we're going binary, or fdopen() * will fail with "invalid argument"... so we tell VMS what the @@ -2633,18 +3054,22 @@ BIO *bio_open_owner(const char *filename, int format, int private) if (!textmode) fd = open(filename, mode, 0600, "ctx=bin"); else -#endif +# endif fd = open(filename, mode, 0600); if (fd < 0) goto err; fp = fdopen(fd, modestr('w', format)); +#else /* OPENSSL_NO_POSIX_IO */ + /* Have stdio but not Posix IO, do the best we can */ + fp = fopen(filename, modestr('w', format)); +#endif /* OPENSSL_NO_POSIX_IO */ if (fp == NULL) goto err; bflags = BIO_CLOSE; if (textmode) bflags |= BIO_FP_TEXT; b = BIO_new_fp(fp, bflags); - if (b) + if (b != NULL) return b; err: @@ -2652,10 +3077,12 @@ BIO *bio_open_owner(const char *filename, int format, int private) opt_getprog(), filename, strerror(errno)); ERR_print_errors(bio_err); /* If we have fp, then fdopen took over fd, so don't close both. */ - if (fp) + if (fp != NULL) fclose(fp); +#ifndef OPENSSL_NO_POSIX_IO else if (fd >= 0) close(fd); +#endif return NULL; } @@ -2684,7 +3111,7 @@ static BIO *bio_open_default_(const char *filename, char mode, int format, if (ret != NULL) return ret; BIO_printf(bio_err, - "Can't open %s for %s, %s\n", + "Can't open \"%s\" for %s, %s\n", filename, modeverb(mode), strerror(errno)); } ERR_print_errors(bio_err); @@ -2787,6 +3214,57 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, return 1; } +int set_crl_lastupdate(X509_CRL *crl, const char *lastupdate) +{ + int ret = 0; + ASN1_TIME *tm = ASN1_TIME_new(); + + if (tm == NULL) + goto end; + + if (lastupdate == NULL) { + if (X509_gmtime_adj(tm, 0) == NULL) + goto end; + } else { + if (!ASN1_TIME_set_string_X509(tm, lastupdate)) + goto end; + } + + if (!X509_CRL_set1_lastUpdate(crl, tm)) + goto end; + + ret = 1; +end: + ASN1_TIME_free(tm); + return ret; +} + +int set_crl_nextupdate(X509_CRL *crl, const char *nextupdate, + long days, long hours, long secs) +{ + int ret = 0; + ASN1_TIME *tm = ASN1_TIME_new(); + + if (tm == NULL) + goto end; + + if (nextupdate == NULL) { + if (X509_time_adj_ex(tm, days, hours * 60 * 60 + secs, NULL) == NULL) + goto end; + } else { + if (!ASN1_TIME_set_string_X509(tm, nextupdate)) + goto end; + } + + if (!X509_CRL_set1_nextUpdate(crl, tm)) + goto end; + + ret = 1; +end: + ASN1_TIME_free(tm); + return ret; +} + void make_uppercase(char *string) { int i; @@ -2794,3 +3272,118 @@ void make_uppercase(char *string) for (i = 0; string[i] != '\0'; i++) string[i] = toupper((unsigned char)string[i]); } + +/* This function is defined here due to visibility of bio_err */ +int opt_printf_stderr(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = BIO_vprintf(bio_err, fmt, ap); + va_end(ap); + return ret; +} + +OSSL_PARAM *app_params_new_from_opts(STACK_OF(OPENSSL_STRING) *opts, + const OSSL_PARAM *paramdefs) +{ + OSSL_PARAM *params = NULL; + size_t sz = (size_t)sk_OPENSSL_STRING_num(opts); + size_t params_n; + char *opt = "", *stmp, *vtmp = NULL; + int found = 1; + + if (opts == NULL) + return NULL; + + params = OPENSSL_zalloc(sizeof(OSSL_PARAM) * (sz + 1)); + if (params == NULL) + return NULL; + + for (params_n = 0; params_n < sz; params_n++) { + opt = sk_OPENSSL_STRING_value(opts, (int)params_n); + if ((stmp = OPENSSL_strdup(opt)) == NULL + || (vtmp = strchr(stmp, ':')) == NULL) + goto err; + /* Replace ':' with 0 to terminate the string pointed to by stmp */ + *vtmp = 0; + /* Skip over the separator so that vmtp points to the value */ + vtmp++; + if (!OSSL_PARAM_allocate_from_text(¶ms[params_n], paramdefs, + stmp, vtmp, strlen(vtmp), &found)) + goto err; + OPENSSL_free(stmp); + } + params[params_n] = OSSL_PARAM_construct_end(); + return params; +err: + OPENSSL_free(stmp); + BIO_printf(bio_err, "Parameter %s '%s'\n", found ? "error" : "unknown", + opt); + ERR_print_errors(bio_err); + app_params_free(params); + return NULL; +} + +void app_params_free(OSSL_PARAM *params) +{ + int i; + + if (params != NULL) { + for (i = 0; params[i].key != NULL; ++i) + OPENSSL_free(params[i].data); + OPENSSL_free(params); + } +} + +EVP_PKEY *app_keygen(EVP_PKEY_CTX *ctx, const char *alg, int bits, int verbose) +{ + EVP_PKEY *res = NULL; + + if (verbose && alg != NULL) { + BIO_printf(bio_err, "Generating %s key", alg); + if (bits > 0) + BIO_printf(bio_err, " with %d bits\n", bits); + else + BIO_printf(bio_err, "\n"); + } + if (!RAND_status()) + BIO_printf(bio_err, "Warning: generating random key material may take a long time\n" + "if the system has a poor entropy source\n"); + if (EVP_PKEY_keygen(ctx, &res) <= 0) + app_bail_out("%s: Error generating %s key\n", opt_getprog(), + alg != NULL ? alg : "asymmetric"); + return res; +} + +EVP_PKEY *app_paramgen(EVP_PKEY_CTX *ctx, const char *alg) +{ + EVP_PKEY *res = NULL; + + if (!RAND_status()) + BIO_printf(bio_err, "Warning: generating random key parameters may take a long time\n" + "if the system has a poor entropy source\n"); + if (EVP_PKEY_paramgen(ctx, &res) <= 0) + app_bail_out("%s: Generating %s key parameters failed\n", + opt_getprog(), alg != NULL ? alg : "asymmetric"); + return res; +} + +/* + * Return non-zero if the legacy path is still an option. + * This decision is based on the global command line operations and the + * behaviour thus far. + */ +int opt_legacy_okay(void) +{ + int provider_options = opt_provider_option_given(); + int libctx = app_get0_libctx() != NULL || app_get0_propq() != NULL; + /* + * Having a provider option specified or a custom library context or + * property query, is a sure sign we're not using legacy. + */ + if (provider_options || libctx) + return 0; + return 1; +} diff --git a/apps/lib/apps_ui.c b/apps/lib/apps_ui.c new file mode 100644 index 000000000000..00e0ba5d9996 --- /dev/null +++ b/apps/lib/apps_ui.c @@ -0,0 +1,223 @@ +/* + * Copyright 1995-2020 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 <string.h> +#include <openssl/err.h> +#include <openssl/ui.h> +#include "apps_ui.h" + +static UI_METHOD *ui_method = NULL; +static const UI_METHOD *ui_base_method = NULL; + +static int ui_open(UI *ui) +{ + int (*opener)(UI *ui) = UI_method_get_opener(ui_base_method); + + if (opener != NULL) + return opener(ui); + return 1; +} + +static int ui_read(UI *ui, UI_STRING *uis) +{ + int (*reader)(UI *ui, UI_STRING *uis) = NULL; + + if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD + && UI_get0_user_data(ui)) { + switch (UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + { + const char *password = + ((PW_CB_DATA *)UI_get0_user_data(ui))->password; + + if (password != NULL) { + UI_set_result(ui, uis, password); + return 1; + } + } + break; + case UIT_NONE: + case UIT_BOOLEAN: + case UIT_INFO: + case UIT_ERROR: + break; + } + } + + reader = UI_method_get_reader(ui_base_method); + if (reader != NULL) + return reader(ui, uis); + /* Default to the empty password if we've got nothing better */ + UI_set_result(ui, uis, ""); + return 1; +} + +static int ui_write(UI *ui, UI_STRING *uis) +{ + int (*writer)(UI *ui, UI_STRING *uis) = NULL; + + if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD + && UI_get0_user_data(ui)) { + switch (UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + { + const char *password = + ((PW_CB_DATA *)UI_get0_user_data(ui))->password; + + if (password != NULL) + return 1; + } + break; + case UIT_NONE: + case UIT_BOOLEAN: + case UIT_INFO: + case UIT_ERROR: + break; + } + } + + writer = UI_method_get_writer(ui_base_method); + if (writer != NULL) + return writer(ui, uis); + return 1; +} + +static int ui_close(UI *ui) +{ + int (*closer)(UI *ui) = UI_method_get_closer(ui_base_method); + + if (closer != NULL) + return closer(ui); + return 1; +} + +/* object_name defaults to prompt_info from ui user data if present */ +static char *ui_prompt_construct(UI *ui, const char *phrase_desc, + const char *object_name) +{ + PW_CB_DATA *cb_data = (PW_CB_DATA *)UI_get0_user_data(ui); + + if (phrase_desc == NULL) + phrase_desc = "pass phrase"; + if (object_name == NULL && cb_data != NULL) + object_name = cb_data->prompt_info; + return UI_construct_prompt(NULL, phrase_desc, object_name); +} + +int set_base_ui_method(const UI_METHOD *ui_meth) +{ + if (ui_meth == NULL) + ui_meth = UI_null(); + ui_base_method = ui_meth; + return 1; +} + +int setup_ui_method(void) +{ + ui_base_method = UI_null(); +#ifndef OPENSSL_NO_UI_CONSOLE + ui_base_method = UI_OpenSSL(); +#endif + ui_method = UI_create_method("OpenSSL application user interface"); + return ui_method != NULL + && 0 == UI_method_set_opener(ui_method, ui_open) + && 0 == UI_method_set_reader(ui_method, ui_read) + && 0 == UI_method_set_writer(ui_method, ui_write) + && 0 == UI_method_set_closer(ui_method, ui_close) + && 0 == UI_method_set_prompt_constructor(ui_method, + ui_prompt_construct); +} + +void destroy_ui_method(void) +{ + if (ui_method != NULL) { + UI_destroy_method(ui_method); + ui_method = NULL; + } +} + +const UI_METHOD *get_ui_method(void) +{ + return ui_method; +} + +static void *ui_malloc(int sz, const char *what) +{ + void *vp = OPENSSL_malloc(sz); + + if (vp == NULL) { + BIO_printf(bio_err, "Could not allocate %d bytes for %s\n", sz, what); + ERR_print_errors(bio_err); + exit(1); + } + return vp; +} + +int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data) +{ + int res = 0; + UI *ui; + int ok = 0; + char *buff = NULL; + int ui_flags = 0; + const char *prompt_info = NULL; + char *prompt; + + if ((ui = UI_new_method(ui_method)) == NULL) + return 0; + + if (cb_data != NULL && cb_data->prompt_info != NULL) + prompt_info = cb_data->prompt_info; + prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); + if (prompt == NULL) { + BIO_printf(bio_err, "Out of memory\n"); + UI_free(ui); + return 0; + } + + ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD; + UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); + + /* We know that there is no previous user data to return to us */ + (void)UI_add_user_data(ui, cb_data); + + ok = UI_add_input_string(ui, prompt, ui_flags, buf, + PW_MIN_LENGTH, bufsiz - 1); + + if (ok >= 0 && verify) { + buff = ui_malloc(bufsiz, "password buffer"); + ok = UI_add_verify_string(ui, prompt, ui_flags, buff, + PW_MIN_LENGTH, bufsiz - 1, buf); + } + if (ok >= 0) + do { + ok = UI_process(ui); + } while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); + + OPENSSL_clear_free(buff, (unsigned int)bufsiz); + + if (ok >= 0) + res = strlen(buf); + if (ok == -1) { + BIO_printf(bio_err, "User interface error\n"); + ERR_print_errors(bio_err); + OPENSSL_cleanse(buf, (unsigned int)bufsiz); + res = 0; + } + if (ok == -2) { + BIO_printf(bio_err, "aborted!\n"); + OPENSSL_cleanse(buf, (unsigned int)bufsiz); + res = 0; + } + UI_free(ui); + OPENSSL_free(prompt); + return res; +} diff --git a/apps/lib/build.info b/apps/lib/build.info new file mode 100644 index 000000000000..923ef5d92b83 --- /dev/null +++ b/apps/lib/build.info @@ -0,0 +1,23 @@ +# Auxiliary program source +IF[{- $config{target} =~ /^(?:VC-|mingw|BC-)/ -}] + # It's called 'init', but doesn't have much 'init' in it... + $AUXLIBAPPSSRC=win32_init.c +ENDIF +IF[{- $config{target} =~ /^vms-/ -}] + $AUXLIBAPPSSRC=vms_term_sock.c vms_decc_argv.c +ENDIF + +# Source for libapps +$LIBAPPSSRC=apps.c apps_ui.c opt.c fmt.c s_cb.c s_socket.c app_rand.c \ + columns.c app_params.c names.c app_provider.c app_x509.c http_server.c \ + engine.c engine_loader.c app_libctx.c + +IF[{- !$disabled{apps} -}] + LIBS{noinst}=../libapps.a + SOURCE[../libapps.a]=$LIBAPPSSRC $AUXLIBAPPSSRC + INCLUDE[../libapps.a]=../.. ../../include ../include +ENDIF + +IF[{- !$disabled{srp} -}] + SOURCE[../libapps.a]=tlssrp_depr.c +ENDIF diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c new file mode 100644 index 000000000000..b37f3dd3d89c --- /dev/null +++ b/apps/lib/cmp_mock_srv.c @@ -0,0 +1,450 @@ +/* + * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Siemens AG 2018-2020 + * + * 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 atf + * https://www.openssl.org/source/license.html + */ + +#include "apps.h" +#include "cmp_mock_srv.h" + +#include <openssl/cmp.h> +#include <openssl/err.h> +#include <openssl/cmperr.h> + +/* the context for the CMP mock server */ +typedef struct +{ + X509 *certOut; /* certificate to be returned in cp/ip/kup msg */ + STACK_OF(X509) *chainOut; /* chain of certOut to add to extraCerts field */ + STACK_OF(X509) *caPubsOut; /* certs to return in caPubs field of ip msg */ + OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */ + int sendError; /* send error response also on valid requests */ + OSSL_CMP_MSG *certReq; /* ir/cr/p10cr/kur remembered while polling */ + int certReqId; /* id of last ir/cr/kur, used for polling */ + int pollCount; /* number of polls before actual cert response */ + int curr_pollCount; /* number of polls so far for current request */ + int checkAfterTime; /* time the client should wait between polling */ +} mock_srv_ctx; + + +static void mock_srv_ctx_free(mock_srv_ctx *ctx) +{ + if (ctx == NULL) + return; + + OSSL_CMP_PKISI_free(ctx->statusOut); + X509_free(ctx->certOut); + sk_X509_pop_free(ctx->chainOut, X509_free); + sk_X509_pop_free(ctx->caPubsOut, X509_free); + OSSL_CMP_MSG_free(ctx->certReq); + OPENSSL_free(ctx); +} + +static mock_srv_ctx *mock_srv_ctx_new(void) +{ + mock_srv_ctx *ctx = OPENSSL_zalloc(sizeof(mock_srv_ctx)); + + if (ctx == NULL) + goto err; + + if ((ctx->statusOut = OSSL_CMP_PKISI_new()) == NULL) + goto err; + + ctx->certReqId = -1; + + /* all other elements are initialized to 0 or NULL, respectively */ + return ctx; + err: + mock_srv_ctx_free(ctx); + return NULL; +} + +int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (cert == NULL || X509_up_ref(cert)) { + X509_free(ctx->certOut); + ctx->certOut = cert; + return 1; + } + return 0; +} + +int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *chain) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + STACK_OF(X509) *chain_copy = NULL; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (chain != NULL && (chain_copy = X509_chain_up_ref(chain)) == NULL) + return 0; + sk_X509_pop_free(ctx->chainOut, X509_free); + ctx->chainOut = chain_copy; + return 1; +} + +int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *caPubs) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + STACK_OF(X509) *caPubs_copy = NULL; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (caPubs != NULL && (caPubs_copy = X509_chain_up_ref(caPubs)) == NULL) + return 0; + sk_X509_pop_free(ctx->caPubsOut, X509_free); + ctx->caPubsOut = caPubs_copy; + return 1; +} + +int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, + int fail_info, const char *text) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + OSSL_CMP_PKISI *si; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, text)) == NULL) + return 0; + OSSL_CMP_PKISI_free(ctx->statusOut); + ctx->statusOut = si; + return 1; +} + +int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + ctx->sendError = val != 0; + return 1; +} + +int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (count < 0) { + ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ARGS); + return 0; + } + ctx->pollCount = count; + return 1; +} + +int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + ctx->checkAfterTime = sec; + return 1; +} + +static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *cert_req, + int certReqId, + const OSSL_CRMF_MSG *crm, + const X509_REQ *p10cr, + X509 **certOut, + STACK_OF(X509) **chainOut, + STACK_OF(X509) **caPubs) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + OSSL_CMP_PKISI *si = NULL; + + if (ctx == NULL || cert_req == NULL + || certOut == NULL || chainOut == NULL || caPubs == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return NULL; + } + if (ctx->sendError) { + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + return NULL; + } + + *certOut = NULL; + *chainOut = NULL; + *caPubs = NULL; + ctx->certReqId = certReqId; + + if (ctx->pollCount > 0 && ctx->curr_pollCount == 0) { + /* start polling */ + if (ctx->certReq != NULL) { + /* already in polling mode */ + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return NULL; + } + if ((ctx->certReq = OSSL_CMP_MSG_dup(cert_req)) == NULL) + return NULL; + return OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_waiting, 0, NULL); + } + if (ctx->curr_pollCount >= ctx->pollCount) + /* give final response after polling */ + ctx->curr_pollCount = 0; + + if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_KUR + && crm != NULL && ctx->certOut != NULL) { + const OSSL_CRMF_CERTID *cid = OSSL_CRMF_MSG_get0_regCtrl_oldCertID(crm); + const X509_NAME *issuer = X509_get_issuer_name(ctx->certOut); + const ASN1_INTEGER *serial = X509_get0_serialNumber(ctx->certOut); + + if (cid == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_CERTID); + return NULL; + } + if (issuer != NULL + && X509_NAME_cmp(issuer, OSSL_CRMF_CERTID_get0_issuer(cid)) != 0) { + ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID); + return NULL; + } + if (serial != NULL + && ASN1_INTEGER_cmp(serial, + OSSL_CRMF_CERTID_get0_serialNumber(cid)) != 0) { + ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID); + return NULL; + } + } + + if (ctx->certOut != NULL + && (*certOut = X509_dup(ctx->certOut)) == NULL) + goto err; + if (ctx->chainOut != NULL + && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL) + goto err; + if (ctx->caPubsOut != NULL + && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL) + goto err; + if (ctx->statusOut != NULL + && (si = OSSL_CMP_PKISI_dup(ctx->statusOut)) == NULL) + goto err; + return si; + + err: + X509_free(*certOut); + *certOut = NULL; + sk_X509_pop_free(*chainOut, X509_free); + *chainOut = NULL; + sk_X509_pop_free(*caPubs, X509_free); + *caPubs = NULL; + return NULL; +} + +static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *rr, + const X509_NAME *issuer, + const ASN1_INTEGER *serial) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL || rr == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return NULL; + } + if (ctx->sendError || ctx->certOut == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + return NULL; + } + + /* Allow any RR derived from CSR, which may include subject and serial */ + if (issuer == NULL || serial == NULL) + return OSSL_CMP_PKISI_dup(ctx->statusOut); + + /* accept revocation only for the certificate we sent in ir/cr/kur */ + if (X509_NAME_cmp(issuer, X509_get_issuer_name(ctx->certOut)) != 0 + || ASN1_INTEGER_cmp(serial, + X509_get0_serialNumber(ctx->certOut)) != 0) { + ERR_raise_data(ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED, + "wrong certificate to revoke"); + return NULL; + } + return OSSL_CMP_PKISI_dup(ctx->statusOut); +} + +static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *genm, + const STACK_OF(OSSL_CMP_ITAV) *in, + STACK_OF(OSSL_CMP_ITAV) **out) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL || genm == NULL || in == NULL || out == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (sk_OSSL_CMP_ITAV_num(in) > 1 || ctx->sendError) { + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + return 0; + } + + *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup, + OSSL_CMP_ITAV_free); + return *out != NULL; +} + +static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error, + const OSSL_CMP_PKISI *statusInfo, + const ASN1_INTEGER *errorCode, + const OSSL_CMP_PKIFREETEXT *errorDetails) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + char buf[OSSL_CMP_PKISI_BUFLEN]; + char *sibuf; + int i; + + if (ctx == NULL || error == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return; + } + + BIO_printf(bio_err, "mock server received error:\n"); + + if (statusInfo == NULL) { + BIO_printf(bio_err, "pkiStatusInfo absent\n"); + } else { + sibuf = OSSL_CMP_snprint_PKIStatusInfo(statusInfo, buf, sizeof(buf)); + BIO_printf(bio_err, "pkiStatusInfo: %s\n", + sibuf != NULL ? sibuf: "<invalid>"); + } + + if (errorCode == NULL) + BIO_printf(bio_err, "errorCode absent\n"); + else + BIO_printf(bio_err, "errorCode: %ld\n", ASN1_INTEGER_get(errorCode)); + + if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) { + BIO_printf(bio_err, "errorDetails absent\n"); + } else { + BIO_printf(bio_err, "errorDetails: "); + for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) { + if (i > 0) + BIO_printf(bio_err, ", "); + BIO_printf(bio_err, "\""); + ASN1_STRING_print(bio_err, + sk_ASN1_UTF8STRING_value(errorDetails, i)); + BIO_printf(bio_err, "\""); + } + BIO_printf(bio_err, "\n"); + } +} + +static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *certConf, int certReqId, + const ASN1_OCTET_STRING *certHash, + const OSSL_CMP_PKISI *si) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + ASN1_OCTET_STRING *digest; + + if (ctx == NULL || certConf == NULL || certHash == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (ctx->sendError || ctx->certOut == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + return 0; + } + + if (certReqId != ctx->certReqId) { + /* in case of error, invalid reqId -1 */ + ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); + return 0; + } + + if ((digest = X509_digest_sig(ctx->certOut, NULL, NULL)) == NULL) + return 0; + if (ASN1_OCTET_STRING_cmp(certHash, digest) != 0) { + ASN1_OCTET_STRING_free(digest); + ERR_raise(ERR_LIB_CMP, CMP_R_CERTHASH_UNMATCHED); + return 0; + } + ASN1_OCTET_STRING_free(digest); + return 1; +} + +static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *pollReq, int certReqId, + OSSL_CMP_MSG **certReq, int64_t *check_after) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL || pollReq == NULL + || certReq == NULL || check_after == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if (ctx->sendError) { + *certReq = NULL; + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + return 0; + } + if (ctx->certReq == NULL) { + /* not currently in polling mode */ + *certReq = NULL; + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; + } + + if (++ctx->curr_pollCount >= ctx->pollCount) { + /* end polling */ + *certReq = ctx->certReq; + ctx->certReq = NULL; + *check_after = 0; + } else { + *certReq = NULL; + *check_after = ctx->checkAfterTime; + } + return 1; +} + +OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq) +{ + OSSL_CMP_SRV_CTX *srv_ctx = OSSL_CMP_SRV_CTX_new(libctx, propq); + mock_srv_ctx *ctx = mock_srv_ctx_new(); + + if (srv_ctx != NULL && ctx != NULL + && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request, + process_rr, process_genm, process_error, + process_certConf, process_pollReq)) + return srv_ctx; + + mock_srv_ctx_free(ctx); + OSSL_CMP_SRV_CTX_free(srv_ctx); + return NULL; +} + +void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx) +{ + if (srv_ctx != NULL) + mock_srv_ctx_free(OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx)); + OSSL_CMP_SRV_CTX_free(srv_ctx); +} diff --git a/apps/lib/columns.c b/apps/lib/columns.c new file mode 100644 index 000000000000..aa58fe1781f5 --- /dev/null +++ b/apps/lib/columns.c @@ -0,0 +1,27 @@ +/* + * Copyright 2017-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 <string.h> +#include "apps.h" +#include "function.h" + +void calculate_columns(FUNCTION *functions, DISPLAY_COLUMNS *dc) +{ + FUNCTION *f; + int len, maxlen = 0; + + for (f = functions; f->name != NULL; ++f) + if (f->type == FT_general || f->type == FT_md || f->type == FT_cipher) + if ((len = strlen(f->name)) > maxlen) + maxlen = len; + + dc->width = maxlen + 2; + dc->columns = (80 - 1) / dc->width; +} + diff --git a/apps/lib/engine.c b/apps/lib/engine.c new file mode 100644 index 000000000000..209c4b6b03c2 --- /dev/null +++ b/apps/lib/engine.c @@ -0,0 +1,193 @@ +/* + * Copyright 2020 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 + */ + +/* + * Here is a set of wrappers for the ENGINE API, which are no-ops when the + * ENGINE API is disabled / removed. + * We need to suppress deprecation warnings to make this work. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include <string.h> /* strcmp */ + +#include <openssl/types.h> /* Ensure we have the ENGINE type, regardless */ +#include <openssl/err.h> +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif +#include "apps.h" + +#ifndef OPENSSL_NO_ENGINE +/* Try to load an engine in a shareable library */ +static ENGINE *try_load_engine(const char *engine) +{ + ENGINE *e = NULL; + + if ((e = ENGINE_by_id("dynamic")) != NULL) { + if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) + || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { + ENGINE_free(e); + e = NULL; + } + } + return e; +} +#endif + +ENGINE *setup_engine_methods(const char *id, unsigned int methods, int debug) +{ + ENGINE *e = NULL; + +#ifndef OPENSSL_NO_ENGINE + if (id != NULL) { + if (strcmp(id, "auto") == 0) { + BIO_printf(bio_err, "Enabling auto ENGINE support\n"); + ENGINE_register_all_complete(); + return NULL; + } + if ((e = ENGINE_by_id(id)) == NULL + && (e = try_load_engine(id)) == NULL) { + BIO_printf(bio_err, "Invalid engine \"%s\"\n", id); + ERR_print_errors(bio_err); + return NULL; + } + if (debug) + (void)ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, bio_err, 0); + if (!ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, + (void *)get_ui_method(), 0, 1) + || !ENGINE_set_default(e, methods)) { + BIO_printf(bio_err, "Cannot use engine \"%s\"\n", ENGINE_get_id(e)); + ERR_print_errors(bio_err); + ENGINE_free(e); + return NULL; + } + + BIO_printf(bio_err, "Engine \"%s\" set.\n", ENGINE_get_id(e)); + } +#endif + return e; +} + +void release_engine(ENGINE *e) +{ +#ifndef OPENSSL_NO_ENGINE + /* Free our "structural" reference. */ + ENGINE_free(e); +#endif +} + +int init_engine(ENGINE *e) +{ + int rv = 1; + +#ifndef OPENSSL_NO_ENGINE + rv = ENGINE_init(e); +#endif + return rv; +} + +int finish_engine(ENGINE *e) +{ + int rv = 1; + +#ifndef OPENSSL_NO_ENGINE + rv = ENGINE_finish(e); +#endif + return rv; +} + +char *make_engine_uri(ENGINE *e, const char *key_id, const char *desc) +{ + char *new_uri = NULL; + +#ifndef OPENSSL_NO_ENGINE + if (e == NULL) { + BIO_printf(bio_err, "No engine specified for loading %s\n", desc); + } else if (key_id == NULL) { + BIO_printf(bio_err, "No engine key id specified for loading %s\n", desc); + } else { + const char *engineid = ENGINE_get_id(e); + size_t uri_sz = + sizeof(ENGINE_SCHEME_COLON) - 1 + + strlen(engineid) + + 1 /* : */ + + strlen(key_id) + + 1 /* \0 */ + ; + + new_uri = OPENSSL_malloc(uri_sz); + if (new_uri != NULL) { + OPENSSL_strlcpy(new_uri, ENGINE_SCHEME_COLON, uri_sz); + OPENSSL_strlcat(new_uri, engineid, uri_sz); + OPENSSL_strlcat(new_uri, ":", uri_sz); + OPENSSL_strlcat(new_uri, key_id, uri_sz); + } + } +#else + BIO_printf(bio_err, "Engines not supported for loading %s\n", desc); +#endif + return new_uri; +} + +int get_legacy_pkey_id(OSSL_LIB_CTX *libctx, const char *algname, ENGINE *e) +{ + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng = NULL; + int pkey_id = NID_undef; + + ERR_set_mark(); + ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); + +#if !defined(OPENSSL_NO_ENGINE) + ENGINE_finish(tmpeng); + + if (ameth == NULL && e != NULL) + ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); + else +#endif + /* We're only interested if it comes from an ENGINE */ + if (tmpeng == NULL) + ameth = NULL; + + ERR_pop_to_mark(); + if (ameth == NULL) + return NID_undef; + + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); + + return pkey_id; +} + +const EVP_MD *get_digest_from_engine(const char *name) +{ +#ifndef OPENSSL_NO_ENGINE + ENGINE *eng; + + eng = ENGINE_get_digest_engine(OBJ_sn2nid(name)); + if (eng != NULL) { + ENGINE_finish(eng); + return EVP_get_digestbyname(name); + } +#endif + return NULL; +} + +const EVP_CIPHER *get_cipher_from_engine(const char *name) +{ +#ifndef OPENSSL_NO_ENGINE + ENGINE *eng; + + eng = ENGINE_get_cipher_engine(OBJ_sn2nid(name)); + if (eng != NULL) { + ENGINE_finish(eng); + return EVP_get_cipherbyname(name); + } +#endif + return NULL; +} diff --git a/apps/lib/engine_loader.c b/apps/lib/engine_loader.c new file mode 100644 index 000000000000..42775a89f361 --- /dev/null +++ b/apps/lib/engine_loader.c @@ -0,0 +1,203 @@ +/* + * Copyright 2018-2022 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 + */ + +/* + * Here is an STORE loader for ENGINE backed keys. It relies on deprecated + * functions, and therefore need to have deprecation warnings suppressed. + * This file is not compiled at all in a '--api=3 no-deprecated' configuration. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include "apps.h" + +#ifndef OPENSSL_NO_ENGINE + +# include <stdarg.h> +# include <string.h> +# include <openssl/engine.h> +# include <openssl/store.h> + +/* + * Support for legacy private engine keys via the 'org.openssl.engine:' scheme + * + * org.openssl.engine:{engineid}:{keyid} + * + * Note: we ONLY support ENGINE_load_private_key() and ENGINE_load_public_key() + * Note 2: This scheme has a precedent in code in PKIX-SSH. for exactly + * this sort of purpose. + */ + +/* Local definition of OSSL_STORE_LOADER_CTX */ +struct ossl_store_loader_ctx_st { + ENGINE *e; /* Structural reference */ + char *keyid; + int expected; + int loaded; /* 0 = key not loaded yet, 1 = key loaded */ +}; + +static OSSL_STORE_LOADER_CTX *OSSL_STORE_LOADER_CTX_new(ENGINE *e, char *keyid) +{ + OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->e = e; + ctx->keyid = keyid; + } + return ctx; +} + +static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) +{ + if (ctx != NULL) { + ENGINE_free(ctx->e); + OPENSSL_free(ctx->keyid); + OPENSSL_free(ctx); + } +} + +static OSSL_STORE_LOADER_CTX *engine_open(const OSSL_STORE_LOADER *loader, + const char *uri, + const UI_METHOD *ui_method, + void *ui_data) +{ + const char *p = uri, *q; + ENGINE *e = NULL; + char *keyid = NULL; + OSSL_STORE_LOADER_CTX *ctx = NULL; + + if (OPENSSL_strncasecmp(p, ENGINE_SCHEME_COLON, sizeof(ENGINE_SCHEME_COLON) - 1) + != 0) + return NULL; + p += sizeof(ENGINE_SCHEME_COLON) - 1; + + /* Look for engine ID */ + q = strchr(p, ':'); + if (q != NULL /* There is both an engine ID and a key ID */ + && p[0] != ':' /* The engine ID is at least one character */ + && q[1] != '\0') { /* The key ID is at least one character */ + char engineid[256]; + size_t engineid_l = q - p; + + strncpy(engineid, p, engineid_l); + engineid[engineid_l] = '\0'; + e = ENGINE_by_id(engineid); + + keyid = OPENSSL_strdup(q + 1); + } + + if (e != NULL && keyid != NULL) + ctx = OSSL_STORE_LOADER_CTX_new(e, keyid); + + if (ctx == NULL) { + OPENSSL_free(keyid); + ENGINE_free(e); + } + + return ctx; +} + +static int engine_expect(OSSL_STORE_LOADER_CTX *ctx, int expected) +{ + if (expected == 0 + || expected == OSSL_STORE_INFO_PUBKEY + || expected == OSSL_STORE_INFO_PKEY) { + ctx->expected = expected; + return 1; + } + return 0; +} + +static OSSL_STORE_INFO *engine_load(OSSL_STORE_LOADER_CTX *ctx, + const UI_METHOD *ui_method, void *ui_data) +{ + EVP_PKEY *pkey = NULL, *pubkey = NULL; + OSSL_STORE_INFO *info = NULL; + + if (ctx->loaded == 0) { + if (ENGINE_init(ctx->e)) { + if (ctx->expected == 0 + || ctx->expected == OSSL_STORE_INFO_PKEY) + pkey = + ENGINE_load_private_key(ctx->e, ctx->keyid, + (UI_METHOD *)ui_method, ui_data); + if ((pkey == NULL && ctx->expected == 0) + || ctx->expected == OSSL_STORE_INFO_PUBKEY) + pubkey = + ENGINE_load_public_key(ctx->e, ctx->keyid, + (UI_METHOD *)ui_method, ui_data); + ENGINE_finish(ctx->e); + } + } + + ctx->loaded = 1; + + if (pubkey != NULL) + info = OSSL_STORE_INFO_new_PUBKEY(pubkey); + else if (pkey != NULL) + info = OSSL_STORE_INFO_new_PKEY(pkey); + if (info == NULL) { + EVP_PKEY_free(pkey); + EVP_PKEY_free(pubkey); + } + return info; +} + +static int engine_eof(OSSL_STORE_LOADER_CTX *ctx) +{ + return ctx->loaded != 0; +} + +static int engine_error(OSSL_STORE_LOADER_CTX *ctx) +{ + return 0; +} + +static int engine_close(OSSL_STORE_LOADER_CTX *ctx) +{ + OSSL_STORE_LOADER_CTX_free(ctx); + return 1; +} + +int setup_engine_loader(void) +{ + OSSL_STORE_LOADER *loader = NULL; + + if ((loader = OSSL_STORE_LOADER_new(NULL, ENGINE_SCHEME)) == NULL + || !OSSL_STORE_LOADER_set_open(loader, engine_open) + || !OSSL_STORE_LOADER_set_expect(loader, engine_expect) + || !OSSL_STORE_LOADER_set_load(loader, engine_load) + || !OSSL_STORE_LOADER_set_eof(loader, engine_eof) + || !OSSL_STORE_LOADER_set_error(loader, engine_error) + || !OSSL_STORE_LOADER_set_close(loader, engine_close) + || !OSSL_STORE_register_loader(loader)) { + OSSL_STORE_LOADER_free(loader); + loader = NULL; + } + + return loader != NULL; +} + +void destroy_engine_loader(void) +{ + OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader(ENGINE_SCHEME); + OSSL_STORE_LOADER_free(loader); +} + +#else /* !OPENSSL_NO_ENGINE */ + +int setup_engine_loader(void) +{ + return 0; +} + +void destroy_engine_loader(void) +{ +} + +#endif diff --git a/apps/lib/fmt.c b/apps/lib/fmt.c new file mode 100644 index 000000000000..af0e63b85b14 --- /dev/null +++ b/apps/lib/fmt.c @@ -0,0 +1,15 @@ +/* + * Copyright 2018-2020 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 "fmt.h" + +int FMT_istext(int format) +{ + return (format & B_FORMAT_TEXT) == B_FORMAT_TEXT; +} diff --git a/apps/lib/http_server.c b/apps/lib/http_server.c new file mode 100644 index 000000000000..a7fe5e1a58b0 --- /dev/null +++ b/apps/lib/http_server.c @@ -0,0 +1,533 @@ +/* + * Copyright 1995-2022 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 + */ + +/* Very basic HTTP server */ + +#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) +/* + * On VMS, you need to define this to get the declaration of fileno(). The + * value 2 is to make sure no function defined in POSIX-2 is left undefined. + */ +# define _POSIX_C_SOURCE 2 +#endif + +#include <string.h> +#include <ctype.h> +#include "http_server.h" +#include "internal/sockets.h" +#include <openssl/err.h> +#include <openssl/rand.h> +#include "s_apps.h" + +#if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_fork)> +# endif +#endif + +static int verbosity = LOG_INFO; + +#define HTTP_PREFIX "HTTP/" +#define HTTP_VERSION_PATT "1." /* allow 1.x */ +#define HTTP_PREFIX_VERSION HTTP_PREFIX""HTTP_VERSION_PATT +#define HTTP_1_0 HTTP_PREFIX_VERSION"0" /* "HTTP/1.0" */ + +#ifdef HTTP_DAEMON + +int multi = 0; /* run multiple responder processes */ +int acfd = (int) INVALID_SOCKET; + +static int print_syslog(const char *str, size_t len, void *levPtr) +{ + int level = *(int *)levPtr; + int ilen = len > MAXERRLEN ? MAXERRLEN : len; + + syslog(level, "%.*s", ilen, str); + + return ilen; +} +#endif + +void log_message(const char *prog, int level, const char *fmt, ...) +{ + va_list ap; + + if (verbosity < level) + return; + + va_start(ap, fmt); +#ifdef HTTP_DAEMON + if (multi) { + char buf[1024]; + + if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) + syslog(level, "%s", buf); + if (level <= LOG_ERR) + ERR_print_errors_cb(print_syslog, &level); + } else +#endif + { + BIO_printf(bio_err, "%s: ", prog); + BIO_vprintf(bio_err, fmt, ap); + BIO_printf(bio_err, "\n"); + (void)BIO_flush(bio_err); + } + va_end(ap); +} + +#ifdef HTTP_DAEMON +void socket_timeout(int signum) +{ + if (acfd != (int)INVALID_SOCKET) + (void)shutdown(acfd, SHUT_RD); +} + +static void killall(int ret, pid_t *kidpids) +{ + int i; + + for (i = 0; i < multi; ++i) + if (kidpids[i] != 0) + (void)kill(kidpids[i], SIGTERM); + OPENSSL_free(kidpids); + ossl_sleep(1000); + exit(ret); +} + +static int termsig = 0; + +static void noteterm(int sig) +{ + termsig = sig; +} + +/* + * Loop spawning up to `multi` child processes, only child processes return + * from this function. The parent process loops until receiving a termination + * signal, kills extant children and exits without returning. + */ +void spawn_loop(const char *prog) +{ + pid_t *kidpids = NULL; + int status; + int procs = 0; + int i; + + openlog(prog, LOG_PID, LOG_DAEMON); + + if (setpgid(0, 0)) { + syslog(LOG_ERR, "fatal: error detaching from parent process group: %s", + strerror(errno)); + exit(1); + } + kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array"); + for (i = 0; i < multi; ++i) + kidpids[i] = 0; + + signal(SIGINT, noteterm); + signal(SIGTERM, noteterm); + + while (termsig == 0) { + pid_t fpid; + + /* + * Wait for a child to replace when we're at the limit. + * Slow down if a child exited abnormally or waitpid() < 0 + */ + while (termsig == 0 && procs >= multi) { + if ((fpid = waitpid(-1, &status, 0)) > 0) { + for (i = 0; i < procs; ++i) { + if (kidpids[i] == fpid) { + kidpids[i] = 0; + --procs; + break; + } + } + if (i >= multi) { + syslog(LOG_ERR, "fatal: internal error: " + "no matching child slot for pid: %ld", + (long) fpid); + killall(1, kidpids); + } + if (status != 0) { + if (WIFEXITED(status)) + syslog(LOG_WARNING, "child process: %ld, exit status: %d", + (long)fpid, WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + syslog(LOG_WARNING, "child process: %ld, term signal %d%s", + (long)fpid, WTERMSIG(status), +# ifdef WCOREDUMP + WCOREDUMP(status) ? " (core dumped)" : +# endif + ""); + ossl_sleep(1000); + } + break; + } else if (errno != EINTR) { + syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno)); + killall(1, kidpids); + } + } + if (termsig) + break; + + switch (fpid = fork()) { + case -1: /* error */ + /* System critically low on memory, pause and try again later */ + ossl_sleep(30000); + break; + case 0: /* child */ + OPENSSL_free(kidpids); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + if (termsig) + _exit(0); + if (RAND_poll() <= 0) { + syslog(LOG_ERR, "fatal: RAND_poll() failed"); + _exit(1); + } + return; + default: /* parent */ + for (i = 0; i < multi; ++i) { + if (kidpids[i] == 0) { + kidpids[i] = fpid; + procs++; + break; + } + } + if (i >= multi) { + syslog(LOG_ERR, "fatal: internal error: no free child slots"); + killall(1, kidpids); + } + break; + } + } + + /* The loop above can only break on termsig */ + syslog(LOG_INFO, "terminating on signal: %d", termsig); + killall(0, kidpids); +} +#endif + +#ifndef OPENSSL_NO_SOCK +BIO *http_server_init_bio(const char *prog, const char *port) +{ + BIO *acbio = NULL, *bufbio; + int asock; + + bufbio = BIO_new(BIO_f_buffer()); + if (bufbio == NULL) + goto err; + acbio = BIO_new(BIO_s_accept()); + if (acbio == NULL + || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0 + || BIO_set_accept_port(acbio, port) < 0) { + log_message(prog, LOG_ERR, "Error setting up accept BIO"); + goto err; + } + + BIO_set_accept_bios(acbio, bufbio); + bufbio = NULL; + if (BIO_do_accept(acbio) <= 0) { + log_message(prog, LOG_ERR, "Error starting accept"); + goto err; + } + + /* Report back what address and port are used */ + BIO_get_fd(acbio, &asock); + if (!report_server_accept(bio_out, asock, 1, 1)) { + log_message(prog, LOG_ERR, "Error printing ACCEPT string"); + goto err; + } + + return acbio; + + err: + BIO_free_all(acbio); + BIO_free(bufbio); + return NULL; +} + +/* + * Decode %xx URL-decoding in-place. Ignores malformed sequences. + */ +static int urldecode(char *p) +{ + unsigned char *out = (unsigned char *)p; + unsigned char *save = out; + + for (; *p; p++) { + if (*p != '%') { + *out++ = *p; + } else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) { + /* Don't check, can't fail because of ixdigit() call. */ + *out++ = (OPENSSL_hexchar2int(p[1]) << 4) + | OPENSSL_hexchar2int(p[2]); + p += 2; + } else { + return -1; + } + } + *out = '\0'; + return (int)(out - save); +} + +/* if *pcbio != NULL, continue given connected session, else accept new */ +/* if found_keep_alive != NULL, return this way connection persistence state */ +int http_server_get_asn1_req(const ASN1_ITEM *it, ASN1_VALUE **preq, + char **ppath, BIO **pcbio, BIO *acbio, + int *found_keep_alive, + const char *prog, const char *port, + int accept_get, int timeout) +{ + BIO *cbio = *pcbio, *getbio = NULL, *b64 = NULL; + int len; + char reqbuf[2048], inbuf[2048]; + char *meth, *url, *end; + ASN1_VALUE *req; + int ret = 0; + + *preq = NULL; + if (ppath != NULL) + *ppath = NULL; + + if (cbio == NULL) { + log_message(prog, LOG_DEBUG, + "Awaiting new connection on port %s...", port); + if (BIO_do_accept(acbio) <= 0) + /* Connection loss before accept() is routine, ignore silently */ + return ret; + + *pcbio = cbio = BIO_pop(acbio); + } else { + log_message(prog, LOG_DEBUG, "Awaiting next request..."); + } + if (cbio == NULL) { + /* Cannot call http_server_send_status(cbio, ...) */ + ret = -1; + goto out; + } + +# ifdef HTTP_DAEMON + if (timeout > 0) { + (void)BIO_get_fd(cbio, &acfd); + alarm(timeout); + } +# endif + + /* Read the request line. */ + len = BIO_gets(cbio, reqbuf, sizeof(reqbuf)); + if (len == 0) + return ret; + ret = 1; + if (len < 0) { + log_message(prog, LOG_WARNING, "Request line read error"); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + if ((end = strchr(reqbuf, '\r')) != NULL + || (end = strchr(reqbuf, '\n')) != NULL) + *end = '\0'; + log_message(prog, LOG_INFO, "Received request, 1st line: %s", reqbuf); + + meth = reqbuf; + url = meth + 3; + if ((accept_get && strncmp(meth, "GET ", 4) == 0) + || (url++, strncmp(meth, "POST ", 5) == 0)) { + static const char http_version_str[] = " "HTTP_PREFIX_VERSION; + static const size_t http_version_str_len = sizeof(http_version_str) - 1; + + /* Expecting (GET|POST) {sp} /URL {sp} HTTP/1.x */ + *(url++) = '\0'; + while (*url == ' ') + url++; + if (*url != '/') { + log_message(prog, LOG_WARNING, + "Invalid %s -- URL does not begin with '/': %s", + meth, url); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + url++; + + /* Splice off the HTTP version identifier. */ + for (end = url; *end != '\0'; end++) + if (*end == ' ') + break; + if (strncmp(end, http_version_str, http_version_str_len) != 0) { + log_message(prog, LOG_WARNING, + "Invalid %s -- bad HTTP/version string: %s", + meth, end + 1); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + *end = '\0'; + /* above HTTP 1.0, connection persistence is the default */ + if (found_keep_alive != NULL) + *found_keep_alive = end[http_version_str_len] > '0'; + + /*- + * Skip "GET / HTTP..." requests often used by load-balancers. + * 'url' was incremented above to point to the first byte *after* + * the leading slash, so in case 'GET / ' it is now an empty string. + */ + if (strlen(meth) == 3 && url[0] == '\0') { + (void)http_server_send_status(cbio, 200, "OK"); + goto out; + } + + len = urldecode(url); + if (len < 0) { + log_message(prog, LOG_WARNING, + "Invalid %s request -- bad URL encoding: %s", + meth, url); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + if (strlen(meth) == 3) { /* GET */ + if ((getbio = BIO_new_mem_buf(url, len)) == NULL + || (b64 = BIO_new(BIO_f_base64())) == NULL) { + log_message(prog, LOG_ERR, + "Could not allocate base64 bio with size = %d", + len); + goto fatal; + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + getbio = BIO_push(b64, getbio); + } + } else { + log_message(prog, LOG_WARNING, + "HTTP request does not begin with %sPOST: %s", + accept_get ? "GET or " : "", reqbuf); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + + /* chop any further/duplicate leading or trailing '/' */ + while (*url == '/') + url++; + while (end >= url + 2 && end[-2] == '/' && end[-1] == '/') + end--; + *end = '\0'; + + /* Read and skip past the headers. */ + for (;;) { + char *key, *value, *line_end = NULL; + + len = BIO_gets(cbio, inbuf, sizeof(inbuf)); + if (len <= 0) { + log_message(prog, LOG_WARNING, "Error reading HTTP header"); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + + if (inbuf[0] == '\r' || inbuf[0] == '\n') + break; + + key = inbuf; + value = strchr(key, ':'); + if (value == NULL) { + log_message(prog, LOG_WARNING, + "Error parsing HTTP header: missing ':'"); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + *(value++) = '\0'; + while (*value == ' ') + value++; + line_end = strchr(value, '\r'); + if (line_end == NULL) { + line_end = strchr(value, '\n'); + if (line_end == NULL) { + log_message(prog, LOG_WARNING, + "Error parsing HTTP header: missing end of line"); + (void)http_server_send_status(cbio, 400, "Bad Request"); + goto out; + } + } + *line_end = '\0'; + /* https://tools.ietf.org/html/rfc7230#section-6.3 Persistence */ + if (found_keep_alive != NULL + && OPENSSL_strcasecmp(key, "Connection") == 0) { + if (OPENSSL_strcasecmp(value, "keep-alive") == 0) + *found_keep_alive = 1; + else if (OPENSSL_strcasecmp(value, "close") == 0) + *found_keep_alive = 0; + } + } + +# ifdef HTTP_DAEMON + /* Clear alarm before we close the client socket */ + alarm(0); + timeout = 0; +# endif + + /* Try to read and parse request */ + req = ASN1_item_d2i_bio(it, getbio != NULL ? getbio : cbio, NULL); + if (req == NULL) { + log_message(prog, LOG_WARNING, + "Error parsing DER-encoded request content"); + (void)http_server_send_status(cbio, 400, "Bad Request"); + } else if (ppath != NULL && (*ppath = OPENSSL_strdup(url)) == NULL) { + log_message(prog, LOG_ERR, + "Out of memory allocating %zu bytes", strlen(url) + 1); + ASN1_item_free(req, it); + goto fatal; + } + + *preq = req; + + out: + BIO_free_all(getbio); +# ifdef HTTP_DAEMON + if (timeout > 0) + alarm(0); + acfd = (int)INVALID_SOCKET; +# endif + return ret; + + fatal: + (void)http_server_send_status(cbio, 500, "Internal Server Error"); + if (ppath != NULL) { + OPENSSL_free(*ppath); + *ppath = NULL; + } + BIO_free_all(cbio); + *pcbio = NULL; + ret = -1; + goto out; +} + +/* assumes that cbio does not do an encoding that changes the output length */ +int http_server_send_asn1_resp(BIO *cbio, int keep_alive, + const char *content_type, + const ASN1_ITEM *it, const ASN1_VALUE *resp) +{ + int ret = BIO_printf(cbio, HTTP_1_0" 200 OK\r\n%s" + "Content-type: %s\r\n" + "Content-Length: %d\r\n\r\n", + keep_alive ? "Connection: keep-alive\r\n" : "", + content_type, + ASN1_item_i2d(resp, NULL, it)) > 0 + && ASN1_item_i2d_bio(it, cbio, resp) > 0; + + (void)BIO_flush(cbio); + return ret; +} + +int http_server_send_status(BIO *cbio, int status, const char *reason) +{ + int ret = BIO_printf(cbio, HTTP_1_0" %d %s\r\n\r\n", + /* This implicitly cancels keep-alive */ + status, reason) > 0; + + (void)BIO_flush(cbio); + return ret; +} +#endif diff --git a/apps/lib/names.c b/apps/lib/names.c new file mode 100644 index 000000000000..4788ae84b915 --- /dev/null +++ b/apps/lib/names.c @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2022 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 <string.h> +#include <openssl/bio.h> +#include <openssl/safestack.h> +#include "names.h" +#include "openssl/crypto.h" + +int name_cmp(const char * const *a, const char * const *b) +{ + return OPENSSL_strcasecmp(*a, *b); +} + +void collect_names(const char *name, void *vdata) +{ + STACK_OF(OPENSSL_CSTRING) *names = vdata; + + sk_OPENSSL_CSTRING_push(names, name); +} + +void print_names(BIO *out, STACK_OF(OPENSSL_CSTRING) *names) +{ + int i = sk_OPENSSL_CSTRING_num(names); + int j; + + sk_OPENSSL_CSTRING_sort(names); + if (i > 1) + BIO_printf(out, "{ "); + for (j = 0; j < i; j++) { + const char *name = sk_OPENSSL_CSTRING_value(names, j); + + if (j > 0) + BIO_printf(out, ", "); + BIO_printf(out, "%s", name); + } + if (i > 1) + BIO_printf(out, " }"); +} diff --git a/apps/opt.c b/apps/lib/opt.c index 666856535d5e..157367982d2f 100644 --- a/apps/opt.c +++ b/apps/lib/opt.c @@ -1,27 +1,38 @@ /* - * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 "apps.h" + +/* + * This file is also used by the test suite. Do not #include "apps.h". + */ +#include "opt.h" +#include "fmt.h" +#include "app_libctx.h" +#include "internal/nelem.h" +#include "internal/numbers.h" #include <string.h> #if !defined(OPENSSL_SYS_MSDOS) -# include OPENSSL_UNISTD +# include <unistd.h> #endif #include <stdlib.h> #include <errno.h> #include <ctype.h> #include <limits.h> +#include <openssl/err.h> #include <openssl/bio.h> #include <openssl/x509v3.h> #define MAX_OPT_HELP_WIDTH 30 -const char OPT_HELP_STR[] = "--"; -const char OPT_MORE_STR[] = "---"; +const char OPT_HELP_STR[] = "-H"; +const char OPT_MORE_STR[] = "-M"; +const char OPT_SECTION_STR[] = "-S"; +const char OPT_PARAM_STR[] = "-P"; /* Our state */ static char **argv; @@ -38,18 +49,27 @@ static char prog[40]; * Return the simple name of the program; removing various platform gunk. */ #if defined(OPENSSL_SYS_WIN32) -char *opt_progname(const char *argv0) + +const char *opt_path_end(const char *filename) { - size_t i, n; const char *p; - char *q; /* find the last '/', '\' or ':' */ - for (p = argv0 + strlen(argv0); --p > argv0;) + for (p = filename + strlen(filename); --p > filename; ) if (*p == '/' || *p == '\\' || *p == ':') { p++; break; } + return p; +} + +char *opt_progname(const char *argv0) +{ + size_t i, n; + const char *p; + char *q; + + p = opt_path_end(argv0); /* Strip off trailing nonsense. */ n = strlen(p); @@ -68,19 +88,28 @@ char *opt_progname(const char *argv0) #elif defined(OPENSSL_SYS_VMS) -char *opt_progname(const char *argv0) +const char *opt_path_end(const char *filename) { - const char *p, *q; + const char *p; /* Find last special character sys:[foo.bar]openssl */ - for (p = argv0 + strlen(argv0); --p > argv0;) + for (p = filename + strlen(filename); --p > filename;) if (*p == ':' || *p == ']' || *p == '>') { p++; break; } + return p; +} +char *opt_progname(const char *argv0) +{ + const char *p, *q; + + /* Find last special character sys:[foo.bar]openssl */ + p = opt_path_end(argv0); q = strrchr(p, '.'); - strncpy(prog, p, sizeof(prog) - 1); + if (prog != p) + strncpy(prog, p, sizeof(prog) - 1); prog[sizeof(prog) - 1] = '\0'; if (q != NULL && q - p < sizeof(prog)) prog[q - p] = '\0'; @@ -89,22 +118,40 @@ char *opt_progname(const char *argv0) #else -char *opt_progname(const char *argv0) +const char *opt_path_end(const char *filename) { const char *p; /* Could use strchr, but this is like the ones above. */ - for (p = argv0 + strlen(argv0); --p > argv0;) + for (p = filename + strlen(filename); --p > filename;) if (*p == '/') { p++; break; } - strncpy(prog, p, sizeof(prog) - 1); + return p; +} + +char *opt_progname(const char *argv0) +{ + const char *p; + + p = opt_path_end(argv0); + if (prog != p) + strncpy(prog, p, sizeof(prog) - 1); prog[sizeof(prog) - 1] = '\0'; return prog; } #endif +char *opt_appname(const char *argv0) +{ + size_t len = strlen(prog); + + if (argv0 != NULL) + BIO_snprintf(prog + len, sizeof(prog) - len - 1, " %s", argv0); + return prog; +} + char *opt_getprog(void) { return prog; @@ -116,32 +163,41 @@ char *opt_init(int ac, char **av, const OPTIONS *o) /* Store state. */ argc = ac; argv = av; - opt_index = 1; + opt_begin(); opts = o; - opt_progname(av[0]); unknown = NULL; - for (; o->name; ++o) { + /* Make sure prog name is set for usage output */ + (void)opt_progname(argv[0]); + + /* Check all options up until the PARAM marker (if present) */ + for (; o->name != NULL && o->name != OPT_PARAM_STR; ++o) { #ifndef NDEBUG const OPTIONS *next; int duplicated, i; #endif - if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR) + if (o->name == OPT_HELP_STR + || o->name == OPT_MORE_STR + || o->name == OPT_SECTION_STR) continue; #ifndef NDEBUG i = o->valtype; /* Make sure options are legit. */ - assert(o->name[0] != '-'); - assert(o->retval > 0); + OPENSSL_assert(o->name[0] != '-'); + if (o->valtype == '.') + OPENSSL_assert(o->retval == OPT_PARAM); + else + OPENSSL_assert(o->retval == OPT_DUP || o->retval > OPT_PARAM); switch (i) { - case 0: case '-': case '/': case '<': case '>': case 'E': case 'F': + case 0: case '-': case '.': + case '/': case '<': case '>': case 'E': case 'F': case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's': - case 'u': case 'c': + case 'u': case 'c': case ':': case 'N': break; default: - assert(0); + OPENSSL_assert(0); } /* Make sure there are no duplicates. */ @@ -149,14 +205,19 @@ char *opt_init(int ac, char **av, const OPTIONS *o) /* * Some compilers inline strcmp and the assert string is too long. */ - duplicated = strcmp(o->name, next->name) == 0; - assert(!duplicated); + duplicated = next->retval != OPT_DUP + && strcmp(o->name, next->name) == 0; + if (duplicated) { + opt_printf_stderr("%s: Internal error: duplicate option %s\n", + prog, o->name); + OPENSSL_assert(!duplicated); + } } #endif if (o->name[0] == '\0') { - assert(unknown == NULL); + OPENSSL_assert(unknown == NULL); unknown = o; - assert(unknown->valtype == 0 || unknown->valtype == '-'); + OPENSSL_assert(unknown->valtype == 0 || unknown->valtype == '-'); } } return prog; @@ -176,19 +237,19 @@ static OPT_PAIR formats[] = { }; /* Print an error message about a failed format parse. */ -int opt_format_error(const char *s, unsigned long flags) +static int opt_format_error(const char *s, unsigned long flags) { OPT_PAIR *ap; if (flags == OPT_FMT_PEMDER) { - BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n", - prog, s); + opt_printf_stderr("%s: Bad format \"%s\"; must be pem or der\n", + prog, s); } else { - BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n", - prog, s); + opt_printf_stderr("%s: Bad format \"%s\"; must be one of:\n", + prog, s); for (ap = formats; ap->name; ap++) if (flags & ap->retval) - BIO_printf(bio_err, " %s\n", ap->name); + opt_printf_stderr(" %s\n", ap->name); } return 0; } @@ -198,6 +259,7 @@ int opt_format(const char *s, unsigned long flags, int *result) { switch (*s) { default: + opt_printf_stderr("%s: Bad format \"%s\"\n", prog, s); return 0; case 'D': case 'd': @@ -264,6 +326,7 @@ int opt_format(const char *s, unsigned long flags, int *result) return opt_format_error(s, flags); *result = FORMAT_PKCS12; } else { + opt_printf_stderr("%s: Bad format \"%s\"\n", prog, s); return 0; } break; @@ -271,28 +334,132 @@ int opt_format(const char *s, unsigned long flags, int *result) return 1; } -/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */ -int opt_cipher(const char *name, const EVP_CIPHER **cipherp) +/* Return string representing the given format. */ +static const char *format2str(int format) +{ + switch (format) { + default: + return "(undefined)"; + case FORMAT_PEM: + return "PEM"; + case FORMAT_ASN1: + return "DER"; + case FORMAT_TEXT: + return "TEXT"; + case FORMAT_NSS: + return "NSS"; + case FORMAT_SMIME: + return "SMIME"; + case FORMAT_MSBLOB: + return "MSBLOB"; + case FORMAT_ENGINE: + return "ENGINE"; + case FORMAT_HTTP: + return "HTTP"; + case FORMAT_PKCS12: + return "P12"; + case FORMAT_PVK: + return "PVK"; + } +} + +/* Print an error message about unsuitable/unsupported format requested. */ +void print_format_error(int format, unsigned long flags) { - *cipherp = EVP_get_cipherbyname(name); - if (*cipherp != NULL) + (void)opt_format_error(format2str(format), flags); +} + +/* + * Parse a cipher name, put it in *cipherp after freeing what was there, if + * cipherp is not NULL. Return 0 on failure, else 1. + */ +int opt_cipher_silent(const char *name, EVP_CIPHER **cipherp) +{ + EVP_CIPHER *c; + + ERR_set_mark(); + if ((c = EVP_CIPHER_fetch(app_get0_libctx(), name, + app_get0_propq())) != NULL + || (opt_legacy_okay() + && (c = (EVP_CIPHER *)EVP_get_cipherbyname(name)) != NULL)) { + ERR_pop_to_mark(); + if (cipherp != NULL) { + EVP_CIPHER_free(*cipherp); + *cipherp = c; + } else { + EVP_CIPHER_free(c); + } return 1; - BIO_printf(bio_err, "%s: Unrecognized flag %s\n", prog, name); + } + ERR_clear_last_mark(); return 0; } +int opt_cipher_any(const char *name, EVP_CIPHER **cipherp) +{ + int ret; + + if ((ret = opt_cipher_silent(name, cipherp)) == 0) + opt_printf_stderr("%s: Unknown cipher: %s\n", prog, name); + return ret; +} + +int opt_cipher(const char *name, EVP_CIPHER **cipherp) +{ + int mode, ret = 0; + unsigned long int flags; + EVP_CIPHER *c = NULL; + + if (opt_cipher_any(name, &c)) { + mode = EVP_CIPHER_get_mode(c); + flags = EVP_CIPHER_get_flags(c); + if (mode == EVP_CIPH_XTS_MODE) { + opt_printf_stderr("%s XTS ciphers not supported\n", prog); + } else if ((flags & EVP_CIPH_FLAG_AEAD_CIPHER) != 0) { + opt_printf_stderr("%s: AEAD ciphers not supported\n", prog); + } else { + ret = 1; + if (cipherp != NULL) + *cipherp = c; + } + } + return ret; +} + /* * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1. */ -int opt_md(const char *name, const EVP_MD **mdp) +int opt_md_silent(const char *name, EVP_MD **mdp) { - *mdp = EVP_get_digestbyname(name); - if (*mdp != NULL) + EVP_MD *md; + + ERR_set_mark(); + if ((md = EVP_MD_fetch(app_get0_libctx(), name, app_get0_propq())) != NULL + || (opt_legacy_okay() + && (md = (EVP_MD *)EVP_get_digestbyname(name)) != NULL)) { + ERR_pop_to_mark(); + if (mdp != NULL) { + EVP_MD_free(*mdp); + *mdp = md; + } else { + EVP_MD_free(md); + } return 1; - BIO_printf(bio_err, "%s: Unrecognized flag %s\n", prog, name); + } + ERR_clear_last_mark(); return 0; } +int opt_md(const char *name, EVP_MD **mdp) +{ + int ret; + + if ((ret = opt_md_silent(name, mdp)) == 0) + opt_printf_stderr("%s: Unknown option or message digest: %s\n", prog, + name != NULL ? name : "\"\""); + return ret; +} + /* Look through a list of name/value pairs. */ int opt_pair(const char *name, const OPT_PAIR* pairs, int *result) { @@ -303,9 +470,23 @@ int opt_pair(const char *name, const OPT_PAIR* pairs, int *result) *result = pp->retval; return 1; } - BIO_printf(bio_err, "%s: Value must be one of:\n", prog); + opt_printf_stderr("%s: Value must be one of:\n", prog); for (pp = pairs; pp->name; pp++) - BIO_printf(bio_err, "\t%s\n", pp->name); + opt_printf_stderr("\t%s\n", pp->name); + return 0; +} + +/* Look through a list of valid names */ +int opt_string(const char *name, const char **options) +{ + const char **p; + + for (p = options; *p != NULL; p++) + if (strcmp(*p, name) == 0) + return 1; + opt_printf_stderr("%s: Value must be one of:\n", prog); + for (p = options; *p != NULL; p++) + opt_printf_stderr("\t%s\n", *p); return 0; } @@ -318,13 +499,22 @@ int opt_int(const char *value, int *result) return 0; *result = (int)l; if (*result != l) { - BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n", - prog, value); + opt_printf_stderr("%s: Value \"%s\" outside integer range\n", + prog, value); return 0; } return 1; } +/* Parse and return an integer, assuming range has been checked before. */ +int opt_int_arg(void) +{ + int result = -1; + + (void)opt_int(arg, &result); + return result; +} + static void opt_number_error(const char *v) { size_t i = 0; @@ -339,13 +529,12 @@ static void opt_number_error(const char *v) for (i = 0; i < OSSL_NELEM(b); i++) { if (strncmp(v, b[i].prefix, strlen(b[i].prefix)) == 0) { - BIO_printf(bio_err, - "%s: Can't parse \"%s\" as %s number\n", - prog, v, b[i].name); + opt_printf_stderr("%s: Can't parse \"%s\" as %s number\n", + prog, v, b[i].name); return; } } - BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", prog, v); + opt_printf_stderr("%s: Can't parse \"%s\" as a number\n", prog, v); return; } @@ -372,10 +561,11 @@ int opt_long(const char *value, long *result) } #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ - defined(INTMAX_MAX) && defined(UINTMAX_MAX) + defined(INTMAX_MAX) && defined(UINTMAX_MAX) && \ + !defined(OPENSSL_NO_INTTYPES_H) /* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */ -int opt_imax(const char *value, intmax_t *result) +int opt_intmax(const char *value, ossl_intmax_t *result) { int oerrno = errno; intmax_t m; @@ -385,19 +575,26 @@ int opt_imax(const char *value, intmax_t *result) m = strtoimax(value, &endp, 0); if (*endp || endp == value - || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE) + || ((m == INTMAX_MAX || m == INTMAX_MIN) + && errno == ERANGE) || (m == 0 && errno != 0)) { opt_number_error(value); errno = oerrno; return 0; } - *result = m; + /* Ensure that the value in |m| is never too big for |*result| */ + if (sizeof(m) > sizeof(*result) + && (m < OSSL_INTMAX_MIN || m > OSSL_INTMAX_MAX)) { + opt_number_error(value); + return 0; + } + *result = (ossl_intmax_t)m; errno = oerrno; return 1; } /* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */ -int opt_umax(const char *value, uintmax_t *result) +int opt_uintmax(const char *value, ossl_uintmax_t *result) { int oerrno = errno; uintmax_t m; @@ -413,10 +610,37 @@ int opt_umax(const char *value, uintmax_t *result) errno = oerrno; return 0; } - *result = m; + /* Ensure that the value in |m| is never too big for |*result| */ + if (sizeof(m) > sizeof(*result) + && m > OSSL_UINTMAX_MAX) { + opt_number_error(value); + return 0; + } + *result = (ossl_intmax_t)m; errno = oerrno; return 1; } +#else +/* Fallback implementations based on long */ +int opt_intmax(const char *value, ossl_intmax_t *result) +{ + long m; + int ret; + + if ((ret = opt_long(value, &m))) + *result = m; + return ret; +} + +int opt_uintmax(const char *value, ossl_uintmax_t *result) +{ + unsigned long m; + int ret; + + if ((ret = opt_ulong(value, &m))) + *result = m; + return ret; +} #endif /* @@ -458,9 +682,9 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) X509_PURPOSE *xptmp; const X509_VERIFY_PARAM *vtmp; - assert(vpm != NULL); - assert(opt > OPT_V__FIRST); - assert(opt < OPT_V__LAST); + OPENSSL_assert(vpm != NULL); + OPENSSL_assert(opt > OPT_V__FIRST); + OPENSSL_assert(opt < OPT_V__LAST); switch ((enum range)opt) { case OPT_V__FIRST: @@ -469,7 +693,7 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) case OPT_V_POLICY: otmp = OBJ_txt2obj(opt_arg(), 0); if (otmp == NULL) { - BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg()); + opt_printf_stderr("%s: Invalid Policy %s\n", prog, opt_arg()); return 0; } X509_VERIFY_PARAM_add0_policy(vpm, otmp); @@ -478,7 +702,7 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) /* purpose name -> purpose index */ i = X509_PURPOSE_get_by_sname(opt_arg()); if (i < 0) { - BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg()); + opt_printf_stderr("%s: Invalid purpose %s\n", prog, opt_arg()); return 0; } @@ -489,17 +713,16 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) i = X509_PURPOSE_get_id(xptmp); if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) { - BIO_printf(bio_err, - "%s: Internal error setting purpose %s\n", - prog, opt_arg()); + opt_printf_stderr("%s: Internal error setting purpose %s\n", + prog, opt_arg()); return 0; } break; case OPT_V_VERIFY_NAME: vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); if (vtmp == NULL) { - BIO_printf(bio_err, "%s: Invalid verify name %s\n", - prog, opt_arg()); + opt_printf_stderr("%s: Invalid verify name %s\n", + prog, opt_arg()); return 0; } X509_VERIFY_PARAM_set1(vpm, vtmp); @@ -515,11 +738,11 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) X509_VERIFY_PARAM_set_auth_level(vpm, i); break; case OPT_V_ATTIME: - if (!opt_imax(opt_arg(), &t)) + if (!opt_intmax(opt_arg(), &t)) return 0; if (t != (time_t)t) { - BIO_printf(bio_err, "%s: epoch time out of range %s\n", - prog, opt_arg()); + opt_printf_stderr("%s: epoch time out of range %s\n", + prog, opt_arg()); return 0; } X509_VERIFY_PARAM_set_time(vpm, (time_t)t); @@ -606,6 +829,13 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) } +void opt_begin(void) +{ + opt_index = 1; + arg = NULL; + flag = NULL; +} + /* * Parse the next flag (and value if specified), return 0 if done, -1 on * error, otherwise the flag's retval. @@ -645,14 +875,15 @@ int opt_next(void) *arg++ = '\0'; for (o = opts; o->name; ++o) { /* If not this option, move on to the next one. */ - if (strcmp(p, o->name) != 0) + if (!(strcmp(p, "h") == 0 && strcmp(o->name, "help") == 0) + && strcmp(p, o->name) != 0) continue; /* If it doesn't take a value, make sure none was given. */ if (o->valtype == 0 || o->valtype == '-') { if (arg) { - BIO_printf(bio_err, - "%s: Option -%s does not take a value\n", prog, p); + opt_printf_stderr("%s: Option -%s does not take a value\n", + prog, p); return -1; } return o->retval; @@ -661,8 +892,8 @@ int opt_next(void) /* Want a value; get the next param if =foo not used. */ if (arg == NULL) { if (argv[opt_index] == NULL) { - BIO_printf(bio_err, - "%s: Option -%s needs a value\n", prog, o->name); + opt_printf_stderr("%s: Option -%s needs a value\n", + prog, o->name); return -1; } arg = argv[opt_index++]; @@ -672,12 +903,16 @@ int opt_next(void) switch (o->valtype) { default: case 's': + case ':': /* Just a string. */ break; + case '.': + /* Parameters */ + break; case '/': - if (app_isdir(arg) > 0) + if (opt_isdir(arg) > 0) break; - BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg); + opt_printf_stderr("%s: Not a directory: %s\n", prog, arg); return -1; case '<': /* Input file. */ @@ -687,45 +922,35 @@ int opt_next(void) break; case 'p': case 'n': - if (!opt_int(arg, &ival) - || (o->valtype == 'p' && ival <= 0)) { - BIO_printf(bio_err, - "%s: Non-positive number \"%s\" for -%s\n", - prog, arg, o->name); + case 'N': + if (!opt_int(arg, &ival)) + return -1; + if (o->valtype == 'p' && ival <= 0) { + opt_printf_stderr("%s: Non-positive number \"%s\" for option -%s\n", + prog, arg, o->name); + return -1; + } + if (o->valtype == 'N' && ival < 0) { + opt_printf_stderr("%s: Negative number \"%s\" for option -%s\n", + prog, arg, o->name); return -1; } break; case 'M': - if (!opt_imax(arg, &imval)) { - BIO_printf(bio_err, - "%s: Invalid number \"%s\" for -%s\n", - prog, arg, o->name); + if (!opt_intmax(arg, &imval)) return -1; - } break; case 'U': - if (!opt_umax(arg, &umval)) { - BIO_printf(bio_err, - "%s: Invalid number \"%s\" for -%s\n", - prog, arg, o->name); + if (!opt_uintmax(arg, &umval)) return -1; - } break; case 'l': - if (!opt_long(arg, &lval)) { - BIO_printf(bio_err, - "%s: Invalid number \"%s\" for -%s\n", - prog, arg, o->name); + if (!opt_long(arg, &lval)) return -1; - } break; case 'u': - if (!opt_ulong(arg, &ulval)) { - BIO_printf(bio_err, - "%s: Invalid number \"%s\" for -%s\n", - prog, arg, o->name); + if (!opt_ulong(arg, &ulval)) return -1; - } break; case 'c': case 'E': @@ -737,9 +962,8 @@ int opt_next(void) o->valtype == 'F' ? OPT_FMT_PEMDER : OPT_FMT_ANY, &ival)) break; - BIO_printf(bio_err, - "%s: Invalid format \"%s\" for -%s\n", - prog, arg, o->name); + opt_printf_stderr("%s: Invalid format \"%s\" for option -%s\n", + prog, arg, o->name); return -1; } @@ -750,7 +974,7 @@ int opt_next(void) dunno = p; return unknown->retval; } - BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p); + opt_printf_stderr("%s: Unknown option: -%s\n", prog, p); return -1; } @@ -760,7 +984,7 @@ char *opt_arg(void) return arg; } -/* Return the most recent flag. */ +/* Return the most recent flag (option name including the preceding '-'). */ char *opt_flag(void) { return flag; @@ -796,6 +1020,8 @@ static const char *valtype2param(const OPTIONS *o) case 0: case '-': return ""; + case ':': + return "uri"; case 's': return "val"; case '/': @@ -820,47 +1046,33 @@ static const char *valtype2param(const OPTIONS *o) return "format"; case 'M': return "intmax"; + case 'N': + return "nonneg"; case 'U': return "uintmax"; } return "parm"; } -void opt_help(const OPTIONS *list) +static void opt_print(const OPTIONS *o, int doingparams, int width) { - const OPTIONS *o; - int i; - int standard_prolog; - int width = 5; + const char* help; char start[80 + 1]; char *p; - const char *help; - /* Starts with its own help message? */ - standard_prolog = list[0].name != OPT_HELP_STR; - - /* Find the widest help. */ - for (o = list; o->name; o++) { - if (o->name == OPT_MORE_STR) - continue; - i = 2 + (int)strlen(o->name); - if (o->valtype != '-') - i += 1 + strlen(valtype2param(o)); - if (i < MAX_OPT_HELP_WIDTH && i > width) - width = i; - assert(i < (int)sizeof(start)); - } - - if (standard_prolog) - BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n", - prog); - - /* Now let's print. */ - for (o = list; o->name; o++) { help = o->helpstr ? o->helpstr : "(No additional info)"; if (o->name == OPT_HELP_STR) { - BIO_printf(bio_err, help, prog); - continue; + opt_printf_stderr(help, prog); + return; + } + if (o->name == OPT_SECTION_STR) { + opt_printf_stderr("\n"); + opt_printf_stderr(help, prog); + return; + } + if (o->name == OPT_PARAM_STR) { + opt_printf_stderr("\nParameters:\n"); + return; } /* Pad out prefix */ @@ -870,14 +1082,15 @@ void opt_help(const OPTIONS *list) if (o->name == OPT_MORE_STR) { /* Continuation of previous line; pad and print. */ start[width] = '\0'; - BIO_printf(bio_err, "%s %s\n", start, help); - continue; + opt_printf_stderr("%s %s\n", start, help); + return; } /* Build up the "-flag [param]" part. */ p = start; *p++ = ' '; - *p++ = '-'; + if (!doingparams) + *p++ = '-'; if (o->name[0]) p += strlen(strcpy(p, o->name)); else @@ -889,10 +1102,97 @@ void opt_help(const OPTIONS *list) *p = ' '; if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) { *p = '\0'; - BIO_printf(bio_err, "%s\n", start); + opt_printf_stderr("%s\n", start); memset(start, ' ', sizeof(start)); } start[width] = '\0'; - BIO_printf(bio_err, "%s %s\n", start, help); + opt_printf_stderr("%s %s\n", start, help); +} + +void opt_help(const OPTIONS *list) +{ + const OPTIONS *o; + int i, sawparams = 0, width = 5; + int standard_prolog; + char start[80 + 1]; + + /* Starts with its own help message? */ + standard_prolog = list[0].name != OPT_HELP_STR; + + /* Find the widest help. */ + for (o = list; o->name; o++) { + if (o->name == OPT_MORE_STR) + continue; + i = 2 + (int)strlen(o->name); + if (o->valtype != '-') + i += 1 + strlen(valtype2param(o)); + if (i < MAX_OPT_HELP_WIDTH && i > width) + width = i; + OPENSSL_assert(i < (int)sizeof(start)); + } + + if (standard_prolog) { + opt_printf_stderr("Usage: %s [options]\n", prog); + if (list[0].name != OPT_SECTION_STR) + opt_printf_stderr("Valid options are:\n", prog); } + + /* Now let's print. */ + for (o = list; o->name; o++) { + if (o->name == OPT_PARAM_STR) + sawparams = 1; + opt_print(o, sawparams, width); + } +} + +/* opt_isdir section */ +#ifdef _WIN32 +# include <windows.h> +int opt_isdir(const char *name) +{ + DWORD attr; +# if defined(UNICODE) || defined(_UNICODE) + size_t i, len_0 = strlen(name) + 1; + WCHAR tempname[MAX_PATH]; + + if (len_0 > MAX_PATH) + return -1; + +# if !defined(_WIN32_WCE) || _WIN32_WCE>=101 + if (!MultiByteToWideChar(CP_ACP, 0, name, len_0, tempname, MAX_PATH)) +# endif + for (i = 0; i < len_0; i++) + tempname[i] = (WCHAR)name[i]; + + attr = GetFileAttributes(tempname); +# else + attr = GetFileAttributes(name); +# endif + if (attr == INVALID_FILE_ATTRIBUTES) + return -1; + return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0); } +#else +# include <sys/stat.h> +# ifndef S_ISDIR +# if defined(_S_IFMT) && defined(_S_IFDIR) +# define S_ISDIR(a) (((a) & _S_IFMT) == _S_IFDIR) +# else +# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) +# endif +# endif + +int opt_isdir(const char *name) +{ +# if defined(S_ISDIR) + struct stat st; + + if (stat(name, &st) == 0) + return S_ISDIR(st.st_mode); + else + return -1; +# else + return -1; +# endif +} +#endif diff --git a/apps/s_cb.c b/apps/lib/s_cb.c index 2f94c13393a5..f2ddd94c3de4 100644 --- a/apps/s_cb.c +++ b/apps/lib/s_cb.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -12,6 +12,8 @@ #include <stdlib.h> #include <string.h> /* for memcpy() and strcmp() */ #include "apps.h" +#include <openssl/core_names.h> +#include <openssl/params.h> #include <openssl/err.h> #include <openssl/rand.h> #include <openssl/x509.h> @@ -150,6 +152,7 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, STACK_OF(X509) *chain, int build_chain) { int chflags = chain ? SSL_BUILD_CHAIN_FLAG_CHECK : 0; + if (cert == NULL) return 1; if (SSL_CTX_use_certificate(ctx, cert) <= 0) { @@ -194,7 +197,7 @@ static STRINT_PAIR cert_type_list[] = { {"RSA fixed ECDH", TLS_CT_RSA_FIXED_ECDH}, {"ECDSA fixed ECDH", TLS_CT_ECDSA_FIXED_ECDH}, {"GOST01 Sign", TLS_CT_GOST01_SIGN}, - {"GOST12 Sign", TLS_CT_GOST12_SIGN}, + {"GOST12 Sign", TLS_CT_GOST12_IANA_SIGN}, {NULL} }; @@ -203,6 +206,7 @@ static void ssl_print_client_cert_types(BIO *bio, SSL *s) const unsigned char *p; int i; int cert_type_num = SSL_get0_certificate_types(s, &p); + if (!cert_type_num) return; BIO_puts(bio, "Client Certificate Types: "); @@ -232,22 +236,22 @@ static const char *get_sigtype(int nid) case EVP_PKEY_DSA: return "DSA"; - case EVP_PKEY_EC: + case EVP_PKEY_EC: return "ECDSA"; - case NID_ED25519: + case NID_ED25519: return "Ed25519"; - case NID_ED448: + case NID_ED448: return "Ed448"; - case NID_id_GostR3410_2001: + case NID_id_GostR3410_2001: return "gost2001"; - case NID_id_GostR3410_2012_256: + case NID_id_GostR3410_2012_256: return "gost2012_256"; - case NID_id_GostR3410_2012_512: + case NID_id_GostR3410_2012_512: return "gost2012_512"; default: @@ -258,6 +262,7 @@ static const char *get_sigtype(int nid) static int do_print_sigalgs(BIO *out, SSL *s, int shared) { int i, nsig, client; + client = SSL_is_server(s) ? 0 : 1; if (shared) nsig = SSL_get_shared_sigalgs(s, 0, NULL, NULL, NULL, NULL, NULL); @@ -300,6 +305,7 @@ static int do_print_sigalgs(BIO *out, SSL *s, int shared) int ssl_print_sigalgs(BIO *out, SSL *s) { int nid; + if (!SSL_is_server(s)) ssl_print_client_cert_types(out, s); do_print_sigalgs(out, s, 0); @@ -316,6 +322,7 @@ int ssl_print_point_formats(BIO *out, SSL *s) { int i, nformats; const char *pformats; + nformats = SSL_get0_ec_point_formats(s, &pformats); if (nformats <= 0) return 1; @@ -349,7 +356,6 @@ int ssl_print_point_formats(BIO *out, SSL *s) int ssl_print_groups(BIO *out, SSL *s, int noshared) { int i, ngroups, *groups, nid; - const char *gname; ngroups = SSL_get1_groups(s, NULL); if (ngroups <= 0) @@ -357,39 +363,25 @@ int ssl_print_groups(BIO *out, SSL *s, int noshared) groups = app_malloc(ngroups * sizeof(int), "groups to print"); SSL_get1_groups(s, groups); - BIO_puts(out, "Supported Elliptic Groups: "); + BIO_puts(out, "Supported groups: "); for (i = 0; i < ngroups; i++) { if (i) BIO_puts(out, ":"); nid = groups[i]; - /* If unrecognised print out hex version */ - if (nid & TLSEXT_nid_unknown) { - BIO_printf(out, "0x%04X", nid & 0xFFFF); - } else { - /* TODO(TLS1.3): Get group name here */ - /* Use NIST name for curve if it exists */ - gname = EC_curve_nid2nist(nid); - if (gname == NULL) - gname = OBJ_nid2sn(nid); - BIO_printf(out, "%s", gname); - } + BIO_printf(out, "%s", SSL_group_to_name(s, nid)); } OPENSSL_free(groups); if (noshared) { BIO_puts(out, "\n"); return 1; } - BIO_puts(out, "\nShared Elliptic groups: "); + BIO_puts(out, "\nShared groups: "); ngroups = SSL_get_shared_group(s, -1); for (i = 0; i < ngroups; i++) { if (i) BIO_puts(out, ":"); nid = SSL_get_shared_group(s, i); - /* TODO(TLS1.3): Convert for DH groups */ - gname = EC_curve_nid2nist(nid); - if (gname == NULL) - gname = OBJ_nid2sn(nid); - BIO_printf(out, "%s", gname); + BIO_printf(out, "%s", SSL_group_to_name(s, nid)); } if (ngroups == 0) BIO_puts(out, "NONE"); @@ -405,39 +397,37 @@ int ssl_print_tmp_key(BIO *out, SSL *s) if (!SSL_get_peer_tmp_key(s, &key)) return 1; BIO_puts(out, "Server Temp Key: "); - switch (EVP_PKEY_id(key)) { + switch (EVP_PKEY_get_id(key)) { case EVP_PKEY_RSA: - BIO_printf(out, "RSA, %d bits\n", EVP_PKEY_bits(key)); + BIO_printf(out, "RSA, %d bits\n", EVP_PKEY_get_bits(key)); break; case EVP_PKEY_DH: - BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(key)); + BIO_printf(out, "DH, %d bits\n", EVP_PKEY_get_bits(key)); break; #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: { - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); - int nid; - const char *cname; - nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); - EC_KEY_free(ec); - cname = EC_curve_nid2nist(nid); - if (cname == NULL) - cname = OBJ_nid2sn(nid); - BIO_printf(out, "ECDH, %s, %d bits\n", cname, EVP_PKEY_bits(key)); + char name[80]; + size_t name_len; + + if (!EVP_PKEY_get_utf8_string_param(key, OSSL_PKEY_PARAM_GROUP_NAME, + name, sizeof(name), &name_len)) + strcpy(name, "?"); + BIO_printf(out, "ECDH, %s, %d bits\n", name, EVP_PKEY_get_bits(key)); } break; #endif default: - BIO_printf(out, "%s, %d bits\n", OBJ_nid2sn(EVP_PKEY_id(key)), - EVP_PKEY_bits(key)); + BIO_printf(out, "%s, %d bits\n", OBJ_nid2sn(EVP_PKEY_get_id(key)), + EVP_PKEY_get_bits(key)); } EVP_PKEY_free(key); return 1; } -long bio_dump_callback(BIO *bio, int cmd, const char *argp, - int argi, long argl, long ret) +long bio_dump_callback(BIO *bio, int cmd, const char *argp, size_t len, + int argi, long argl, int ret, size_t *processed) { BIO *out; @@ -446,14 +436,23 @@ long bio_dump_callback(BIO *bio, int cmd, const char *argp, return ret; if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) { - BIO_printf(out, "read from %p [%p] (%lu bytes => %ld (0x%lX))\n", - (void *)bio, (void *)argp, (unsigned long)argi, ret, ret); - BIO_dump(out, argp, (int)ret); - return ret; + if (ret > 0 && processed != NULL) { + BIO_printf(out, "read from %p [%p] (%zu bytes => %zu (0x%zX))\n", + (void *)bio, (void *)argp, len, *processed, *processed); + BIO_dump(out, argp, (int)*processed); + } else { + BIO_printf(out, "read from %p [%p] (%zu bytes => %d)\n", + (void *)bio, (void *)argp, len, ret); + } } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) { - BIO_printf(out, "write to %p [%p] (%lu bytes => %ld (0x%lX))\n", - (void *)bio, (void *)argp, (unsigned long)argi, ret, ret); - BIO_dump(out, argp, (int)ret); + if (ret > 0 && processed != NULL) { + BIO_printf(out, "write to %p [%p] (%zu bytes => %zu (0x%zX))\n", + (void *)bio, (void *)argp, len, *processed, *processed); + BIO_dump(out, argp, (int)*processed); + } else { + BIO_printf(out, "write to %p [%p] (%zu bytes => %d)\n", + (void *)bio, (void *)argp, len, ret); + } } return ret; } @@ -569,8 +568,8 @@ void msg_cb(int write_p, int version, int content_type, const void *buf, { BIO *bio = arg; const char *str_write_p = write_p ? ">>>" : "<<<"; - const char *str_version = lookup(version, ssl_versions, "???"); - const char *str_content_type = "", *str_details1 = "", *str_details2 = ""; + char tmpbuf[128]; + const char *str_version, *str_content_type = "", *str_details1 = "", *str_details2 = ""; const unsigned char* bp = buf; if (version == SSL3_VERSION || @@ -579,11 +578,14 @@ void msg_cb(int write_p, int version, int content_type, const void *buf, version == TLS1_2_VERSION || version == TLS1_3_VERSION || version == DTLS1_VERSION || version == DTLS1_BAD_VER) { + str_version = lookup(version, ssl_versions, "???"); switch (content_type) { - case 20: + case SSL3_RT_CHANGE_CIPHER_SPEC: + /* type 20 */ str_content_type = ", ChangeCipherSpec"; break; - case 21: + case SSL3_RT_ALERT: + /* type 21 */ str_content_type = ", Alert"; str_details1 = ", ???"; if (len == 2) { @@ -598,32 +600,32 @@ void msg_cb(int write_p, int version, int content_type, const void *buf, str_details2 = lookup((int)bp[1], alert_types, " ???"); } break; - case 22: + case SSL3_RT_HANDSHAKE: + /* type 22 */ str_content_type = ", Handshake"; str_details1 = "???"; if (len > 0) str_details1 = lookup((int)bp[0], handshakes, "???"); break; - case 23: + case SSL3_RT_APPLICATION_DATA: + /* type 23 */ str_content_type = ", ApplicationData"; break; -#ifndef OPENSSL_NO_HEARTBEATS - case 24: - str_details1 = ", Heartbeat"; - - if (len > 0) { - switch (bp[0]) { - case 1: - str_details1 = ", HeartbeatRequest"; - break; - case 2: - str_details1 = ", HeartbeatResponse"; - break; - } - } + case SSL3_RT_HEADER: + /* type 256 */ + str_content_type = ", RecordHeader"; break; -#endif + case SSL3_RT_INNER_CONTENT_TYPE: + /* type 257 */ + str_content_type = ", InnerContent"; + break; + default: + BIO_snprintf(tmpbuf, sizeof(tmpbuf)-1, ", Unknown (content_type=%d)", content_type); + str_content_type = tmpbuf; } + } else { + BIO_snprintf(tmpbuf, sizeof(tmpbuf)-1, "Not TLS data or unknown version (version=%d, content_type=%d)", version, content_type); + str_version = tmpbuf; } BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version, @@ -663,7 +665,6 @@ static STRINT_PAIR tlsext_types[] = { {"SRP", TLSEXT_TYPE_srp}, {"signature algorithms", TLSEXT_TYPE_signature_algorithms}, {"use SRTP", TLSEXT_TYPE_use_srtp}, - {"heartbeat", TLSEXT_TYPE_heartbeat}, {"session ticket", TLSEXT_TYPE_session_ticket}, {"renegotiation info", TLSEXT_TYPE_renegotiate}, {"signed certificate timestamps", TLSEXT_TYPE_signed_certificate_timestamp}, @@ -750,13 +751,14 @@ void tlsext_cb(SSL *s, int client_server, int type, } #ifndef OPENSSL_NO_SOCK -int generate_cookie_callback(SSL *ssl, unsigned char *cookie, - unsigned int *cookie_len) +int generate_stateless_cookie_callback(SSL *ssl, unsigned char *cookie, + size_t *cookie_len) { - unsigned char *buffer; + unsigned char *buffer = NULL; size_t length = 0; unsigned short port; BIO_ADDR *lpeer = NULL, *peer = NULL; + int res = 0; /* Initialize a random secret */ if (!cookie_initialized) { @@ -783,6 +785,7 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie, /* Create buffer with peer's address and port */ if (!BIO_ADDR_rawaddress(peer, NULL, &length)) { BIO_printf(bio_err, "Failed getting peer address\n"); + BIO_ADDR_free(lpeer); return 0; } OPENSSL_assert(length != 0); @@ -793,26 +796,31 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie, memcpy(buffer, &port, sizeof(port)); BIO_ADDR_rawaddress(peer, buffer + sizeof(port), NULL); - /* Calculate HMAC of buffer using the secret */ - HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, - buffer, length, cookie, cookie_len); - + if (EVP_Q_mac(NULL, "HMAC", NULL, "SHA1", NULL, + cookie_secret, COOKIE_SECRET_LENGTH, buffer, length, + cookie, DTLS1_COOKIE_LENGTH, cookie_len) == NULL) { + BIO_printf(bio_err, + "Error calculating HMAC-SHA1 of buffer with secret\n"); + goto end; + } + res = 1; +end: OPENSSL_free(buffer); BIO_ADDR_free(lpeer); - return 1; + return res; } -int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, - unsigned int cookie_len) +int verify_stateless_cookie_callback(SSL *ssl, const unsigned char *cookie, + size_t cookie_len) { unsigned char result[EVP_MAX_MD_SIZE]; - unsigned int resultlength; + size_t resultlength; /* Note: we check cookie_initialized because if it's not, * it cannot be valid */ if (cookie_initialized - && generate_cookie_callback(ssl, result, &resultlength) + && generate_stateless_cookie_callback(ssl, result, &resultlength) && cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) return 1; @@ -820,21 +828,21 @@ int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, return 0; } -int generate_stateless_cookie_callback(SSL *ssl, unsigned char *cookie, - size_t *cookie_len) +int generate_cookie_callback(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len) { - unsigned int temp; - int res = generate_cookie_callback(ssl, cookie, &temp); + size_t temp = 0; + int res = generate_stateless_cookie_callback(ssl, cookie, &temp); if (res != 0) - *cookie_len = temp; + *cookie_len = (unsigned int)temp; return res; } -int verify_stateless_cookie_callback(SSL *ssl, const unsigned char *cookie, - size_t cookie_len) +int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, + unsigned int cookie_len) { - return verify_cookie_callback(ssl, cookie, cookie_len); + return verify_stateless_cookie_callback(ssl, cookie, cookie_len); } #endif @@ -898,6 +906,7 @@ static int set_cert_cb(SSL *ssl, void *arg) SSL_EXCERT *exc = arg; #ifdef CERT_CB_TEST_RETRY static int retry_cnt; + if (retry_cnt < 5) { retry_cnt++; BIO_printf(bio_err, @@ -996,6 +1005,7 @@ void ssl_excert_free(SSL_EXCERT *exc) int load_excert(SSL_EXCERT **pexc) { SSL_EXCERT *exc = *pexc; + if (exc == NULL) return 1; /* If nothing in list, free and set to NULL */ @@ -1015,16 +1025,15 @@ int load_excert(SSL_EXCERT **pexc) return 0; if (exc->keyfile != NULL) { exc->key = load_key(exc->keyfile, exc->keyform, - 0, NULL, NULL, "Server Key"); + 0, NULL, NULL, "server key"); } else { exc->key = load_key(exc->certfile, exc->certform, - 0, NULL, NULL, "Server Key"); + 0, NULL, NULL, "server key"); } if (exc->key == NULL) return 0; if (exc->chainfile != NULL) { - if (!load_certs(exc->chainfile, &exc->chain, FORMAT_PEM, NULL, - "Server Chain")) + if (!load_certs(exc->chainfile, 0, &exc->chain, NULL, "server chain")) return 0; } } @@ -1080,11 +1089,11 @@ int args_excert(int opt, SSL_EXCERT **pexc) exc->build_chain = 1; break; case OPT_X_CERTFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &exc->certform)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &exc->certform)) return 0; break; case OPT_X_KEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &exc->keyform)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &exc->keyform)) return 0; break; } @@ -1102,6 +1111,7 @@ static void print_raw_cipherlist(SSL *s) const unsigned char *rlist; static const unsigned char scsv_id[] = { 0, 0xFF }; size_t i, rlistlen, num; + if (!SSL_is_server(s)) return; num = SSL_get0_raw_cipherlist(s, NULL); @@ -1210,7 +1220,7 @@ void print_ssl_summary(SSL *s) c = SSL_get_current_cipher(s); BIO_printf(bio_err, "Ciphersuite: %s\n", SSL_CIPHER_get_name(c)); do_print_sigalgs(bio_err, s, 0); - peer = SSL_get_peer_certificate(s); + peer = SSL_get0_peer_certificate(s); if (peer != NULL) { int nid; @@ -1226,7 +1236,6 @@ void print_ssl_summary(SSL *s) } else { BIO_puts(bio_err, "No peer certificate\n"); } - X509_free(peer); #ifndef OPENSSL_NO_EC ssl_print_point_formats(bio_err, s); if (SSL_is_server(s)) @@ -1248,12 +1257,10 @@ int config_ctx(SSL_CONF_CTX *cctx, STACK_OF(OPENSSL_STRING) *str, for (i = 0; i < sk_OPENSSL_STRING_num(str); i += 2) { const char *flag = sk_OPENSSL_STRING_value(str, i); const char *arg = sk_OPENSSL_STRING_value(str, i + 1); + if (SSL_CONF_cmd(cctx, flag, arg) <= 0) { - if (arg != NULL) - BIO_printf(bio_err, "Error with command: \"%s %s\"\n", - flag, arg); - else - BIO_printf(bio_err, "Error with command: \"%s\"\n", flag); + BIO_printf(bio_err, "Call to SSL_CONF_cmd(%s, %s) failed\n", + flag, arg == NULL ? "<NULL>" : arg); ERR_print_errors(bio_err); return 0; } @@ -1269,17 +1276,20 @@ int config_ctx(SSL_CONF_CTX *cctx, STACK_OF(OPENSSL_STRING) *str, static int add_crls_store(X509_STORE *st, STACK_OF(X509_CRL) *crls) { X509_CRL *crl; - int i; + int i, ret = 1; + for (i = 0; i < sk_X509_CRL_num(crls); i++) { crl = sk_X509_CRL_value(crls, i); - X509_STORE_add_crl(st, crl); + if (!X509_STORE_add_crl(st, crl)) + ret = 0; } - return 1; + return ret; } int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, int crl_download) { X509_STORE *st; + st = SSL_CTX_get_cert_store(ctx); add_crls_store(st, crls); if (crl_download) @@ -1289,27 +1299,38 @@ int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, int crl_download) int ssl_load_stores(SSL_CTX *ctx, const char *vfyCApath, const char *vfyCAfile, + const char *vfyCAstore, const char *chCApath, const char *chCAfile, + const char *chCAstore, STACK_OF(X509_CRL) *crls, int crl_download) { X509_STORE *vfy = NULL, *ch = NULL; int rv = 0; - if (vfyCApath != NULL || vfyCAfile != NULL) { + + if (vfyCApath != NULL || vfyCAfile != NULL || vfyCAstore != NULL) { vfy = X509_STORE_new(); if (vfy == NULL) goto err; - if (!X509_STORE_load_locations(vfy, vfyCAfile, vfyCApath)) + if (vfyCAfile != NULL && !X509_STORE_load_file(vfy, vfyCAfile)) + goto err; + if (vfyCApath != NULL && !X509_STORE_load_path(vfy, vfyCApath)) + goto err; + if (vfyCAstore != NULL && !X509_STORE_load_store(vfy, vfyCAstore)) goto err; add_crls_store(vfy, crls); SSL_CTX_set1_verify_cert_store(ctx, vfy); if (crl_download) store_setup_crl_download(vfy); } - if (chCApath != NULL || chCAfile != NULL) { + if (chCApath != NULL || chCAfile != NULL || chCAstore != NULL) { ch = X509_STORE_new(); if (ch == NULL) goto err; - if (!X509_STORE_load_locations(ch, chCAfile, chCApath)) + if (chCAfile != NULL && !X509_STORE_load_file(ch, chCAfile)) + goto err; + if (chCApath != NULL && !X509_STORE_load_path(ch, chCApath)) + goto err; + if (chCAstore != NULL && !X509_STORE_load_store(ch, chCAstore)) goto err; SSL_CTX_set1_chain_cert_store(ctx, ch); } @@ -1362,6 +1383,7 @@ static int security_callback_debug(const SSL *s, const SSL_CTX *ctx, int rv, show_bits = 1, cert_md = 0; const char *nm; int show_nm; + rv = sdb->old_cb(s, ctx, op, bits, nid, other, ex); if (rv == 1 && sdb->verbose < 2) return 1; @@ -1411,26 +1433,25 @@ static int security_callback_debug(const SSL *s, const SSL_CTX *ctx, } break; #endif -#ifndef OPENSSL_NO_DH - case SSL_SECOP_OTHER_DH: - { - DH *dh = other; - BIO_printf(sdb->out, "%d", DH_bits(dh)); - break; - } -#endif case SSL_SECOP_OTHER_CERT: { if (cert_md) { int sig_nid = X509_get_signature_nid(other); + BIO_puts(sdb->out, OBJ_nid2sn(sig_nid)); } else { EVP_PKEY *pkey = X509_get0_pubkey(other); - const char *algname = ""; - EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, - &algname, EVP_PKEY_get0_asn1(pkey)); - BIO_printf(sdb->out, "%s, bits=%d", - algname, EVP_PKEY_bits(pkey)); + + if (pkey == NULL) { + BIO_printf(sdb->out, "Public key missing"); + } else { + const char *algname = ""; + + EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, + &algname, EVP_PKEY_get0_asn1(pkey)); + BIO_printf(sdb->out, "%s, bits=%d", + algname, EVP_PKEY_get_bits(pkey)); + } } break; } diff --git a/apps/s_socket.c b/apps/lib/s_socket.c index 96f16d2931cd..059afe47b904 100644 --- a/apps/s_socket.c +++ b/apps/lib/s_socket.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -26,12 +26,27 @@ typedef unsigned int u_int; #endif +#ifdef _WIN32 +# include <process.h> + +/* MSVC renamed some POSIX functions to have an underscore prefix. */ +# ifdef _MSC_VER +# define getpid _getpid +# endif +#endif + #ifndef OPENSSL_NO_SOCK # include "apps.h" # include "s_apps.h" # include "internal/sockets.h" +# if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_read)> +# endif +# endif + # include <openssl/bio.h> # include <openssl/err.h> @@ -160,7 +175,9 @@ int init_client(int *sock, const char *host, const char *port, if (*sock == INVALID_SOCKET) { if (bindaddr != NULL && !found) { BIO_printf(bio_err, "Can't bind %saddress for %s%s%s\n", +#ifdef AF_INET6 BIO_ADDRINFO_family(res) == AF_INET6 ? "IPv6 " : +#endif BIO_ADDRINFO_family(res) == AF_INET ? "IPv4 " : BIO_ADDRINFO_family(res) == AF_UNIX ? "unix " : "", bindhost != NULL ? bindhost : "", @@ -183,6 +200,42 @@ out: return ret; } +int report_server_accept(BIO *out, int asock, int with_address, int with_pid) +{ + int success = 1; + + if (BIO_printf(out, "ACCEPT") <= 0) + return 0; + if (with_address) { + union BIO_sock_info_u info; + char *hostname = NULL; + char *service = NULL; + + if ((info.addr = BIO_ADDR_new()) != NULL + && BIO_sock_info(asock, BIO_SOCK_INFO_ADDRESS, &info) + && (hostname = BIO_ADDR_hostname_string(info.addr, 1)) != NULL + && (service = BIO_ADDR_service_string(info.addr, 1)) != NULL) { + success = BIO_printf(out, + strchr(hostname, ':') == NULL + ? /* IPv4 */ " %s:%s" + : /* IPv6 */ " [%s]:%s", + hostname, service) > 0; + } else { + (void)BIO_printf(out, "unknown:error\n"); + success = 0; + } + OPENSSL_free(hostname); + OPENSSL_free(service); + BIO_ADDR_free(info.addr); + } + if (with_pid) + success = success && BIO_printf(out, " PID=%d", getpid()) > 0; + success = success && BIO_printf(out, "\n") > 0; + (void)BIO_flush(out); + + return success; +} + /* * do_server - helper routine to perform a server operation * @accept_sock: pointer to storage of resulting socket. @@ -239,6 +292,7 @@ int do_server(int *accept_sock, const char *host, const char *port, sock_protocol = BIO_ADDRINFO_protocol(res); sock_address = BIO_ADDRINFO_address(res); next = BIO_ADDRINFO_next(res); +#ifdef AF_INET6 if (sock_family == AF_INET6) sock_options |= BIO_SOCK_V6_ONLY; if (next != NULL @@ -257,6 +311,7 @@ int do_server(int *accept_sock, const char *host, const char *port, sock_options &= ~BIO_SOCK_V6_ONLY; } } +#endif asock = BIO_socket(sock_family, sock_type, sock_protocol, 0); if (asock == INVALID_SOCKET && sock_family_fallback != AF_UNSPEC) { @@ -296,36 +351,10 @@ int do_server(int *accept_sock, const char *host, const char *port, BIO_ADDRINFO_free(res); res = NULL; - if (sock_port == 0) { - /* dynamically allocated port, report which one */ - union BIO_sock_info_u info; - char *hostname = NULL; - char *service = NULL; - int success = 0; - - if ((info.addr = BIO_ADDR_new()) != NULL - && BIO_sock_info(asock, BIO_SOCK_INFO_ADDRESS, &info) - && (hostname = BIO_ADDR_hostname_string(info.addr, 1)) != NULL - && (service = BIO_ADDR_service_string(info.addr, 1)) != NULL - && BIO_printf(bio_s_out, - strchr(hostname, ':') == NULL - ? /* IPv4 */ "ACCEPT %s:%s\n" - : /* IPv6 */ "ACCEPT [%s]:%s\n", - hostname, service) > 0) - success = 1; - - (void)BIO_flush(bio_s_out); - OPENSSL_free(hostname); - OPENSSL_free(service); - BIO_ADDR_free(info.addr); - if (!success) { - BIO_closesocket(asock); - ERR_print_errors(bio_err); - goto end; - } - } else { - (void)BIO_printf(bio_s_out, "ACCEPT\n"); - (void)BIO_flush(bio_s_out); + if (!report_server_accept(bio_s_out, asock, sock_port == 0, 0)) { + BIO_closesocket(asock); + ERR_print_errors(bio_err); + goto end; } if (accept_sock != NULL) @@ -402,4 +431,25 @@ int do_server(int *accept_sock, const char *host, const char *port, return ret; } +void do_ssl_shutdown(SSL *ssl) +{ + int ret; + + do { + /* We only do unidirectional shutdown */ + ret = SSL_shutdown(ssl); + if (ret < 0) { + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_ASYNC: + case SSL_ERROR_WANT_ASYNC_JOB: + /* We just do busy waiting. Nothing clever */ + continue; + } + ret = 0; + } + } while (ret < 0); +} + #endif /* OPENSSL_NO_SOCK */ diff --git a/apps/lib/tlssrp_depr.c b/apps/lib/tlssrp_depr.c new file mode 100644 index 000000000000..91c19b096e9a --- /dev/null +++ b/apps/lib/tlssrp_depr.c @@ -0,0 +1,231 @@ +/* + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2005 Nokia. 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 + */ + +/* + * This file is to enable backwards compatibility for the SRP features of + * s_client, s_server and ciphers. All of those features are deprecated and will + * eventually disappear. In the meantime, to continue to support them, we + * need to access deprecated SRP APIs. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include <openssl/bn.h> +#include <openssl/bio.h> +#include <openssl/ssl.h> +#include <openssl/srp.h> +#include "apps_ui.h" +#include "apps.h" +#include "s_apps.h" + +static int srp_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g) +{ + BN_CTX *bn_ctx = BN_CTX_new(); + BIGNUM *p = BN_new(); + BIGNUM *r = BN_new(); + int ret = + g != NULL && N != NULL && bn_ctx != NULL && BN_is_odd(N) && + BN_check_prime(N, bn_ctx, NULL) == 1 && + p != NULL && BN_rshift1(p, N) && + /* p = (N-1)/2 */ + BN_check_prime(p, bn_ctx, NULL) == 1 && + r != NULL && + /* verify g^((N-1)/2) == -1 (mod N) */ + BN_mod_exp(r, g, p, N, bn_ctx) && + BN_add_word(r, 1) && BN_cmp(r, N) == 0; + + BN_free(r); + BN_free(p); + BN_CTX_free(bn_ctx); + return ret; +} + +/*- + * This callback is used here for two purposes: + * - extended debugging + * - making some primality tests for unknown groups + * The callback is only called for a non default group. + * + * An application does not need the call back at all if + * only the standard groups are used. In real life situations, + * client and server already share well known groups, + * thus there is no need to verify them. + * Furthermore, in case that a server actually proposes a group that + * is not one of those defined in RFC 5054, it is more appropriate + * to add the group to a static list and then compare since + * primality tests are rather cpu consuming. + */ + +static int ssl_srp_verify_param_cb(SSL *s, void *arg) +{ + SRP_ARG *srp_arg = (SRP_ARG *)arg; + BIGNUM *N = NULL, *g = NULL; + + if (((N = SSL_get_srp_N(s)) == NULL) || ((g = SSL_get_srp_g(s)) == NULL)) + return 0; + if (srp_arg->debug || srp_arg->msg || srp_arg->amp == 1) { + BIO_printf(bio_err, "SRP parameters:\n"); + BIO_printf(bio_err, "\tN="); + BN_print(bio_err, N); + BIO_printf(bio_err, "\n\tg="); + BN_print(bio_err, g); + BIO_printf(bio_err, "\n"); + } + + if (SRP_check_known_gN_param(g, N)) + return 1; + + if (srp_arg->amp == 1) { + if (srp_arg->debug) + BIO_printf(bio_err, + "SRP param N and g are not known params, going to check deeper.\n"); + + /* + * The srp_moregroups is a real debugging feature. Implementors + * should rather add the value to the known ones. The minimal size + * has already been tested. + */ + if (BN_num_bits(g) <= BN_BITS && srp_Verify_N_and_g(N, g)) + return 1; + } + BIO_printf(bio_err, "SRP param N and g rejected.\n"); + return 0; +} + +#define PWD_STRLEN 1024 + +static char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg) +{ + SRP_ARG *srp_arg = (SRP_ARG *)arg; + char *pass = app_malloc(PWD_STRLEN + 1, "SRP password buffer"); + PW_CB_DATA cb_tmp; + int l; + + cb_tmp.password = (char *)srp_arg->srppassin; + cb_tmp.prompt_info = "SRP user"; + if ((l = password_callback(pass, PWD_STRLEN, 0, &cb_tmp)) < 0) { + BIO_printf(bio_err, "Can't read Password\n"); + OPENSSL_free(pass); + return NULL; + } + *(pass + l) = '\0'; + + return pass; +} + +int set_up_srp_arg(SSL_CTX *ctx, SRP_ARG *srp_arg, int srp_lateuser, int c_msg, + int c_debug) +{ + if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg->srplogin)) { + BIO_printf(bio_err, "Unable to set SRP username\n"); + return 0; + } + srp_arg->msg = c_msg; + srp_arg->debug = c_debug; + SSL_CTX_set_srp_cb_arg(ctx, &srp_arg); + SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb); + SSL_CTX_set_srp_strength(ctx, srp_arg->strength); + if (c_msg || c_debug || srp_arg->amp == 0) + SSL_CTX_set_srp_verify_param_callback(ctx, ssl_srp_verify_param_cb); + + return 1; +} + +static char *dummy_srp(SSL *ssl, void *arg) +{ + return ""; +} + +void set_up_dummy_srp(SSL_CTX *ctx) +{ + SSL_CTX_set_srp_client_pwd_callback(ctx, dummy_srp); +} + +/* + * This callback pretends to require some asynchronous logic in order to + * obtain a verifier. When the callback is called for a new connection we + * return with a negative value. This will provoke the accept etc to return + * with an LOOKUP_X509. The main logic of the reinvokes the suspended call + * (which would normally occur after a worker has finished) and we set the + * user parameters. + */ +static int ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) +{ + srpsrvparm *p = (srpsrvparm *) arg; + int ret = SSL3_AL_FATAL; + + if (p->login == NULL && p->user == NULL) { + p->login = SSL_get_srp_username(s); + BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); + return -1; + } + + if (p->user == NULL) { + BIO_printf(bio_err, "User %s doesn't exist\n", p->login); + goto err; + } + + if (SSL_set_srp_server_param + (s, p->user->N, p->user->g, p->user->s, p->user->v, + p->user->info) < 0) { + *ad = SSL_AD_INTERNAL_ERROR; + goto err; + } + BIO_printf(bio_err, + "SRP parameters set: username = \"%s\" info=\"%s\" \n", + p->login, p->user->info); + ret = SSL_ERROR_NONE; + + err: + SRP_user_pwd_free(p->user); + p->user = NULL; + p->login = NULL; + return ret; +} + +int set_up_srp_verifier_file(SSL_CTX *ctx, srpsrvparm *srp_callback_parm, + char *srpuserseed, char *srp_verifier_file) +{ + int ret; + + srp_callback_parm->vb = SRP_VBASE_new(srpuserseed); + srp_callback_parm->user = NULL; + srp_callback_parm->login = NULL; + + if (srp_callback_parm->vb == NULL) { + BIO_printf(bio_err, "Failed to initialize SRP verifier file \n"); + return 0; + } + if ((ret = + SRP_VBASE_init(srp_callback_parm->vb, + srp_verifier_file)) != SRP_NO_ERROR) { + BIO_printf(bio_err, + "Cannot initialize SRP verifier file \"%s\":ret=%d\n", + srp_verifier_file, ret); + return 0; + } + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_callback); + SSL_CTX_set_srp_cb_arg(ctx, &srp_callback_parm); + SSL_CTX_set_srp_username_callback(ctx, ssl_srp_server_param_cb); + + return 1; +} + +void lookup_srp_user(srpsrvparm *srp_callback_parm, BIO *bio_s_out) +{ + SRP_user_pwd_free(srp_callback_parm->user); + srp_callback_parm->user = SRP_VBASE_get1_by_user(srp_callback_parm->vb, + srp_callback_parm->login); + + if (srp_callback_parm->user != NULL) + BIO_printf(bio_s_out, "LOOKUP done %s\n", + srp_callback_parm->user->info); + else + BIO_printf(bio_s_out, "LOOKUP not successful\n"); +} diff --git a/apps/lib/vms_decc_argv.c b/apps/lib/vms_decc_argv.c new file mode 100644 index 000000000000..031e5afdeca0 --- /dev/null +++ b/apps/lib/vms_decc_argv.c @@ -0,0 +1,72 @@ +/* + * Copyright 2015-2021 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 <stdlib.h> +#include <openssl/crypto.h> +#include "platform.h" /* for copy_argv() */ + +char **newargv = NULL; + +static void cleanup_argv(void) +{ + OPENSSL_free(newargv); + newargv = NULL; +} + +char **copy_argv(int *argc, char *argv[]) +{ + /*- + * The note below is for historical purpose. On VMS now we always + * copy argv "safely." + * + * 2011-03-22 SMS. + * If we have 32-bit pointers everywhere, then we're safe, and + * we bypass this mess, as on non-VMS systems. + * Problem 1: Compaq/HP C before V7.3 always used 32-bit + * pointers for argv[]. + * Fix 1: For a 32-bit argv[], when we're using 64-bit pointers + * everywhere else, we always allocate and use a 64-bit + * duplicate of argv[]. + * Problem 2: Compaq/HP C V7.3 (Alpha, IA64) before ECO1 failed + * to NULL-terminate a 64-bit argv[]. (As this was written, the + * compiler ECO was available only on IA64.) + * Fix 2: Unless advised not to (VMS_TRUST_ARGV), we test a + * 64-bit argv[argc] for NULL, and, if necessary, use a + * (properly) NULL-terminated (64-bit) duplicate of argv[]. + * The same code is used in either case to duplicate argv[]. + * Some of these decisions could be handled in preprocessing, + * but the code tends to get even uglier, and the penalty for + * deciding at compile- or run-time is tiny. + */ + + int i, count = *argc; + char **p = newargv; + + cleanup_argv(); + + /* + * We purposefully use OPENSSL_malloc() rather than app_malloc() here, + * to avoid symbol name clashes in test programs that would otherwise + * get them when linking with all of libapps.a. + * See comment in test/build.info. + */ + newargv = OPENSSL_malloc(sizeof(*newargv) * (count + 1)); + if (newargv == NULL) + return NULL; + + /* Register automatic cleanup on first use */ + if (p == NULL) + OPENSSL_atexit(cleanup_argv); + + for (i = 0; i < count; i++) + newargv[i] = argv[i]; + newargv[i] = NULL; + *argc = i; + return newargv; +} diff --git a/apps/lib/vms_term_sock.c b/apps/lib/vms_term_sock.c new file mode 100644 index 000000000000..97fb3943265c --- /dev/null +++ b/apps/lib/vms_term_sock.c @@ -0,0 +1,591 @@ +/* + * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016 VMS Software, Inc. 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 + */ + +#ifdef __VMS +# define OPENSSL_SYS_VMS +# pragma message disable DOLLARID + + +# include <openssl/opensslconf.h> + +# if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) +/* + * On VMS, you need to define this to get the declaration of fileno(). The + * value 2 is to make sure no function defined in POSIX-2 is left undefined. + */ +# define _POSIX_C_SOURCE 2 +# endif + +# include <stdio.h> + +# undef _POSIX_C_SOURCE + +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <inet.h> +# include <unistd.h> +# include <string.h> +# include <errno.h> +# include <starlet.h> +# include <iodef.h> +# ifdef __alpha +# include <iosbdef.h> +# else +typedef struct _iosb { /* Copied from IOSBDEF.H for Alpha */ +# pragma __nomember_alignment + __union { + __struct { + unsigned short int iosb$w_status; /* Final I/O status */ + __union { + __struct { /* 16-bit byte count variant */ + unsigned short int iosb$w_bcnt; /* 16-bit byte count */ + __union { + unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */ + unsigned int iosb$l_pid; /* 32-bit pid */ + } iosb$r_l; + } iosb$r_bcnt_16; + __struct { /* 32-bit byte count variant */ + unsigned int iosb$l_bcnt; /* 32-bit byte count (unaligned) */ + unsigned short int iosb$w_dev_depend_high; /* 16-bit device dependent info */ + } iosb$r_bcnt_32; + } iosb$r_devdepend; + } iosb$r_io_64; + __struct { + __union { + unsigned int iosb$l_getxxi_status; /* Final GETxxI status */ + unsigned int iosb$l_reg_status; /* Final $Registry status */ + } iosb$r_l_status; + unsigned int iosb$l_reserved; /* Reserved field */ + } iosb$r_get_64; + } iosb$r_io_get; +} IOSB; + +# if !defined(__VAXC) +# define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status +# define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt +# define iosb$r_l iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l +# define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend +# define iosb$l_pid iosb$r_l.iosb$l_pid +# define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt +# define iosb$w_dev_depend_high iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$w_dev_depend_high +# define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status +# define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status +# endif /* #if !defined(__VAXC) */ + +# endif /* End of IOSBDEF */ + +# include <efndef.h> +# include <stdlib.h> +# include <ssdef.h> +# include <time.h> +# include <stdarg.h> +# include <descrip.h> + +# include "vms_term_sock.h" + +# ifdef __alpha +static struct _iosb TerminalDeviceIosb; +# else +IOSB TerminalDeviceIosb; +# endif + +static char TerminalDeviceBuff[255 + 2]; +static int TerminalSocketPair[2] = {0, 0}; +static unsigned short TerminalDeviceChan = 0; + +static int CreateSocketPair (int, int, int, int *); +static void SocketPairTimeoutAst (int); +static int TerminalDeviceAst (int); +static void LogMessage (char *, ...); + +/* +** Socket Pair Timeout Value (must be 0-59 seconds) +*/ +# define SOCKET_PAIR_TIMEOUT_VALUE 20 + +/* +** Socket Pair Timeout Block which is passed to timeout AST +*/ +typedef struct _SocketPairTimeoutBlock { + unsigned short SockChan1; + unsigned short SockChan2; +} SPTB; + +# ifdef TERM_SOCK_TEST + +/*----------------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------------*/ +int main (int argc, char *argv[], char *envp[]) +{ + char TermBuff[80]; + int TermSock, + status, + len; + + LogMessage ("Enter 'q' or 'Q' to quit ..."); + while (OPENSSL_strcasecmp (TermBuff, "Q")) { + /* + ** Create the terminal socket + */ + status = TerminalSocket (TERM_SOCK_CREATE, &TermSock); + if (status != TERM_SOCK_SUCCESS) + exit (1); + + /* + ** Process the terminal input + */ + LogMessage ("Waiting on terminal I/O ...\n"); + len = recv (TermSock, TermBuff, sizeof(TermBuff), 0) ; + TermBuff[len] = '\0'; + LogMessage ("Received terminal I/O [%s]", TermBuff); + + /* + ** Delete the terminal socket + */ + status = TerminalSocket (TERM_SOCK_DELETE, &TermSock); + if (status != TERM_SOCK_SUCCESS) + exit (1); + } + + return 1; + +} +# endif + +/*----------------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------------*/ +int TerminalSocket (int FunctionCode, int *ReturnSocket) +{ + int status; + $DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND"); + + /* + ** Process the requested function code + */ + switch (FunctionCode) { + case TERM_SOCK_CREATE: + /* + ** Create a socket pair + */ + status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair); + if (status == -1) { + LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status); + if (TerminalSocketPair[0]) + close (TerminalSocketPair[0]); + if (TerminalSocketPair[1]) + close (TerminalSocketPair[1]); + return TERM_SOCK_FAILURE; + } + + /* + ** Assign a channel to the terminal device + */ + status = sys$assign (&TerminalDeviceDesc, + &TerminalDeviceChan, + 0, 0, 0); + if (! (status & 1)) { + LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status); + close (TerminalSocketPair[0]); + close (TerminalSocketPair[1]); + return TERM_SOCK_FAILURE; + } + + /* + ** Queue an async IO to the terminal device + */ + status = sys$qio (EFN$C_ENF, + TerminalDeviceChan, + IO$_READVBLK, + &TerminalDeviceIosb, + TerminalDeviceAst, + 0, + TerminalDeviceBuff, + sizeof(TerminalDeviceBuff) - 2, + 0, 0, 0, 0); + if (! (status & 1)) { + LogMessage ("TerminalSocket: SYS$QIO () - %08X", status); + close (TerminalSocketPair[0]); + close (TerminalSocketPair[1]); + return TERM_SOCK_FAILURE; + } + + /* + ** Return the input side of the socket pair + */ + *ReturnSocket = TerminalSocketPair[1]; + break; + + case TERM_SOCK_DELETE: + /* + ** Cancel any pending IO on the terminal channel + */ + status = sys$cancel (TerminalDeviceChan); + if (! (status & 1)) { + LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status); + close (TerminalSocketPair[0]); + close (TerminalSocketPair[1]); + return TERM_SOCK_FAILURE; + } + + /* + ** Deassign the terminal channel + */ + status = sys$dassgn (TerminalDeviceChan); + if (! (status & 1)) { + LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status); + close (TerminalSocketPair[0]); + close (TerminalSocketPair[1]); + return TERM_SOCK_FAILURE; + } + + /* + ** Close the terminal socket pair + */ + close (TerminalSocketPair[0]); + close (TerminalSocketPair[1]); + + /* + ** Return the initialized socket + */ + *ReturnSocket = 0; + break; + + default: + /* + ** Invalid function code + */ + LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode); + return TERM_SOCK_FAILURE; + break; + } + + /* + ** Return success + */ + return TERM_SOCK_SUCCESS; + +} + +/*----------------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------------*/ +static int CreateSocketPair (int SocketFamily, + int SocketType, + int SocketProtocol, + int *SocketPair) +{ + struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; + static const char* LocalHostAddr = {"127.0.0.1"}; + unsigned short TcpAcceptChan = 0, + TcpDeviceChan = 0; + unsigned long BinTimeBuff[2]; + struct sockaddr_in sin; + char AscTimeBuff[32]; + short LocalHostPort; + int status; + unsigned int slen; + +# ifdef __alpha + struct _iosb iosb; +# else + IOSB iosb; +# endif + + int SockDesc1 = 0, + SockDesc2 = 0; + SPTB sptb; + $DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE"); + + /* + ** Create a socket + */ + SockDesc1 = socket (SocketFamily, SocketType, 0); + if (SockDesc1 < 0) { + LogMessage ("CreateSocketPair: socket () - %d", errno); + return -1; + } + + /* + ** Initialize the socket information + */ + slen = sizeof(sin); + memset ((char *) &sin, 0, slen); + sin.sin_family = SocketFamily; + sin.sin_addr.s_addr = inet_addr (LocalHostAddr); + sin.sin_port = 0; + + /* + ** Bind the socket to the local IP + */ + status = bind (SockDesc1, (struct sockaddr *) &sin, slen); + if (status < 0) { + LogMessage ("CreateSocketPair: bind () - %d", errno); + close (SockDesc1); + return -1; + } + + /* + ** Get the socket name so we can save the port number + */ + status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen); + if (status < 0) { + LogMessage ("CreateSocketPair: getsockname () - %d", errno); + close (SockDesc1); + return -1; + } else + LocalHostPort = sin.sin_port; + + /* + ** Setup a listen for the socket + */ + listen (SockDesc1, 5); + + /* + ** Get the binary (64-bit) time of the specified timeout value + */ + sprintf (AscTimeBuff, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE); + AscTimeDesc.dsc$w_length = strlen (AscTimeBuff); + AscTimeDesc.dsc$a_pointer = AscTimeBuff; + status = sys$bintim (&AscTimeDesc, BinTimeBuff); + if (! (status & 1)) { + LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status); + close (SockDesc1); + return -1; + } + + /* + ** Assign another channel to the TCP/IP device for the accept. + ** This is the channel that ends up being connected to. + */ + status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0); + if (! (status & 1)) { + LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status); + close (SockDesc1); + return -1; + } + + /* + ** Get the channel of the first socket for the accept + */ + TcpAcceptChan = decc$get_sdc (SockDesc1); + + /* + ** Perform the accept using $QIO so we can do this asynchronously + */ + status = sys$qio (EFN$C_ENF, + TcpAcceptChan, + IO$_ACCESS | IO$M_ACCEPT, + &iosb, + 0, 0, 0, 0, 0, + &TcpDeviceChan, + 0, 0); + if (! (status & 1)) { + LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status); + close (SockDesc1); + sys$dassgn (TcpDeviceChan); + return -1; + } + + /* + ** Create the second socket to do the connect + */ + SockDesc2 = socket (SocketFamily, SocketType, 0); + if (SockDesc2 < 0) { + LogMessage ("CreateSocketPair: socket () - %d", errno); + sys$cancel (TcpAcceptChan); + close (SockDesc1); + sys$dassgn (TcpDeviceChan); + return (-1) ; + } + + /* + ** Setup the Socket Pair Timeout Block + */ + sptb.SockChan1 = TcpAcceptChan; + sptb.SockChan2 = decc$get_sdc (SockDesc2); + + /* + ** Before we block on the connect, set a timer that can cancel I/O on our + ** two sockets if it never connects. + */ + status = sys$setimr (EFN$C_ENF, + BinTimeBuff, + SocketPairTimeoutAst, + &sptb, + 0); + if (! (status & 1)) { + LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status); + sys$cancel (TcpAcceptChan); + close (SockDesc1); + close (SockDesc2); + sys$dassgn (TcpDeviceChan); + return -1; + } + + /* + ** Now issue the connect + */ + memset ((char *) &sin, 0, sizeof(sin)) ; + sin.sin_family = SocketFamily; + sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ; + sin.sin_port = LocalHostPort ; + + status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof(sin)); + if (status < 0 ) { + LogMessage ("CreateSocketPair: connect () - %d", errno); + sys$cantim (&sptb, 0); + sys$cancel (TcpAcceptChan); + close (SockDesc1); + close (SockDesc2); + sys$dassgn (TcpDeviceChan); + return -1; + } + + /* + ** Wait for the asynch $QIO to finish. Note that if the I/O was aborted + ** (SS$_ABORT), then we probably canceled it from the AST routine - so log + ** a timeout. + */ + status = sys$synch (EFN$C_ENF, &iosb); + if (! (iosb.iosb$w_status & 1)) { + if (iosb.iosb$w_status == SS$_ABORT) + LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout"); + else { + LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d", + iosb.iosb$w_status); + sys$cantim (&sptb, 0); + } + close (SockDesc1); + close (SockDesc2); + sys$dassgn (TcpDeviceChan); + return -1; + } + + /* + ** Here we're successfully connected, so cancel the timer, convert the + ** I/O channel to a socket fd, close the listener socket and return the + ** connected pair. + */ + sys$cantim (&sptb, 0); + + close (SockDesc1) ; + SocketPair[0] = SockDesc2 ; + SocketPair[1] = socket_fd (TcpDeviceChan); + + return (0) ; + +} + +/*----------------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------------*/ +static void SocketPairTimeoutAst (int astparm) +{ + SPTB *sptb = (SPTB *) astparm; + + sys$cancel (sptb->SockChan2); /* Cancel the connect() */ + sys$cancel (sptb->SockChan1); /* Cancel the accept() */ + + return; + +} + +/*----------------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------------*/ +static int TerminalDeviceAst (int astparm) +{ + int status; + + /* + ** Terminate the terminal buffer + */ + TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0'; + strcat (TerminalDeviceBuff, "\n"); + + /* + ** Send the data read from the terminal device through the socket pair + */ + send (TerminalSocketPair[0], TerminalDeviceBuff, + TerminalDeviceIosb.iosb$w_bcnt + 1, 0); + + /* + ** Queue another async IO to the terminal device + */ + status = sys$qio (EFN$C_ENF, + TerminalDeviceChan, + IO$_READVBLK, + &TerminalDeviceIosb, + TerminalDeviceAst, + 0, + TerminalDeviceBuff, + sizeof(TerminalDeviceBuff) - 1, + 0, 0, 0, 0); + + /* + ** Return status + */ + return status; + +} + +/*----------------------------------------------------------------------------*/ +/* */ +/*----------------------------------------------------------------------------*/ +static void LogMessage (char *msg, ...) +{ + char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + static unsigned int pid = 0; + va_list args; + time_t CurTime; + struct tm *LocTime; + char MsgBuff[256]; + + /* + ** Get the process pid + */ + if (pid == 0) + pid = getpid (); + + /* + ** Convert the current time into local time + */ + CurTime = time (NULL); + LocTime = localtime (&CurTime); + + /* + ** Format the message buffer + */ + sprintf (MsgBuff, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n", + LocTime->tm_mday, Month[LocTime->tm_mon], + (LocTime->tm_year + 1900), LocTime->tm_hour, LocTime->tm_min, + LocTime->tm_sec, pid, msg); + + /* + ** Get any variable arguments and add them to the print of the message + ** buffer + */ + va_start (args, msg); + vfprintf (stderr, MsgBuff, args); + va_end (args); + + /* + ** Flush standard error output + */ + fsync (fileno (stderr)); + + return; + +} +#endif diff --git a/apps/lib/win32_init.c b/apps/lib/win32_init.c new file mode 100644 index 000000000000..6d2be0c62942 --- /dev/null +++ b/apps/lib/win32_init.c @@ -0,0 +1,307 @@ +/* + * Copyright 2016-2020 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 <windows.h> +#include <stdlib.h> +#include <string.h> +#include <malloc.h> + +#if defined(CP_UTF8) + +static UINT saved_cp; +static int newargc; +static char **newargv; + +static void cleanup(void) +{ + int i; + + SetConsoleOutputCP(saved_cp); + + for (i = 0; i < newargc; i++) + free(newargv[i]); + + free(newargv); +} + +/* + * Incrementally [re]allocate newargv and keep it NULL-terminated. + */ +static int validate_argv(int argc) +{ + static int size = 0; + + if (argc >= size) { + char **ptr; + + while (argc >= size) + size += 64; + + ptr = realloc(newargv, size * sizeof(newargv[0])); + if (ptr == NULL) + return 0; + + (newargv = ptr)[argc] = NULL; + } else { + newargv[argc] = NULL; + } + + return 1; +} + +static int process_glob(WCHAR *wstr, int wlen) +{ + int i, slash, udlen; + WCHAR saved_char; + WIN32_FIND_DATAW data; + HANDLE h; + + /* + * Note that we support wildcard characters only in filename part + * of the path, and not in directories. Windows users are used to + * this, that's why recursive glob processing is not implemented. + */ + /* + * Start by looking for last slash or backslash, ... + */ + for (slash = 0, i = 0; i < wlen; i++) + if (wstr[i] == L'/' || wstr[i] == L'\\') + slash = i + 1; + /* + * ... then look for asterisk or question mark in the file name. + */ + for (i = slash; i < wlen; i++) + if (wstr[i] == L'*' || wstr[i] == L'?') + break; + + if (i == wlen) + return 0; /* definitely not a glob */ + + saved_char = wstr[wlen]; + wstr[wlen] = L'\0'; + h = FindFirstFileW(wstr, &data); + wstr[wlen] = saved_char; + if (h == INVALID_HANDLE_VALUE) + return 0; /* not a valid glob, just pass... */ + + if (slash) + udlen = WideCharToMultiByte(CP_UTF8, 0, wstr, slash, + NULL, 0, NULL, NULL); + else + udlen = 0; + + do { + int uflen; + char *arg; + + /* + * skip over . and .. + */ + if (data.cFileName[0] == L'.') { + if ((data.cFileName[1] == L'\0') || + (data.cFileName[1] == L'.' && data.cFileName[2] == L'\0')) + continue; + } + + if (!validate_argv(newargc + 1)) + break; + + /* + * -1 below means "scan for trailing '\0' *and* count it", + * so that |uflen| covers even trailing '\0'. + */ + uflen = WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1, + NULL, 0, NULL, NULL); + + arg = malloc(udlen + uflen); + if (arg == NULL) + break; + + if (udlen) + WideCharToMultiByte(CP_UTF8, 0, wstr, slash, + arg, udlen, NULL, NULL); + + WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1, + arg + udlen, uflen, NULL, NULL); + + newargv[newargc++] = arg; + } while (FindNextFileW(h, &data)); + + CloseHandle(h); + + return 1; +} + +void win32_utf8argv(int *argc, char **argv[]) +{ + const WCHAR *wcmdline; + WCHAR *warg, *wend, *p; + int wlen, ulen, valid = 1; + char *arg; + + if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) == 0) + return; + + newargc = 0; + newargv = NULL; + if (!validate_argv(newargc)) + return; + + wcmdline = GetCommandLineW(); + if (wcmdline == NULL) return; + + /* + * make a copy of the command line, since we might have to modify it... + */ + wlen = wcslen(wcmdline); + p = _alloca((wlen + 1) * sizeof(WCHAR)); + wcscpy(p, wcmdline); + + while (*p != L'\0') { + int in_quote = 0; + + if (*p == L' ' || *p == L'\t') { + p++; /* skip over whitespace */ + continue; + } + + /* + * Note: because we may need to fiddle with the number of backslashes, + * the argument string is copied into itself. This is safe because + * the number of characters will never expand. + */ + warg = wend = p; + while (*p != L'\0' + && (in_quote || (*p != L' ' && *p != L'\t'))) { + switch (*p) { + case L'\\': + /* + * Microsoft documentation on how backslashes are treated + * is: + * + * + Backslashes are interpreted literally, unless they + * immediately precede a double quotation mark. + * + If an even number of backslashes is followed by a double + * quotation mark, one backslash is placed in the argv array + * for every pair of backslashes, and the double quotation + * mark is interpreted as a string delimiter. + * + If an odd number of backslashes is followed by a double + * quotation mark, one backslash is placed in the argv array + * for every pair of backslashes, and the double quotation + * mark is "escaped" by the remaining backslash, causing a + * literal double quotation mark (") to be placed in argv. + * + * Ref: https://msdn.microsoft.com/en-us/library/17w5ykft.aspx + * + * Though referred page doesn't mention it, multiple qouble + * quotes are also special. Pair of double quotes in quoted + * string is counted as single double quote. + */ + { + const WCHAR *q = p; + int i; + + while (*p == L'\\') + p++; + + if (*p == L'"') { + int i; + + for (i = (p - q) / 2; i > 0; i--) + *wend++ = L'\\'; + + /* + * if odd amount of backslashes before the quote, + * said quote is part of the argument, not a delimiter + */ + if ((p - q) % 2 == 1) + *wend++ = *p++; + } else { + for (i = p - q; i > 0; i--) + *wend++ = L'\\'; + } + } + break; + case L'"': + /* + * Without the preceding backslash (or when preceded with an + * even number of backslashes), the double quote is a simple + * string delimiter and just slightly change the parsing state + */ + if (in_quote && p[1] == L'"') + *wend++ = *p++; + else + in_quote = !in_quote; + p++; + break; + default: + /* + * Any other non-delimiter character is just taken verbatim + */ + *wend++ = *p++; + } + } + + wlen = wend - warg; + + if (wlen == 0 || !process_glob(warg, wlen)) { + if (!validate_argv(newargc + 1)) { + valid = 0; + break; + } + + ulen = 0; + if (wlen > 0) { + ulen = WideCharToMultiByte(CP_UTF8, 0, warg, wlen, + NULL, 0, NULL, NULL); + if (ulen <= 0) + continue; + } + + arg = malloc(ulen + 1); + if (arg == NULL) { + valid = 0; + break; + } + + if (wlen > 0) + WideCharToMultiByte(CP_UTF8, 0, warg, wlen, + arg, ulen, NULL, NULL); + arg[ulen] = '\0'; + + newargv[newargc++] = arg; + } + } + + if (valid) { + saved_cp = GetConsoleOutputCP(); + SetConsoleOutputCP(CP_UTF8); + + *argc = newargc; + *argv = newargv; + + atexit(cleanup); + } else if (newargv != NULL) { + int i; + + for (i = 0; i < newargc; i++) + free(newargv[i]); + + free(newargv); + + newargc = 0; + newargv = NULL; + } + + return; +} +#else +void win32_utf8argv(int *argc, char **argv[]) +{ return; } +#endif diff --git a/apps/list.c b/apps/list.c new file mode 100644 index 000000000000..514abacfc835 --- /dev/null +++ b/apps/list.c @@ -0,0 +1,1706 @@ +/* + * Copyright 1995-2022 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 + */ + +/* We need to use some deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include <string.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/provider.h> +#include <openssl/safestack.h> +#include <openssl/kdf.h> +#include <openssl/encoder.h> +#include <openssl/decoder.h> +#include <openssl/store.h> +#include <openssl/core_names.h> +#include <openssl/rand.h> +#include "apps.h" +#include "app_params.h" +#include "progs.h" +#include "opt.h" +#include "names.h" + +static int verbose = 0; +static const char *select_name = NULL; + +/* Checks to see if algorithms are fetchable */ +#define IS_FETCHABLE(type, TYPE) \ + static int is_ ## type ## _fetchable(const TYPE *alg) \ + { \ + TYPE *impl; \ + const char *propq = app_get0_propq(); \ + OSSL_LIB_CTX *libctx = app_get0_libctx(); \ + const char *name = TYPE ## _get0_name(alg); \ + \ + ERR_set_mark(); \ + impl = TYPE ## _fetch(libctx, name, propq); \ + ERR_pop_to_mark(); \ + if (impl == NULL) \ + return 0; \ + TYPE ## _free(impl); \ + return 1; \ + } +IS_FETCHABLE(cipher, EVP_CIPHER) +IS_FETCHABLE(digest, EVP_MD) +IS_FETCHABLE(mac, EVP_MAC) +IS_FETCHABLE(kdf, EVP_KDF) +IS_FETCHABLE(rand, EVP_RAND) +IS_FETCHABLE(keymgmt, EVP_KEYMGMT) +IS_FETCHABLE(signature, EVP_SIGNATURE) +IS_FETCHABLE(kem, EVP_KEM) +IS_FETCHABLE(asym_cipher, EVP_ASYM_CIPHER) +IS_FETCHABLE(keyexch, EVP_KEYEXCH) +IS_FETCHABLE(decoder, OSSL_DECODER) +IS_FETCHABLE(encoder, OSSL_ENCODER) + +#ifndef OPENSSL_NO_DEPRECATED_3_0 +static int include_legacy(void) +{ + return app_get0_propq() == NULL; +} + +static void legacy_cipher_fn(const EVP_CIPHER *c, + const char *from, const char *to, void *arg) +{ + if (select_name != NULL + && (c == NULL + || OPENSSL_strcasecmp(select_name, EVP_CIPHER_get0_name(c)) != 0)) + return; + if (c != NULL) { + BIO_printf(arg, " %s\n", EVP_CIPHER_get0_name(c)); + } else { + if (from == NULL) + from = "<undefined>"; + if (to == NULL) + to = "<undefined>"; + BIO_printf(arg, " %s => %s\n", from, to); + } +} +#endif + +DEFINE_STACK_OF(EVP_CIPHER) +static int cipher_cmp(const EVP_CIPHER * const *a, + const EVP_CIPHER * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_CIPHER_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_CIPHER_get0_provider(*b))); +} + +static void collect_ciphers(EVP_CIPHER *cipher, void *stack) +{ + STACK_OF(EVP_CIPHER) *cipher_stack = stack; + + if (is_cipher_fetchable(cipher) + && sk_EVP_CIPHER_push(cipher_stack, cipher) > 0) + EVP_CIPHER_up_ref(cipher); +} + +static void list_ciphers(void) +{ + STACK_OF(EVP_CIPHER) *ciphers = sk_EVP_CIPHER_new(cipher_cmp); + int i; + + if (ciphers == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } +#ifndef OPENSSL_NO_DEPRECATED_3_0 + if (include_legacy()) { + BIO_printf(bio_out, "Legacy:\n"); + EVP_CIPHER_do_all_sorted(legacy_cipher_fn, bio_out); + } +#endif + + BIO_printf(bio_out, "Provided:\n"); + EVP_CIPHER_do_all_provided(app_get0_libctx(), collect_ciphers, ciphers); + sk_EVP_CIPHER_sort(ciphers); + for (i = 0; i < sk_EVP_CIPHER_num(ciphers); i++) { + const EVP_CIPHER *c = sk_EVP_CIPHER_value(ciphers, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_CIPHER_is_a(c, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_CIPHER_names_do_all(c, collect_names, names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_CIPHER_get0_provider(c))); + + if (verbose) { + const char *desc = EVP_CIPHER_get0_description(c); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("retrievable algorithm parameters", + EVP_CIPHER_gettable_params(c), 4); + print_param_types("retrievable operation parameters", + EVP_CIPHER_gettable_ctx_params(c), 4); + print_param_types("settable operation parameters", + EVP_CIPHER_settable_ctx_params(c), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_CIPHER_pop_free(ciphers, EVP_CIPHER_free); +} + +#ifndef OPENSSL_NO_DEPRECATED_3_0 +static void legacy_md_fn(const EVP_MD *m, + const char *from, const char *to, void *arg) +{ + if (m != NULL) { + BIO_printf(arg, " %s\n", EVP_MD_get0_name(m)); + } else { + if (from == NULL) + from = "<undefined>"; + if (to == NULL) + to = "<undefined>"; + BIO_printf((BIO *)arg, " %s => %s\n", from, to); + } +} +#endif + +DEFINE_STACK_OF(EVP_MD) +static int md_cmp(const EVP_MD * const *a, const EVP_MD * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_MD_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_MD_get0_provider(*b))); +} + +static void collect_digests(EVP_MD *digest, void *stack) +{ + STACK_OF(EVP_MD) *digest_stack = stack; + + if (is_digest_fetchable(digest) + && sk_EVP_MD_push(digest_stack, digest) > 0) + EVP_MD_up_ref(digest); +} + +static void list_digests(void) +{ + STACK_OF(EVP_MD) *digests = sk_EVP_MD_new(md_cmp); + int i; + + if (digests == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } +#ifndef OPENSSL_NO_DEPRECATED_3_0 + if (include_legacy()) { + BIO_printf(bio_out, "Legacy:\n"); + EVP_MD_do_all_sorted(legacy_md_fn, bio_out); + } +#endif + + BIO_printf(bio_out, "Provided:\n"); + EVP_MD_do_all_provided(app_get0_libctx(), collect_digests, digests); + sk_EVP_MD_sort(digests); + for (i = 0; i < sk_EVP_MD_num(digests); i++) { + const EVP_MD *m = sk_EVP_MD_value(digests, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_MD_is_a(m, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_MD_names_do_all(m, collect_names, names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_MD_get0_provider(m))); + + if (verbose) { + const char *desc = EVP_MD_get0_description(m); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("retrievable algorithm parameters", + EVP_MD_gettable_params(m), 4); + print_param_types("retrievable operation parameters", + EVP_MD_gettable_ctx_params(m), 4); + print_param_types("settable operation parameters", + EVP_MD_settable_ctx_params(m), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_MD_pop_free(digests, EVP_MD_free); +} + +DEFINE_STACK_OF(EVP_MAC) +static int mac_cmp(const EVP_MAC * const *a, const EVP_MAC * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_MAC_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_MAC_get0_provider(*b))); +} + +static void collect_macs(EVP_MAC *mac, void *stack) +{ + STACK_OF(EVP_MAC) *mac_stack = stack; + + if (is_mac_fetchable(mac) + && sk_EVP_MAC_push(mac_stack, mac) > 0) + EVP_MAC_up_ref(mac); +} + +static void list_macs(void) +{ + STACK_OF(EVP_MAC) *macs = sk_EVP_MAC_new(mac_cmp); + int i; + + if (macs == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Provided MACs:\n"); + EVP_MAC_do_all_provided(app_get0_libctx(), collect_macs, macs); + sk_EVP_MAC_sort(macs); + for (i = 0; i < sk_EVP_MAC_num(macs); i++) { + const EVP_MAC *m = sk_EVP_MAC_value(macs, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_MAC_is_a(m, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_MAC_names_do_all(m, collect_names, names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_MAC_get0_provider(m))); + + if (verbose) { + const char *desc = EVP_MAC_get0_description(m); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("retrievable algorithm parameters", + EVP_MAC_gettable_params(m), 4); + print_param_types("retrievable operation parameters", + EVP_MAC_gettable_ctx_params(m), 4); + print_param_types("settable operation parameters", + EVP_MAC_settable_ctx_params(m), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_MAC_pop_free(macs, EVP_MAC_free); +} + +/* + * KDFs and PRFs + */ +DEFINE_STACK_OF(EVP_KDF) +static int kdf_cmp(const EVP_KDF * const *a, const EVP_KDF * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_KDF_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_KDF_get0_provider(*b))); +} + +static void collect_kdfs(EVP_KDF *kdf, void *stack) +{ + STACK_OF(EVP_KDF) *kdf_stack = stack; + + if (is_kdf_fetchable(kdf) + && sk_EVP_KDF_push(kdf_stack, kdf) > 0) + EVP_KDF_up_ref(kdf); +} + +static void list_kdfs(void) +{ + STACK_OF(EVP_KDF) *kdfs = sk_EVP_KDF_new(kdf_cmp); + int i; + + if (kdfs == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Provided KDFs and PDFs:\n"); + EVP_KDF_do_all_provided(app_get0_libctx(), collect_kdfs, kdfs); + sk_EVP_KDF_sort(kdfs); + for (i = 0; i < sk_EVP_KDF_num(kdfs); i++) { + const EVP_KDF *k = sk_EVP_KDF_value(kdfs, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_KDF_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_KDF_names_do_all(k, collect_names, names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_KDF_get0_provider(k))); + + if (verbose) { + const char *desc = EVP_KDF_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("retrievable algorithm parameters", + EVP_KDF_gettable_params(k), 4); + print_param_types("retrievable operation parameters", + EVP_KDF_gettable_ctx_params(k), 4); + print_param_types("settable operation parameters", + EVP_KDF_settable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_KDF_pop_free(kdfs, EVP_KDF_free); +} + +/* + * RANDs + */ +DEFINE_STACK_OF(EVP_RAND) + +static int rand_cmp(const EVP_RAND * const *a, const EVP_RAND * const *b) +{ + int ret = OPENSSL_strcasecmp(EVP_RAND_get0_name(*a), EVP_RAND_get0_name(*b)); + + if (ret == 0) + ret = strcmp(OSSL_PROVIDER_get0_name(EVP_RAND_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_RAND_get0_provider(*b))); + + return ret; +} + +static void collect_rands(EVP_RAND *rand, void *stack) +{ + STACK_OF(EVP_RAND) *rand_stack = stack; + + if (is_rand_fetchable(rand) + && sk_EVP_RAND_push(rand_stack, rand) > 0) + EVP_RAND_up_ref(rand); +} + +static void list_random_generators(void) +{ + STACK_OF(EVP_RAND) *rands = sk_EVP_RAND_new(rand_cmp); + int i; + + if (rands == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Provided RNGs and seed sources:\n"); + EVP_RAND_do_all_provided(app_get0_libctx(), collect_rands, rands); + sk_EVP_RAND_sort(rands); + for (i = 0; i < sk_EVP_RAND_num(rands); i++) { + const EVP_RAND *m = sk_EVP_RAND_value(rands, i); + + if (select_name != NULL + && OPENSSL_strcasecmp(EVP_RAND_get0_name(m), select_name) != 0) + continue; + BIO_printf(bio_out, " %s", EVP_RAND_get0_name(m)); + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_RAND_get0_provider(m))); + + if (verbose) { + const char *desc = EVP_RAND_get0_description(m); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("retrievable algorithm parameters", + EVP_RAND_gettable_params(m), 4); + print_param_types("retrievable operation parameters", + EVP_RAND_gettable_ctx_params(m), 4); + print_param_types("settable operation parameters", + EVP_RAND_settable_ctx_params(m), 4); + } + } + sk_EVP_RAND_pop_free(rands, EVP_RAND_free); +} + +static void display_random(const char *name, EVP_RAND_CTX *drbg) +{ + EVP_RAND *rand; + uint64_t u; + const char *p; + const OSSL_PARAM *gettables; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + unsigned char buf[1000]; + + BIO_printf(bio_out, "%s:\n", name); + if (drbg != NULL) { + rand = EVP_RAND_CTX_get0_rand(drbg); + + BIO_printf(bio_out, " %s", EVP_RAND_get0_name(rand)); + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_RAND_get0_provider(rand))); + + switch (EVP_RAND_get_state(drbg)) { + case EVP_RAND_STATE_UNINITIALISED: + p = "uninitialised"; + break; + case EVP_RAND_STATE_READY: + p = "ready"; + break; + case EVP_RAND_STATE_ERROR: + p = "error"; + break; + default: + p = "unknown"; + break; + } + BIO_printf(bio_out, " state = %s\n", p); + + gettables = EVP_RAND_gettable_ctx_params(rand); + if (gettables != NULL) + for (; gettables->key != NULL; gettables++) { + /* State has been dealt with already, so ignore */ + if (OPENSSL_strcasecmp(gettables->key, OSSL_RAND_PARAM_STATE) == 0) + continue; + /* Outside of verbose mode, we skip non-string values */ + if (gettables->data_type != OSSL_PARAM_UTF8_STRING + && gettables->data_type != OSSL_PARAM_UTF8_PTR + && !verbose) + continue; + params->key = gettables->key; + params->data_type = gettables->data_type; + if (gettables->data_type == OSSL_PARAM_UNSIGNED_INTEGER + || gettables->data_type == OSSL_PARAM_INTEGER) { + params->data = &u; + params->data_size = sizeof(u); + } else { + params->data = buf; + params->data_size = sizeof(buf); + } + params->return_size = 0; + if (EVP_RAND_CTX_get_params(drbg, params)) + print_param_value(params, 2); + } + } +} + +static void list_random_instances(void) +{ + display_random("primary", RAND_get0_primary(NULL)); + display_random("public", RAND_get0_public(NULL)); + display_random("private", RAND_get0_private(NULL)); +} + +/* + * Encoders + */ +DEFINE_STACK_OF(OSSL_ENCODER) +static int encoder_cmp(const OSSL_ENCODER * const *a, + const OSSL_ENCODER * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(OSSL_ENCODER_get0_provider(*a)), + OSSL_PROVIDER_get0_name(OSSL_ENCODER_get0_provider(*b))); +} + +static void collect_encoders(OSSL_ENCODER *encoder, void *stack) +{ + STACK_OF(OSSL_ENCODER) *encoder_stack = stack; + + if (is_encoder_fetchable(encoder) + && sk_OSSL_ENCODER_push(encoder_stack, encoder) > 0) + OSSL_ENCODER_up_ref(encoder); +} + +static void list_encoders(void) +{ + STACK_OF(OSSL_ENCODER) *encoders; + int i; + + encoders = sk_OSSL_ENCODER_new(encoder_cmp); + if (encoders == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Provided ENCODERs:\n"); + OSSL_ENCODER_do_all_provided(app_get0_libctx(), collect_encoders, + encoders); + sk_OSSL_ENCODER_sort(encoders); + + for (i = 0; i < sk_OSSL_ENCODER_num(encoders); i++) { + OSSL_ENCODER *k = sk_OSSL_ENCODER_value(encoders, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !OSSL_ENCODER_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && OSSL_ENCODER_names_do_all(k, collect_names, names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s (%s)\n", + OSSL_PROVIDER_get0_name(OSSL_ENCODER_get0_provider(k)), + OSSL_ENCODER_get0_properties(k)); + + if (verbose) { + const char *desc = OSSL_ENCODER_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("settable operation parameters", + OSSL_ENCODER_settable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_OSSL_ENCODER_pop_free(encoders, OSSL_ENCODER_free); +} + +/* + * Decoders + */ +DEFINE_STACK_OF(OSSL_DECODER) +static int decoder_cmp(const OSSL_DECODER * const *a, + const OSSL_DECODER * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(OSSL_DECODER_get0_provider(*a)), + OSSL_PROVIDER_get0_name(OSSL_DECODER_get0_provider(*b))); +} + +static void collect_decoders(OSSL_DECODER *decoder, void *stack) +{ + STACK_OF(OSSL_DECODER) *decoder_stack = stack; + + if (is_decoder_fetchable(decoder) + && sk_OSSL_DECODER_push(decoder_stack, decoder) > 0) + OSSL_DECODER_up_ref(decoder); +} + +static void list_decoders(void) +{ + STACK_OF(OSSL_DECODER) *decoders; + int i; + + decoders = sk_OSSL_DECODER_new(decoder_cmp); + if (decoders == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Provided DECODERs:\n"); + OSSL_DECODER_do_all_provided(app_get0_libctx(), collect_decoders, + decoders); + sk_OSSL_DECODER_sort(decoders); + + for (i = 0; i < sk_OSSL_DECODER_num(decoders); i++) { + OSSL_DECODER *k = sk_OSSL_DECODER_value(decoders, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !OSSL_DECODER_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && OSSL_DECODER_names_do_all(k, collect_names, names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s (%s)\n", + OSSL_PROVIDER_get0_name(OSSL_DECODER_get0_provider(k)), + OSSL_DECODER_get0_properties(k)); + + if (verbose) { + const char *desc = OSSL_DECODER_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("settable operation parameters", + OSSL_DECODER_settable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_OSSL_DECODER_pop_free(decoders, OSSL_DECODER_free); +} + +DEFINE_STACK_OF(EVP_KEYMGMT) +static int keymanager_cmp(const EVP_KEYMGMT * const *a, + const EVP_KEYMGMT * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_KEYMGMT_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_KEYMGMT_get0_provider(*b))); +} + +static void collect_keymanagers(EVP_KEYMGMT *km, void *stack) +{ + STACK_OF(EVP_KEYMGMT) *km_stack = stack; + + if (is_keymgmt_fetchable(km) + && sk_EVP_KEYMGMT_push(km_stack, km) > 0) + EVP_KEYMGMT_up_ref(km); +} + +static void list_keymanagers(void) +{ + int i; + STACK_OF(EVP_KEYMGMT) *km_stack = sk_EVP_KEYMGMT_new(keymanager_cmp); + + EVP_KEYMGMT_do_all_provided(app_get0_libctx(), collect_keymanagers, + km_stack); + sk_EVP_KEYMGMT_sort(km_stack); + + for (i = 0; i < sk_EVP_KEYMGMT_num(km_stack); i++) { + EVP_KEYMGMT *k = sk_EVP_KEYMGMT_value(km_stack, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_KEYMGMT_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_KEYMGMT_names_do_all(k, collect_names, names)) { + const char *desc = EVP_KEYMGMT_get0_description(k); + + BIO_printf(bio_out, " Name: "); + if (desc != NULL) + BIO_printf(bio_out, "%s", desc); + else + BIO_printf(bio_out, "%s", sk_OPENSSL_CSTRING_value(names, 0)); + BIO_printf(bio_out, "\n"); + BIO_printf(bio_out, " Type: Provider Algorithm\n"); + BIO_printf(bio_out, " IDs: "); + print_names(bio_out, names); + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_KEYMGMT_get0_provider(k))); + + if (verbose) { + print_param_types("settable key generation parameters", + EVP_KEYMGMT_gen_settable_params(k), 4); + print_param_types("settable operation parameters", + EVP_KEYMGMT_settable_params(k), 4); + print_param_types("retrievable operation parameters", + EVP_KEYMGMT_gettable_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_KEYMGMT_pop_free(km_stack, EVP_KEYMGMT_free); +} + +DEFINE_STACK_OF(EVP_SIGNATURE) +static int signature_cmp(const EVP_SIGNATURE * const *a, + const EVP_SIGNATURE * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_SIGNATURE_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_SIGNATURE_get0_provider(*b))); +} + +static void collect_signatures(EVP_SIGNATURE *sig, void *stack) +{ + STACK_OF(EVP_SIGNATURE) *sig_stack = stack; + + if (is_signature_fetchable(sig) + && sk_EVP_SIGNATURE_push(sig_stack, sig) > 0) + EVP_SIGNATURE_up_ref(sig); +} + +static void list_signatures(void) +{ + int i, count = 0; + STACK_OF(EVP_SIGNATURE) *sig_stack = sk_EVP_SIGNATURE_new(signature_cmp); + + EVP_SIGNATURE_do_all_provided(app_get0_libctx(), collect_signatures, + sig_stack); + sk_EVP_SIGNATURE_sort(sig_stack); + + for (i = 0; i < sk_EVP_SIGNATURE_num(sig_stack); i++) { + EVP_SIGNATURE *k = sk_EVP_SIGNATURE_value(sig_stack, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_SIGNATURE_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_SIGNATURE_names_do_all(k, collect_names, names)) { + count++; + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_SIGNATURE_get0_provider(k))); + + if (verbose) { + const char *desc = EVP_SIGNATURE_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("settable operation parameters", + EVP_SIGNATURE_settable_ctx_params(k), 4); + print_param_types("retrievable operation parameters", + EVP_SIGNATURE_gettable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_SIGNATURE_pop_free(sig_stack, EVP_SIGNATURE_free); + if (count == 0) + BIO_printf(bio_out, " -\n"); +} + +DEFINE_STACK_OF(EVP_KEM) +static int kem_cmp(const EVP_KEM * const *a, + const EVP_KEM * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_KEM_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_KEM_get0_provider(*b))); +} + +static void collect_kem(EVP_KEM *kem, void *stack) +{ + STACK_OF(EVP_KEM) *kem_stack = stack; + + if (is_kem_fetchable(kem) + && sk_EVP_KEM_push(kem_stack, kem) > 0) + EVP_KEM_up_ref(kem); +} + +static void list_kems(void) +{ + int i, count = 0; + STACK_OF(EVP_KEM) *kem_stack = sk_EVP_KEM_new(kem_cmp); + + EVP_KEM_do_all_provided(app_get0_libctx(), collect_kem, kem_stack); + sk_EVP_KEM_sort(kem_stack); + + for (i = 0; i < sk_EVP_KEM_num(kem_stack); i++) { + EVP_KEM *k = sk_EVP_KEM_value(kem_stack, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_KEM_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_KEM_names_do_all(k, collect_names, names)) { + count++; + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_KEM_get0_provider(k))); + + if (verbose) { + const char *desc = EVP_KEM_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("settable operation parameters", + EVP_KEM_settable_ctx_params(k), 4); + print_param_types("retrievable operation parameters", + EVP_KEM_gettable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_KEM_pop_free(kem_stack, EVP_KEM_free); + if (count == 0) + BIO_printf(bio_out, " -\n"); +} + +DEFINE_STACK_OF(EVP_ASYM_CIPHER) +static int asymcipher_cmp(const EVP_ASYM_CIPHER * const *a, + const EVP_ASYM_CIPHER * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_ASYM_CIPHER_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_ASYM_CIPHER_get0_provider(*b))); +} + +static void collect_asymciph(EVP_ASYM_CIPHER *asym_cipher, void *stack) +{ + STACK_OF(EVP_ASYM_CIPHER) *asym_cipher_stack = stack; + + if (is_asym_cipher_fetchable(asym_cipher) + && sk_EVP_ASYM_CIPHER_push(asym_cipher_stack, asym_cipher) > 0) + EVP_ASYM_CIPHER_up_ref(asym_cipher); +} + +static void list_asymciphers(void) +{ + int i, count = 0; + STACK_OF(EVP_ASYM_CIPHER) *asymciph_stack = + sk_EVP_ASYM_CIPHER_new(asymcipher_cmp); + + EVP_ASYM_CIPHER_do_all_provided(app_get0_libctx(), collect_asymciph, + asymciph_stack); + sk_EVP_ASYM_CIPHER_sort(asymciph_stack); + + for (i = 0; i < sk_EVP_ASYM_CIPHER_num(asymciph_stack); i++) { + EVP_ASYM_CIPHER *k = sk_EVP_ASYM_CIPHER_value(asymciph_stack, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_ASYM_CIPHER_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL + && EVP_ASYM_CIPHER_names_do_all(k, collect_names, names)) { + count++; + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_ASYM_CIPHER_get0_provider(k))); + + if (verbose) { + const char *desc = EVP_ASYM_CIPHER_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("settable operation parameters", + EVP_ASYM_CIPHER_settable_ctx_params(k), 4); + print_param_types("retrievable operation parameters", + EVP_ASYM_CIPHER_gettable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_ASYM_CIPHER_pop_free(asymciph_stack, EVP_ASYM_CIPHER_free); + if (count == 0) + BIO_printf(bio_out, " -\n"); +} + +DEFINE_STACK_OF(EVP_KEYEXCH) +static int kex_cmp(const EVP_KEYEXCH * const *a, + const EVP_KEYEXCH * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(EVP_KEYEXCH_get0_provider(*a)), + OSSL_PROVIDER_get0_name(EVP_KEYEXCH_get0_provider(*b))); +} + +static void collect_kex(EVP_KEYEXCH *kex, void *stack) +{ + STACK_OF(EVP_KEYEXCH) *kex_stack = stack; + + if (is_keyexch_fetchable(kex) + && sk_EVP_KEYEXCH_push(kex_stack, kex) > 0) + EVP_KEYEXCH_up_ref(kex); +} + +static void list_keyexchanges(void) +{ + int i, count = 0; + STACK_OF(EVP_KEYEXCH) *kex_stack = sk_EVP_KEYEXCH_new(kex_cmp); + + EVP_KEYEXCH_do_all_provided(app_get0_libctx(), collect_kex, kex_stack); + sk_EVP_KEYEXCH_sort(kex_stack); + + for (i = 0; i < sk_EVP_KEYEXCH_num(kex_stack); i++) { + EVP_KEYEXCH *k = sk_EVP_KEYEXCH_value(kex_stack, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !EVP_KEYEXCH_is_a(k, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && EVP_KEYEXCH_names_do_all(k, collect_names, names)) { + count++; + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(EVP_KEYEXCH_get0_provider(k))); + + if (verbose) { + const char *desc = EVP_KEYEXCH_get0_description(k); + + if (desc != NULL) + BIO_printf(bio_out, " description: %s\n", desc); + print_param_types("settable operation parameters", + EVP_KEYEXCH_settable_ctx_params(k), 4); + print_param_types("retrievable operation parameters", + EVP_KEYEXCH_gettable_ctx_params(k), 4); + } + } + sk_OPENSSL_CSTRING_free(names); + } + sk_EVP_KEYEXCH_pop_free(kex_stack, EVP_KEYEXCH_free); + if (count == 0) + BIO_printf(bio_out, " -\n"); +} + +static void list_objects(void) +{ + int max_nid = OBJ_new_nid(0); + int i; + char *oid_buf = NULL; + int oid_size = 0; + + /* Skip 0, since that's NID_undef */ + for (i = 1; i < max_nid; i++) { + const ASN1_OBJECT *obj = OBJ_nid2obj(i); + const char *sn = OBJ_nid2sn(i); + const char *ln = OBJ_nid2ln(i); + int n = 0; + + /* + * If one of the retrieved objects somehow generated an error, + * we ignore it. The check for NID_undef below will detect the + * error and simply skip to the next NID. + */ + ERR_clear_error(); + + if (OBJ_obj2nid(obj) == NID_undef) + continue; + + if ((n = OBJ_obj2txt(NULL, 0, obj, 1)) == 0) { + BIO_printf(bio_out, "# None-OID object: %s, %s\n", sn, ln); + continue; + } + if (n < 0) + break; /* Error */ + + if (n > oid_size) { + oid_buf = OPENSSL_realloc(oid_buf, n + 1); + if (oid_buf == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + break; /* Error */ + } + oid_size = n + 1; + } + if (OBJ_obj2txt(oid_buf, oid_size, obj, 1) < 0) + break; /* Error */ + if (ln == NULL || strcmp(sn, ln) == 0) + BIO_printf(bio_out, "%s = %s\n", sn, oid_buf); + else + BIO_printf(bio_out, "%s = %s, %s\n", sn, ln, oid_buf); + } + + OPENSSL_free(oid_buf); +} + +static void list_options_for_command(const char *command) +{ + const FUNCTION *fp; + const OPTIONS *o; + + for (fp = functions; fp->name != NULL; fp++) + if (strcmp(fp->name, command) == 0) + break; + if (fp->name == NULL) { + BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n", + command); + return; + } + + if ((o = fp->help) == NULL) + return; + + for ( ; o->name != NULL; o++) { + char c = o->valtype; + + if (o->name == OPT_PARAM_STR) + break; + + if (o->name == OPT_HELP_STR + || o->name == OPT_MORE_STR + || o->name == OPT_SECTION_STR + || o->name[0] == '\0') + continue; + BIO_printf(bio_out, "%s %c\n", o->name, c == '\0' ? '-' : c); + } + /* Always output the -- marker since it is sometimes documented. */ + BIO_printf(bio_out, "- -\n"); +} + +static int is_md_available(const char *name) +{ + EVP_MD *md; + const char *propq = app_get0_propq(); + + /* Look through providers' digests */ + ERR_set_mark(); + md = EVP_MD_fetch(app_get0_libctx(), name, propq); + ERR_pop_to_mark(); + if (md != NULL) { + EVP_MD_free(md); + return 1; + } + + return propq != NULL || get_digest_from_engine(name) == NULL ? 0 : 1; +} + +static int is_cipher_available(const char *name) +{ + EVP_CIPHER *cipher; + const char *propq = app_get0_propq(); + + /* Look through providers' ciphers */ + ERR_set_mark(); + cipher = EVP_CIPHER_fetch(app_get0_libctx(), name, propq); + ERR_pop_to_mark(); + if (cipher != NULL) { + EVP_CIPHER_free(cipher); + return 1; + } + + return propq != NULL || get_cipher_from_engine(name) == NULL ? 0 : 1; +} + +static void list_type(FUNC_TYPE ft, int one) +{ + FUNCTION *fp; + int i = 0; + DISPLAY_COLUMNS dc; + + memset(&dc, 0, sizeof(dc)); + if (!one) + calculate_columns(functions, &dc); + + for (fp = functions; fp->name != NULL; fp++) { + if (fp->type != ft) + continue; + switch (ft) { + case FT_cipher: + if (!is_cipher_available(fp->name)) + continue; + break; + case FT_md: + if (!is_md_available(fp->name)) + continue; + break; + default: + break; + } + if (one) { + BIO_printf(bio_out, "%s\n", fp->name); + } else { + if (i % dc.columns == 0 && i > 0) + BIO_printf(bio_out, "\n"); + BIO_printf(bio_out, "%-*s", dc.width, fp->name); + i++; + } + } + if (!one) + BIO_printf(bio_out, "\n\n"); +} + +static void list_pkey(void) +{ +#ifndef OPENSSL_NO_DEPRECATED_3_0 + int i; + + if (select_name == NULL && include_legacy()) { + BIO_printf(bio_out, "Legacy:\n"); + for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id, pkey_base_id, pkey_flags; + const char *pinfo, *pem_str; + ameth = EVP_PKEY_asn1_get0(i); + EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags, + &pinfo, &pem_str, ameth); + if (pkey_flags & ASN1_PKEY_ALIAS) { + BIO_printf(bio_out, " Name: %s\n", OBJ_nid2ln(pkey_id)); + BIO_printf(bio_out, "\tAlias for: %s\n", + OBJ_nid2ln(pkey_base_id)); + } else { + BIO_printf(bio_out, " Name: %s\n", pinfo); + BIO_printf(bio_out, "\tType: %s Algorithm\n", + pkey_flags & ASN1_PKEY_DYNAMIC ? + "External" : "Builtin"); + BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id)); + if (pem_str == NULL) + pem_str = "(none)"; + BIO_printf(bio_out, "\tPEM string: %s\n", pem_str); + } + } + } +#endif + BIO_printf(bio_out, "Provided:\n"); + BIO_printf(bio_out, " Key Managers:\n"); + list_keymanagers(); +} + +static void list_pkey_meth(void) +{ +#ifndef OPENSSL_NO_DEPRECATED_3_0 + size_t i; + size_t meth_count = EVP_PKEY_meth_get_count(); + + if (select_name == NULL && include_legacy()) { + BIO_printf(bio_out, "Legacy:\n"); + for (i = 0; i < meth_count; i++) { + const EVP_PKEY_METHOD *pmeth = EVP_PKEY_meth_get0(i); + int pkey_id, pkey_flags; + + EVP_PKEY_meth_get0_info(&pkey_id, &pkey_flags, pmeth); + BIO_printf(bio_out, " %s\n", OBJ_nid2ln(pkey_id)); + BIO_printf(bio_out, "\tType: %s Algorithm\n", + pkey_flags & ASN1_PKEY_DYNAMIC ? "External" : "Builtin"); + } + } +#endif + BIO_printf(bio_out, "Provided:\n"); + BIO_printf(bio_out, " Encryption:\n"); + list_asymciphers(); + BIO_printf(bio_out, " Key Exchange:\n"); + list_keyexchanges(); + BIO_printf(bio_out, " Signatures:\n"); + list_signatures(); + BIO_printf(bio_out, " Key encapsulation:\n"); + list_kems(); +} + +DEFINE_STACK_OF(OSSL_STORE_LOADER) +static int store_cmp(const OSSL_STORE_LOADER * const *a, + const OSSL_STORE_LOADER * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(OSSL_STORE_LOADER_get0_provider(*a)), + OSSL_PROVIDER_get0_name(OSSL_STORE_LOADER_get0_provider(*b))); +} + +static void collect_store_loaders(OSSL_STORE_LOADER *store, void *stack) +{ + STACK_OF(OSSL_STORE_LOADER) *store_stack = stack; + + if (sk_OSSL_STORE_LOADER_push(store_stack, store) > 0) + OSSL_STORE_LOADER_up_ref(store); +} + +static void list_store_loaders(void) +{ + STACK_OF(OSSL_STORE_LOADER) *stores = sk_OSSL_STORE_LOADER_new(store_cmp); + int i; + + if (stores == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Provided STORE LOADERs:\n"); + OSSL_STORE_LOADER_do_all_provided(app_get0_libctx(), collect_store_loaders, + stores); + sk_OSSL_STORE_LOADER_sort(stores); + for (i = 0; i < sk_OSSL_STORE_LOADER_num(stores); i++) { + const OSSL_STORE_LOADER *m = sk_OSSL_STORE_LOADER_value(stores, i); + STACK_OF(OPENSSL_CSTRING) *names = NULL; + + if (select_name != NULL && !OSSL_STORE_LOADER_is_a(m, select_name)) + continue; + + names = sk_OPENSSL_CSTRING_new(name_cmp); + if (names != NULL && OSSL_STORE_LOADER_names_do_all(m, collect_names, + names)) { + BIO_printf(bio_out, " "); + print_names(bio_out, names); + + BIO_printf(bio_out, " @ %s\n", + OSSL_PROVIDER_get0_name(OSSL_STORE_LOADER_get0_provider(m))); + } + sk_OPENSSL_CSTRING_free(names); + } + sk_OSSL_STORE_LOADER_pop_free(stores, OSSL_STORE_LOADER_free); +} + +DEFINE_STACK_OF(OSSL_PROVIDER) +static int provider_cmp(const OSSL_PROVIDER * const *a, + const OSSL_PROVIDER * const *b) +{ + return strcmp(OSSL_PROVIDER_get0_name(*a), OSSL_PROVIDER_get0_name(*b)); +} + +static int collect_providers(OSSL_PROVIDER *provider, void *stack) +{ + STACK_OF(OSSL_PROVIDER) *provider_stack = stack; + + sk_OSSL_PROVIDER_push(provider_stack, provider); + return 1; +} + +static void list_provider_info(void) +{ + STACK_OF(OSSL_PROVIDER) *providers = sk_OSSL_PROVIDER_new(provider_cmp); + OSSL_PARAM params[5]; + char *name, *version, *buildinfo; + int status; + int i; + + if (providers == NULL) { + BIO_printf(bio_err, "ERROR: Memory allocation\n"); + return; + } + BIO_printf(bio_out, "Providers:\n"); + OSSL_PROVIDER_do_all(NULL, &collect_providers, providers); + sk_OSSL_PROVIDER_sort(providers); + for (i = 0; i < sk_OSSL_PROVIDER_num(providers); i++) { + const OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(providers, i); + + /* Query the "known" information parameters, the order matches below */ + params[0] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_NAME, + &name, 0); + params[1] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_VERSION, + &version, 0); + params[2] = OSSL_PARAM_construct_int(OSSL_PROV_PARAM_STATUS, &status); + params[3] = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_BUILDINFO, + &buildinfo, 0); + params[4] = OSSL_PARAM_construct_end(); + OSSL_PARAM_set_all_unmodified(params); + if (!OSSL_PROVIDER_get_params(prov, params)) { + BIO_printf(bio_err, "ERROR: Unable to query provider parameters\n"); + return; + } + + /* Print out the provider information, the params order matches above */ + BIO_printf(bio_out, " %s\n", OSSL_PROVIDER_get0_name(prov)); + if (OSSL_PARAM_modified(params)) + BIO_printf(bio_out, " name: %s\n", name); + if (OSSL_PARAM_modified(params + 1)) + BIO_printf(bio_out, " version: %s\n", version); + if (OSSL_PARAM_modified(params + 2)) + BIO_printf(bio_out, " status: %sactive\n", status ? "" : "in"); + if (verbose) { + if (OSSL_PARAM_modified(params + 3)) + BIO_printf(bio_out, " build info: %s\n", buildinfo); + print_param_types("gettable provider parameters", + OSSL_PROVIDER_gettable_params(prov), 4); + } + } + sk_OSSL_PROVIDER_free(providers); +} + +#ifndef OPENSSL_NO_DEPRECATED_3_0 +static void list_engines(void) +{ +# ifndef OPENSSL_NO_ENGINE + ENGINE *e; + + BIO_puts(bio_out, "Engines:\n"); + e = ENGINE_get_first(); + while (e) { + BIO_printf(bio_out, "%s\n", ENGINE_get_id(e)); + e = ENGINE_get_next(e); + } +# else + BIO_puts(bio_out, "Engine support is disabled.\n"); +# endif +} +#endif + +static void list_disabled(void) +{ + BIO_puts(bio_out, "Disabled algorithms:\n"); +#ifdef OPENSSL_NO_ARIA + BIO_puts(bio_out, "ARIA\n"); +#endif +#ifdef OPENSSL_NO_BF + BIO_puts(bio_out, "BF\n"); +#endif +#ifdef OPENSSL_NO_BLAKE2 + BIO_puts(bio_out, "BLAKE2\n"); +#endif +#ifdef OPENSSL_NO_CAMELLIA + BIO_puts(bio_out, "CAMELLIA\n"); +#endif +#ifdef OPENSSL_NO_CAST + BIO_puts(bio_out, "CAST\n"); +#endif +#ifdef OPENSSL_NO_CMAC + BIO_puts(bio_out, "CMAC\n"); +#endif +#ifdef OPENSSL_NO_CMS + BIO_puts(bio_out, "CMS\n"); +#endif +#ifdef OPENSSL_NO_COMP + BIO_puts(bio_out, "COMP\n"); +#endif +#ifdef OPENSSL_NO_DES + BIO_puts(bio_out, "DES\n"); +#endif +#ifdef OPENSSL_NO_DGRAM + BIO_puts(bio_out, "DGRAM\n"); +#endif +#ifdef OPENSSL_NO_DH + BIO_puts(bio_out, "DH\n"); +#endif +#ifdef OPENSSL_NO_DSA + BIO_puts(bio_out, "DSA\n"); +#endif +#if defined(OPENSSL_NO_DTLS) + BIO_puts(bio_out, "DTLS\n"); +#endif +#if defined(OPENSSL_NO_DTLS1) + BIO_puts(bio_out, "DTLS1\n"); +#endif +#if defined(OPENSSL_NO_DTLS1_2) + BIO_puts(bio_out, "DTLS1_2\n"); +#endif +#ifdef OPENSSL_NO_EC + BIO_puts(bio_out, "EC\n"); +#endif +#ifdef OPENSSL_NO_EC2M + BIO_puts(bio_out, "EC2M\n"); +#endif +#if defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0) + BIO_puts(bio_out, "ENGINE\n"); +#endif +#ifdef OPENSSL_NO_GOST + BIO_puts(bio_out, "GOST\n"); +#endif +#ifdef OPENSSL_NO_IDEA + BIO_puts(bio_out, "IDEA\n"); +#endif +#ifdef OPENSSL_NO_MD2 + BIO_puts(bio_out, "MD2\n"); +#endif +#ifdef OPENSSL_NO_MD4 + BIO_puts(bio_out, "MD4\n"); +#endif +#ifdef OPENSSL_NO_MD5 + BIO_puts(bio_out, "MD5\n"); +#endif +#ifdef OPENSSL_NO_MDC2 + BIO_puts(bio_out, "MDC2\n"); +#endif +#ifdef OPENSSL_NO_OCB + BIO_puts(bio_out, "OCB\n"); +#endif +#ifdef OPENSSL_NO_OCSP + BIO_puts(bio_out, "OCSP\n"); +#endif +#ifdef OPENSSL_NO_PSK + BIO_puts(bio_out, "PSK\n"); +#endif +#ifdef OPENSSL_NO_RC2 + BIO_puts(bio_out, "RC2\n"); +#endif +#ifdef OPENSSL_NO_RC4 + BIO_puts(bio_out, "RC4\n"); +#endif +#ifdef OPENSSL_NO_RC5 + BIO_puts(bio_out, "RC5\n"); +#endif +#ifdef OPENSSL_NO_RMD160 + BIO_puts(bio_out, "RMD160\n"); +#endif +#ifdef OPENSSL_NO_SCRYPT + BIO_puts(bio_out, "SCRYPT\n"); +#endif +#ifdef OPENSSL_NO_SCTP + BIO_puts(bio_out, "SCTP\n"); +#endif +#ifdef OPENSSL_NO_SEED + BIO_puts(bio_out, "SEED\n"); +#endif +#ifdef OPENSSL_NO_SM2 + BIO_puts(bio_out, "SM2\n"); +#endif +#ifdef OPENSSL_NO_SM3 + BIO_puts(bio_out, "SM3\n"); +#endif +#ifdef OPENSSL_NO_SM4 + BIO_puts(bio_out, "SM4\n"); +#endif +#ifdef OPENSSL_NO_SOCK + BIO_puts(bio_out, "SOCK\n"); +#endif +#ifdef OPENSSL_NO_SRP + BIO_puts(bio_out, "SRP\n"); +#endif +#ifdef OPENSSL_NO_SRTP + BIO_puts(bio_out, "SRTP\n"); +#endif +#ifdef OPENSSL_NO_SSL3 + BIO_puts(bio_out, "SSL3\n"); +#endif +#ifdef OPENSSL_NO_TLS1 + BIO_puts(bio_out, "TLS1\n"); +#endif +#ifdef OPENSSL_NO_TLS1_1 + BIO_puts(bio_out, "TLS1_1\n"); +#endif +#ifdef OPENSSL_NO_TLS1_2 + BIO_puts(bio_out, "TLS1_2\n"); +#endif +#ifdef OPENSSL_NO_WHIRLPOOL + BIO_puts(bio_out, "WHIRLPOOL\n"); +#endif +#ifndef ZLIB + BIO_puts(bio_out, "ZLIB\n"); +#endif +} + +/* Unified enum for help and list commands. */ +typedef enum HELPLIST_CHOICE { + OPT_COMMON, + OPT_ONE, OPT_VERBOSE, + OPT_COMMANDS, OPT_DIGEST_COMMANDS, OPT_MAC_ALGORITHMS, OPT_OPTIONS, + OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS, + OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_DISABLED, + OPT_KDF_ALGORITHMS, OPT_RANDOM_INSTANCES, OPT_RANDOM_GENERATORS, + OPT_ENCODERS, OPT_DECODERS, OPT_KEYMANAGERS, OPT_KEYEXCHANGE_ALGORITHMS, + OPT_KEM_ALGORITHMS, OPT_SIGNATURE_ALGORITHMS, OPT_ASYM_CIPHER_ALGORITHMS, + OPT_STORE_LOADERS, OPT_PROVIDER_INFO, + OPT_OBJECTS, OPT_SELECT_NAME, +#ifndef OPENSSL_NO_DEPRECATED_3_0 + OPT_ENGINES, +#endif + OPT_PROV_ENUM +} HELPLIST_CHOICE; + +const OPTIONS list_options[] = { + + OPT_SECTION("General"), + {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_SECTION("Output"), + {"1", OPT_ONE, '-', "List in one column"}, + {"verbose", OPT_VERBOSE, '-', "Verbose listing"}, + {"select", OPT_SELECT_NAME, 's', "Select a single algorithm"}, + {"commands", OPT_COMMANDS, '-', "List of standard commands"}, + {"standard-commands", OPT_COMMANDS, '-', "List of standard commands"}, +#ifndef OPENSSL_NO_DEPRECATED_3_0 + {"digest-commands", OPT_DIGEST_COMMANDS, '-', + "List of message digest commands (deprecated)"}, +#endif + {"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-', + "List of message digest algorithms"}, + {"kdf-algorithms", OPT_KDF_ALGORITHMS, '-', + "List of key derivation and pseudo random function algorithms"}, + {"random-instances", OPT_RANDOM_INSTANCES, '-', + "List the primary, public and private random number generator details"}, + {"random-generators", OPT_RANDOM_GENERATORS, '-', + "List of random number generators"}, + {"mac-algorithms", OPT_MAC_ALGORITHMS, '-', + "List of message authentication code algorithms"}, +#ifndef OPENSSL_NO_DEPRECATED_3_0 + {"cipher-commands", OPT_CIPHER_COMMANDS, '-', + "List of cipher commands (deprecated)"}, +#endif + {"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-', + "List of symmetric cipher algorithms"}, + {"encoders", OPT_ENCODERS, '-', "List of encoding methods" }, + {"decoders", OPT_DECODERS, '-', "List of decoding methods" }, + {"key-managers", OPT_KEYMANAGERS, '-', "List of key managers" }, + {"key-exchange-algorithms", OPT_KEYEXCHANGE_ALGORITHMS, '-', + "List of key exchange algorithms" }, + {"kem-algorithms", OPT_KEM_ALGORITHMS, '-', + "List of key encapsulation mechanism algorithms" }, + {"signature-algorithms", OPT_SIGNATURE_ALGORITHMS, '-', + "List of signature algorithms" }, + {"asymcipher-algorithms", OPT_ASYM_CIPHER_ALGORITHMS, '-', + "List of asymmetric cipher algorithms" }, + {"public-key-algorithms", OPT_PK_ALGORITHMS, '-', + "List of public key algorithms"}, + {"public-key-methods", OPT_PK_METHOD, '-', + "List of public key methods"}, + {"store-loaders", OPT_STORE_LOADERS, '-', + "List of store loaders"}, + {"providers", OPT_PROVIDER_INFO, '-', + "List of provider information"}, +#ifndef OPENSSL_NO_DEPRECATED_3_0 + {"engines", OPT_ENGINES, '-', + "List of loaded engines"}, +#endif + {"disabled", OPT_DISABLED, '-', "List of disabled features"}, + {"options", OPT_OPTIONS, 's', + "List options for specified command"}, + {"objects", OPT_OBJECTS, '-', + "List built in objects (OID<->name mappings)"}, + + OPT_PROV_OPTIONS, + {NULL} +}; + +int list_main(int argc, char **argv) +{ + char *prog; + HELPLIST_CHOICE o; + int one = 0, done = 0; + struct { + unsigned int commands:1; + unsigned int random_instances:1; + unsigned int random_generators:1; + unsigned int digest_commands:1; + unsigned int digest_algorithms:1; + unsigned int kdf_algorithms:1; + unsigned int mac_algorithms:1; + unsigned int cipher_commands:1; + unsigned int cipher_algorithms:1; + unsigned int encoder_algorithms:1; + unsigned int decoder_algorithms:1; + unsigned int keymanager_algorithms:1; + unsigned int signature_algorithms:1; + unsigned int keyexchange_algorithms:1; + unsigned int kem_algorithms:1; + unsigned int asym_cipher_algorithms:1; + unsigned int pk_algorithms:1; + unsigned int pk_method:1; + unsigned int store_loaders:1; + unsigned int provider_info:1; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + unsigned int engines:1; +#endif + unsigned int disabled:1; + unsigned int objects:1; + unsigned int options:1; + } todo = { 0, }; + + verbose = 0; /* Clear a possible previous call */ + + prog = opt_init(argc, argv, list_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: /* Never hit, but suppresses warning */ + case OPT_ERR: +opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + return 1; + case OPT_HELP: + opt_help(list_options); + return 0; + case OPT_ONE: + one = 1; + break; + case OPT_COMMANDS: + todo.commands = 1; + break; + case OPT_DIGEST_COMMANDS: + todo.digest_commands = 1; + break; + case OPT_DIGEST_ALGORITHMS: + todo.digest_algorithms = 1; + break; + case OPT_KDF_ALGORITHMS: + todo.kdf_algorithms = 1; + break; + case OPT_RANDOM_INSTANCES: + todo.random_instances = 1; + break; + case OPT_RANDOM_GENERATORS: + todo.random_generators = 1; + break; + case OPT_MAC_ALGORITHMS: + todo.mac_algorithms = 1; + break; + case OPT_CIPHER_COMMANDS: + todo.cipher_commands = 1; + break; + case OPT_CIPHER_ALGORITHMS: + todo.cipher_algorithms = 1; + break; + case OPT_ENCODERS: + todo.encoder_algorithms = 1; + break; + case OPT_DECODERS: + todo.decoder_algorithms = 1; + break; + case OPT_KEYMANAGERS: + todo.keymanager_algorithms = 1; + break; + case OPT_SIGNATURE_ALGORITHMS: + todo.signature_algorithms = 1; + break; + case OPT_KEYEXCHANGE_ALGORITHMS: + todo.keyexchange_algorithms = 1; + break; + case OPT_KEM_ALGORITHMS: + todo.kem_algorithms = 1; + break; + case OPT_ASYM_CIPHER_ALGORITHMS: + todo.asym_cipher_algorithms = 1; + break; + case OPT_PK_ALGORITHMS: + todo.pk_algorithms = 1; + break; + case OPT_PK_METHOD: + todo.pk_method = 1; + break; + case OPT_STORE_LOADERS: + todo.store_loaders = 1; + break; + case OPT_PROVIDER_INFO: + todo.provider_info = 1; + break; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + case OPT_ENGINES: + todo.engines = 1; + break; +#endif + case OPT_DISABLED: + todo.disabled = 1; + break; + case OPT_OBJECTS: + todo.objects = 1; + break; + case OPT_OPTIONS: + list_options_for_command(opt_arg()); + break; + case OPT_VERBOSE: + verbose = 1; + break; + case OPT_SELECT_NAME: + select_name = opt_arg(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + return 1; + break; + } + done = 1; + } + + /* No extra arguments. */ + if (opt_num_rest() != 0) + goto opthelp; + + if (todo.commands) + list_type(FT_general, one); + if (todo.random_instances) + list_random_instances(); + if (todo.random_generators) + list_random_generators(); + if (todo.digest_commands) + list_type(FT_md, one); + if (todo.digest_algorithms) + list_digests(); + if (todo.kdf_algorithms) + list_kdfs(); + if (todo.mac_algorithms) + list_macs(); + if (todo.cipher_commands) + list_type(FT_cipher, one); + if (todo.cipher_algorithms) + list_ciphers(); + if (todo.encoder_algorithms) + list_encoders(); + if (todo.decoder_algorithms) + list_decoders(); + if (todo.keymanager_algorithms) + list_keymanagers(); + if (todo.signature_algorithms) + list_signatures(); + if (todo.asym_cipher_algorithms) + list_asymciphers(); + if (todo.keyexchange_algorithms) + list_keyexchanges(); + if (todo.kem_algorithms) + list_kems(); + if (todo.pk_algorithms) + list_pkey(); + if (todo.pk_method) + list_pkey_meth(); + if (todo.store_loaders) + list_store_loaders(); + if (todo.provider_info) + list_provider_info(); +#ifndef OPENSSL_NO_DEPRECATED_3_0 + if (todo.engines) + list_engines(); +#endif + if (todo.disabled) + list_disabled(); + if (todo.objects) + list_objects(); + + if (!done) + goto opthelp; + + return 0; +} diff --git a/apps/mac.c b/apps/mac.c new file mode 100644 index 000000000000..a9b6a265f49a --- /dev/null +++ b/apps/mac.c @@ -0,0 +1,237 @@ +/* + * Copyright 2018-2022 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 <string.h> + +#include "apps.h" +#include "progs.h" +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/params.h> +#include <openssl/core_names.h> + +#undef BUFSIZE +#define BUFSIZE 1024*8 + +typedef enum OPTION_choice { + OPT_COMMON, + OPT_MACOPT, OPT_BIN, OPT_IN, OPT_OUT, + OPT_CIPHER, OPT_DIGEST, + OPT_PROV_ENUM +} OPTION_CHOICE; + +const OPTIONS mac_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] mac_name\n"}, + + OPT_SECTION("General"), + {"help", OPT_HELP, '-', "Display this summary"}, + {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form"}, + {"cipher", OPT_CIPHER, 's', "Cipher"}, + {"digest", OPT_DIGEST, 's', "Digest"}, + {OPT_MORE_STR, 1, '-', "See 'PARAMETER NAMES' in the EVP_MAC_ docs"}, + + OPT_SECTION("Input"), + {"in", OPT_IN, '<', "Input file to MAC (default is stdin)"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, + {"binary", OPT_BIN, '-', + "Output in binary format (default is hexadecimal)"}, + + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"mac_name", 0, 0, "MAC algorithm"}, + {NULL} +}; + +static char *alloc_mac_algorithm_name(STACK_OF(OPENSSL_STRING) **optp, + const char *name, const char *arg) +{ + size_t len = strlen(name) + strlen(arg) + 2; + char *res; + + if (*optp == NULL) + *optp = sk_OPENSSL_STRING_new_null(); + if (*optp == NULL) + return NULL; + + res = app_malloc(len, "algorithm name"); + BIO_snprintf(res, len, "%s:%s", name, arg); + if (sk_OPENSSL_STRING_push(*optp, res)) + return res; + OPENSSL_free(res); + return NULL; +} + +int mac_main(int argc, char **argv) +{ + int ret = 1; + char *prog; + EVP_MAC *mac = NULL; + OPTION_CHOICE o; + EVP_MAC_CTX *ctx = NULL; + STACK_OF(OPENSSL_STRING) *opts = NULL; + unsigned char *buf = NULL; + size_t len; + int i; + BIO *in = NULL, *out = NULL; + const char *outfile = NULL; + const char *infile = NULL; + int out_bin = 0; + int inform = FORMAT_BINARY; + char *digest = NULL, *cipher = NULL; + OSSL_PARAM *params = NULL; + + prog = opt_init(argc, argv, mac_options); + buf = app_malloc(BUFSIZE, "I/O buffer"); + 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(mac_options); + ret = 0; + goto err; + case OPT_BIN: + out_bin = 1; + break; + case OPT_IN: + infile = opt_arg(); + break; + case OPT_OUT: + outfile = opt_arg(); + break; + case OPT_MACOPT: + if (opts == NULL) + opts = sk_OPENSSL_STRING_new_null(); + if (opts == NULL || !sk_OPENSSL_STRING_push(opts, opt_arg())) + goto opthelp; + break; + case OPT_CIPHER: + OPENSSL_free(cipher); + cipher = alloc_mac_algorithm_name(&opts, "cipher", opt_arg()); + if (cipher == NULL) + goto opthelp; + break; + case OPT_DIGEST: + OPENSSL_free(digest); + digest = alloc_mac_algorithm_name(&opts, "digest", opt_arg()); + if (digest == NULL) + goto opthelp; + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto err; + break; + } + } + + /* One argument, the MAC name. */ + argc = opt_num_rest(); + argv = opt_rest(); + if (argc != 1) + goto opthelp; + + mac = EVP_MAC_fetch(app_get0_libctx(), argv[0], app_get0_propq()); + if (mac == NULL) { + BIO_printf(bio_err, "Invalid MAC name %s\n", argv[0]); + goto opthelp; + } + + ctx = EVP_MAC_CTX_new(mac); + if (ctx == NULL) + goto err; + + if (opts != NULL) { + int ok = 1; + + params = app_params_new_from_opts(opts, + EVP_MAC_settable_ctx_params(mac)); + if (params == NULL) + goto err; + + if (!EVP_MAC_CTX_set_params(ctx, params)) { + BIO_printf(bio_err, "MAC parameter error\n"); + ERR_print_errors(bio_err); + ok = 0; + } + app_params_free(params); + if (!ok) + goto err; + } + + in = bio_open_default(infile, 'r', inform); + if (in == NULL) + goto err; + + out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT); + if (out == NULL) + goto err; + + if (!EVP_MAC_init(ctx, NULL, 0, NULL)) { + BIO_printf(bio_err, "EVP_MAC_Init failed\n"); + goto err; + } + + while (BIO_pending(in) || !BIO_eof(in)) { + i = BIO_read(in, (char *)buf, BUFSIZE); + if (i < 0) { + BIO_printf(bio_err, "Read Error in '%s'\n", infile); + ERR_print_errors(bio_err); + goto err; + } + if (i == 0) + break; + if (!EVP_MAC_update(ctx, buf, i)) { + BIO_printf(bio_err, "EVP_MAC_update failed\n"); + goto err; + } + } + + if (!EVP_MAC_final(ctx, NULL, &len, 0)) { + BIO_printf(bio_err, "EVP_MAC_final failed\n"); + goto err; + } + if (len > BUFSIZE) { + BIO_printf(bio_err, "output len is too large\n"); + goto err; + } + + if (!EVP_MAC_final(ctx, buf, &len, BUFSIZE)) { + BIO_printf(bio_err, "EVP_MAC_final failed\n"); + goto err; + } + + if (out_bin) { + BIO_write(out, buf, len); + } else { + for (i = 0; i < (int)len; ++i) + BIO_printf(out, "%02X", buf[i]); + if (outfile == NULL) + BIO_printf(out,"\n"); + } + + ret = 0; +err: + if (ret != 0) + ERR_print_errors(bio_err); + OPENSSL_clear_free(buf, BUFSIZE); + OPENSSL_free(cipher); + OPENSSL_free(digest); + sk_OPENSSL_STRING_free(opts); + BIO_free(in); + BIO_free(out); + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + return ret; +} diff --git a/apps/nseq.c b/apps/nseq.c index a067c915926f..d5524370f26c 100644 --- a/apps/nseq.c +++ b/apps/nseq.c @@ -1,7 +1,7 @@ /* - * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -15,15 +15,23 @@ #include <openssl/err.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_TOSEQ, OPT_IN, OPT_OUT + OPT_COMMON, + OPT_TOSEQ, OPT_IN, OPT_OUT, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS nseq_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"toseq", OPT_TOSEQ, '-', "Output NS Sequence file"}, + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, + + OPT_SECTION("Output"), + {"toseq", OPT_TOSEQ, '-', "Output NS Sequence file"}, {"out", OPT_OUT, '>', "Output file"}, + + OPT_PROV_OPTIONS, {NULL} }; @@ -57,8 +65,14 @@ int nseq_main(int argc, char **argv) case OPT_OUT: outfile = opt_arg(); break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; @@ -77,8 +91,10 @@ int nseq_main(int argc, char **argv) seq->certs = sk_X509_new_null(); if (seq->certs == NULL) goto end; - while ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL))) - sk_X509_push(seq->certs, x509); + while ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL))) { + if (!sk_X509_push(seq->certs, x509)) + goto end; + } if (!sk_X509_num(seq->certs)) { BIO_printf(bio_err, "%s: Error reading certs file %s\n", diff --git a/apps/ocsp.c b/apps/ocsp.c index 8f20864cea51..821e224c6ce4 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -1,7 +1,7 @@ /* * Copyright 2001-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -10,8 +10,8 @@ #include <openssl/opensslconf.h> #ifdef OPENSSL_SYS_VMS -# define _XOPEN_SOURCE_EXTENDED/* So fd_set and friends get properly defined - * on OpenVMS */ + /* So fd_set and friends get properly defined on OpenVMS */ +# define _XOPEN_SOURCE_EXTENDED #endif #include <stdio.h> @@ -22,6 +22,7 @@ /* Needs to be included before the openssl headers */ #include "apps.h" +#include "http_server.h" #include "progs.h" #include "internal/sockets.h" #include <openssl/e_os2.h> @@ -31,37 +32,11 @@ #include <openssl/evp.h> #include <openssl/bn.h> #include <openssl/x509v3.h> -#include <openssl/rand.h> -#ifndef HAVE_FORK -#if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS) -# define HAVE_FORK 0 -#else -# define HAVE_FORK 1 -#endif -#endif - -#if HAVE_FORK -#undef NO_FORK -#else -#define NO_FORK -#endif - -#if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \ - && !defined(OPENSSL_NO_POSIX_IO) -# define OCSP_DAEMON -# include <sys/types.h> -# include <sys/wait.h> -# include <syslog.h> -# include <signal.h> -# define MAXERRLEN 1000 /* limit error text sent to syslog to 1000 bytes */ -#else -# undef LOG_INFO -# undef LOG_WARNING -# undef LOG_ERR -# define LOG_INFO 0 -# define LOG_WARNING 1 -# define LOG_ERR 2 +#if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_fork)> +# endif #endif #if defined(OPENSSL_SYS_VXWORKS) @@ -87,7 +62,7 @@ static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids); -static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, +static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec, long maxage); @@ -96,76 +71,118 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req EVP_PKEY *rkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(X509) *rother, unsigned long flags, - int nmin, int ndays, int badsig); + int nmin, int ndays, int badsig, + const EVP_MD *resp_md); static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); -static BIO *init_responder(const char *port); -static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, int timeout); -static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp); -static void log_message(int level, const char *fmt, ...); +static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, + const char *port, int timeout); +static int send_ocsp_response(BIO *cbio, const OCSP_RESPONSE *resp); static char *prog; -static int multi = 0; -#ifdef OCSP_DAEMON -static int acfd = (int) INVALID_SOCKET; +#ifdef HTTP_DAEMON static int index_changed(CA_DB *); -static void spawn_loop(void); -static int print_syslog(const char *str, size_t len, void *levPtr); -static void socket_timeout(int signum); -#endif - -#ifndef OPENSSL_NO_SOCK -static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, - const char *path, - const STACK_OF(CONF_VALUE) *headers, - OCSP_REQUEST *req, int req_timeout); #endif typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_OUTFILE, OPT_TIMEOUT, OPT_URL, OPT_HOST, OPT_PORT, +#ifndef OPENSSL_NO_SOCK + OPT_PROXY, OPT_NO_PROXY, +#endif OPT_IGNORE_ERR, OPT_NOVERIFY, OPT_NONCE, OPT_NO_NONCE, OPT_RESP_NO_CERTS, OPT_RESP_KEY_ID, OPT_NO_CERTS, OPT_NO_SIGNATURE_VERIFY, OPT_NO_CERT_VERIFY, OPT_NO_CHAIN, OPT_NO_CERT_CHECKS, OPT_NO_EXPLICIT, OPT_TRUST_OTHER, OPT_NO_INTERN, OPT_BADSIG, OPT_TEXT, OPT_REQ_TEXT, OPT_RESP_TEXT, OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER, - OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH, + OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_CASTORE, OPT_NOCAFILE, + OPT_NOCAPATH, OPT_NOCASTORE, OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT, OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL, OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER, OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_RSIGOPT, OPT_HEADER, + OPT_PASSIN, + OPT_RCID, OPT_V_ENUM, OPT_MD, - OPT_MULTI + OPT_MULTI, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS ocsp_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"out", OPT_OUTFILE, '>', "Output filename"}, - {"timeout", OPT_TIMEOUT, 'p', - "Connection timeout (in seconds) to the OCSP responder"}, - {"url", OPT_URL, 's', "Responder URL"}, - {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"}, - {"port", OPT_PORT, 'p', "Port to run responder on"}, {"ignore_err", OPT_IGNORE_ERR, '-', "Ignore error on OCSP request or response and continue running"}, - {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"}, - {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"}, - {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"}, + {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, + {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"}, + {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"}, + {"no-CAfile", OPT_NOCAFILE, '-', + "Do not load the default certificates file"}, + {"no-CApath", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates directory"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store"}, + + OPT_SECTION("Responder"), + {"timeout", OPT_TIMEOUT, 'p', + "Connection timeout (in seconds) to the OCSP responder"}, {"resp_no_certs", OPT_RESP_NO_CERTS, '-', "Don't include any certificates in response"}, - {"resp_key_id", OPT_RESP_KEY_ID, '-', - "Identify response by signing certificate key ID"}, -#ifdef OCSP_DAEMON +#ifdef HTTP_DAEMON {"multi", OPT_MULTI, 'p', "run multiple responder processes"}, #endif {"no_certs", OPT_NO_CERTS, '-', "Don't include any certificates in signed request"}, + {"badsig", OPT_BADSIG, '-', + "Corrupt last byte of loaded OCSP response signature (for test)"}, + {"CA", OPT_CA, '<', "CA certificate"}, + {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"}, + {"nrequest", OPT_REQUEST, 'p', + "Number of requests to accept (default unlimited)"}, + {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"}, + {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"}, + {"sign_other", OPT_SIGN_OTHER, '<', + "Additional certificates to include in signed request"}, + {"index", OPT_INDEX, '<', "Certificate status index file"}, + {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, + {"rsigner", OPT_RSIGNER, '<', + "Responder certificate to sign responses with"}, + {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"}, + {"passin", OPT_PASSIN, 's', "Responder key pass phrase source"}, + {"rother", OPT_ROTHER, '<', "Other certificates to include in response"}, + {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"}, + {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"}, + {"header", OPT_HEADER, 's', "key=value header to add"}, + {"rcid", OPT_RCID, 's', "Use specified algorithm for cert id in response"}, + {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, + + OPT_SECTION("Client"), + {"url", OPT_URL, 's', "Responder URL"}, + {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"}, + {"port", OPT_PORT, 'N', "Port to run responder on"}, + {"path", OPT_PATH, 's', "Path to use in OCSP request"}, +#ifndef OPENSSL_NO_SOCK + {"proxy", OPT_PROXY, 's', + "[http[s]://]host[:port][/path] of HTTP(S) proxy to use; path is ignored"}, + {"no_proxy", OPT_NO_PROXY, 's', + "List of addresses of servers not to use HTTP(S) proxy for"}, + {OPT_MORE_STR, 0, 0, + "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, +#endif + {"out", OPT_OUTFILE, '>', "Output filename"}, + {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"}, + {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"}, + {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"}, {"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-', "Don't check signature on response"}, + {"resp_key_id", OPT_RESP_KEY_ID, '-', + "Identify response by signing certificate key ID"}, {"no_cert_verify", OPT_NO_CERT_VERIFY, '-', "Don't check signing certificate"}, + {"text", OPT_TEXT, '-', "Print text form of request and response"}, + {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"}, + {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"}, {"no_chain", OPT_NO_CHAIN, '-', "Don't chain verify response"}, {"no_cert_checks", OPT_NO_CERT_CHECKS, '-', "Don't do additional checks on signing certificate"}, @@ -175,57 +192,29 @@ const OPTIONS ocsp_options[] = { "Don't verify additional certificates"}, {"no_intern", OPT_NO_INTERN, '-', "Don't search certificates contained in response for signer"}, - {"badsig", OPT_BADSIG, '-', - "Corrupt last byte of loaded OCSP response signature (for test)"}, - {"text", OPT_TEXT, '-', "Print text form of request and response"}, - {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"}, - {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"}, - {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"}, {"respin", OPT_RESPIN, 's', "File with the DER-encoded response"}, - {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"}, {"VAfile", OPT_VAFILE, '<', "Validator certificates file"}, - {"sign_other", OPT_SIGN_OTHER, '<', - "Additional certificates to include in signed request"}, {"verify_other", OPT_VERIFY_OTHER, '<', "Additional certificates to search for signer"}, - {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, - {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"}, - {"no-CAfile", OPT_NOCAFILE, '-', - "Do not load the default certificates file"}, - {"no-CApath", OPT_NOCAPATH, '-', - "Do not load certificates from the default certificates directory"}, + {"cert", OPT_CERT, '<', "Certificate to check"}, + {"serial", OPT_SERIAL, 's', "Serial number to check"}, {"validity_period", OPT_VALIDITY_PERIOD, 'u', "Maximum validity discrepancy in seconds"}, - {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"}, {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"}, {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"}, - {"path", OPT_PATH, 's', "Path to use in OCSP request"}, {"issuer", OPT_ISSUER, '<', "Issuer certificate"}, - {"cert", OPT_CERT, '<', "Certificate to check"}, - {"serial", OPT_SERIAL, 's', "Serial number to check"}, - {"index", OPT_INDEX, '<', "Certificate status index file"}, - {"CA", OPT_CA, '<', "CA certificate"}, - {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"}, - {"nrequest", OPT_REQUEST, 'p', - "Number of requests to accept (default unlimited)"}, - {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, - {"rsigner", OPT_RSIGNER, '<', - "Responder certificate to sign responses with"}, - {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"}, - {"rother", OPT_ROTHER, '<', "Other certificates to include in response"}, - {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"}, - {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"}, - {"header", OPT_HEADER, 's', "key=value header to add"}, - {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, + {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, + OPT_V_OPTIONS, + OPT_PROV_OPTIONS, {NULL} }; int ocsp_main(int argc, char **argv) { BIO *acbio = NULL, *cbio = NULL, *derbio = NULL, *out = NULL; - const EVP_MD *cert_id_md = NULL, *rsign_md = NULL; + EVP_MD *cert_id_md = NULL, *rsign_md = NULL; STACK_OF(OPENSSL_STRING) *rsign_sigopts = NULL; int trailing_md = 0; CA_DB *rdb = NULL; @@ -240,35 +229,37 @@ int ocsp_main(int argc, char **argv) STACK_OF(X509) *issuers = NULL; X509 *issuer = NULL, *cert = NULL; STACK_OF(X509) *rca_cert = NULL; + EVP_MD *resp_certid_md = NULL; X509 *signer = NULL, *rsigner = NULL; X509_STORE *store = NULL; X509_VERIFY_PARAM *vpm = NULL; - const char *CAfile = NULL, *CApath = NULL; - char *header, *value; + const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL; + char *header, *value, *respdigname = NULL; char *host = NULL, *port = NULL, *path = "/", *outfile = NULL; +#ifndef OPENSSL_NO_SOCK + char *opt_proxy = NULL; + char *opt_no_proxy = NULL; +#endif char *rca_filename = NULL, *reqin = NULL, *respin = NULL; char *reqout = NULL, *respout = NULL, *ridx_filename = NULL; char *rsignfile = NULL, *rkeyfile = NULL; + char *passinarg = NULL, *passin = NULL; char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL; char *signfile = NULL, *keyfile = NULL; char *thost = NULL, *tport = NULL, *tpath = NULL; - int noCAfile = 0, noCApath = 0; + int noCAfile = 0, noCApath = 0, noCAstore = 0; int accept_count = -1, add_nonce = 1, noverify = 0, use_ssl = -1; int vpmtouched = 0, badsig = 0, i, ignore_err = 0, nmin = 0, ndays = -1; - int req_text = 0, resp_text = 0, ret = 1; + int req_text = 0, resp_text = 0, res, ret = 1; int req_timeout = -1; long nsec = MAX_VALIDITY_PERIOD, maxage = -1; unsigned long sign_flags = 0, verify_flags = 0, rflags = 0; OPTION_CHOICE o; - reqnames = sk_OPENSSL_STRING_new_null(); - if (reqnames == NULL) - goto end; - ids = sk_OCSP_CERTID_new_null(); - if (ids == NULL) + if ((reqnames = sk_OPENSSL_STRING_new_null()) == NULL + || (ids = sk_OCSP_CERTID_new_null()) == NULL + || (vpm = X509_VERIFY_PARAM_new()) == NULL) goto end; - if ((vpm = X509_VERIFY_PARAM_new()) == NULL) - return 1; prog = opt_init(argc, argv, ocsp_options); while ((o = opt_next()) != OPT_EOF) { @@ -295,8 +286,10 @@ int ocsp_main(int argc, char **argv) OPENSSL_free(tport); OPENSSL_free(tpath); thost = tport = tpath = NULL; - if (!OCSP_parse_url(opt_arg(), &host, &port, &path, &use_ssl)) { - BIO_printf(bio_err, "%s Error parsing URL\n", prog); + if (!OSSL_HTTP_parse_url(opt_arg(), &use_ssl, NULL /* userinfo */, + &host, &port, NULL /* port_num */, + &path, NULL /* qry */, NULL /* frag */)) { + BIO_printf(bio_err, "%s Error parsing -url argument\n", prog); goto end; } thost = host; @@ -309,6 +302,17 @@ int ocsp_main(int argc, char **argv) case OPT_PORT: port = opt_arg(); break; + case OPT_PATH: + path = opt_arg(); + break; +#ifndef OPENSSL_NO_SOCK + case OPT_PROXY: + opt_proxy = opt_arg(); + break; + case OPT_NO_PROXY: + opt_no_proxy = opt_arg(); + break; +#endif case OPT_IGNORE_ERR: ignore_err = 1; break; @@ -388,12 +392,18 @@ int ocsp_main(int argc, char **argv) case OPT_CAPATH: CApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_NOCAFILE: noCAfile = 1; break; case OPT_NOCAPATH: noCApath = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_V_CASES: if (!opt_verify(o, vpm)) goto end; @@ -414,26 +424,24 @@ int ocsp_main(int argc, char **argv) case OPT_RESPOUT: respout = opt_arg(); break; - case OPT_PATH: - path = opt_arg(); - break; case OPT_ISSUER: - issuer = load_cert(opt_arg(), FORMAT_PEM, "issuer certificate"); + issuer = load_cert(opt_arg(), FORMAT_UNDEF, "issuer certificate"); if (issuer == NULL) goto end; if (issuers == NULL) { if ((issuers = sk_X509_new_null()) == NULL) goto end; } - sk_X509_push(issuers, issuer); + if (!sk_X509_push(issuers, issuer)) + goto end; break; case OPT_CERT: X509_free(cert); - cert = load_cert(opt_arg(), FORMAT_PEM, "certificate"); + cert = load_cert(opt_arg(), FORMAT_UNDEF, "certificate"); if (cert == NULL) goto end; if (cert_id_md == NULL) - cert_id_md = EVP_sha1(); + cert_id_md = (EVP_MD *)EVP_sha1(); if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids)) goto end; if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) @@ -442,7 +450,7 @@ int ocsp_main(int argc, char **argv) break; case OPT_SERIAL: if (cert_id_md == NULL) - cert_id_md = EVP_sha1(); + cert_id_md = (EVP_MD *)EVP_sha1(); if (!add_ocsp_serial(&req, opt_arg(), cert_id_md, issuer, ids)) goto end; if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) @@ -456,12 +464,12 @@ int ocsp_main(int argc, char **argv) rca_filename = opt_arg(); break; case OPT_NMIN: - opt_int(opt_arg(), &nmin); + nmin = opt_int_arg(); if (ndays == -1) ndays = 0; break; case OPT_REQUEST: - opt_int(opt_arg(), &accept_count); + accept_count = opt_int_arg(); break; case OPT_NDAYS: ndays = atoi(opt_arg()); @@ -472,17 +480,20 @@ int ocsp_main(int argc, char **argv) case OPT_RKEY: rkeyfile = opt_arg(); break; + case OPT_PASSIN: + passinarg = opt_arg(); + break; case OPT_ROTHER: rcertfile = opt_arg(); break; case OPT_RMD: /* Response MessageDigest */ - if (!opt_md(opt_arg(), &rsign_md)) - goto end; + respdigname = opt_arg(); break; case OPT_RSIGOPT: if (rsign_sigopts == NULL) rsign_sigopts = sk_OPENSSL_STRING_new_null(); - if (rsign_sigopts == NULL || !sk_OPENSSL_STRING_push(rsign_sigopts, opt_arg())) + if (rsign_sigopts == NULL + || !sk_OPENSSL_STRING_push(rsign_sigopts, opt_arg())) goto end; break; case OPT_HEADER: @@ -496,6 +507,10 @@ int ocsp_main(int argc, char **argv) if (!X509V3_add_value(header, value, &headers)) goto end; break; + case OPT_RCID: + if (!opt_md(opt_arg(), &resp_certid_md)) + goto opthelp; + break; case OPT_MD: if (trailing_md) { BIO_printf(bio_err, @@ -508,20 +523,32 @@ int ocsp_main(int argc, char **argv) trailing_md = 1; break; case OPT_MULTI: -#ifdef OCSP_DAEMON +#ifdef HTTP_DAEMON multi = atoi(opt_arg()); #endif break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ + argc = opt_num_rest(); + if (argc != 0) + goto opthelp; + if (trailing_md) { BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n", prog); goto opthelp; } - argc = opt_num_rest(); - if (argc != 0) - goto opthelp; + + if (respdigname != NULL) { + if (!opt_md(respdigname, &rsign_md)) + goto end; + } /* Have we anything to do? */ if (req == NULL && reqin == NULL @@ -548,28 +575,36 @@ int ocsp_main(int argc, char **argv) } if (req == NULL && port != NULL) { - acbio = init_responder(port); +#ifndef OPENSSL_NO_SOCK + acbio = http_server_init_bio(prog, port); if (acbio == NULL) goto end; +#else + BIO_printf(bio_err, "Cannot act as server - sockets not supported\n"); + goto end; +#endif } if (rsignfile != NULL) { if (rkeyfile == NULL) rkeyfile = rsignfile; - rsigner = load_cert(rsignfile, FORMAT_PEM, "responder certificate"); + rsigner = load_cert(rsignfile, FORMAT_UNDEF, "responder certificate"); if (rsigner == NULL) { BIO_printf(bio_err, "Error loading responder certificate\n"); goto end; } - if (!load_certs(rca_filename, &rca_cert, FORMAT_PEM, - NULL, "CA certificate")) + if (!load_certs(rca_filename, 0, &rca_cert, NULL, "CA certificates")) goto end; if (rcertfile != NULL) { - if (!load_certs(rcertfile, &rother, FORMAT_PEM, NULL, + if (!load_certs(rcertfile, 0, &rother, NULL, "responder other certificates")) goto end; } - rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL, + if (!app_passwd(passinarg, NULL, &passin, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + rkey = load_key(rkeyfile, FORMAT_UNDEF, 0, passin, NULL, "responder private key"); if (rkey == NULL) goto end; @@ -585,25 +620,28 @@ int ocsp_main(int argc, char **argv) if (ridx_filename != NULL) { rdb = load_index(ridx_filename, NULL); if (rdb == NULL || index_index(rdb) <= 0) { + BIO_printf(bio_err, + "Problem with index file: %s (could not load/parse file)\n", + ridx_filename); ret = 1; goto end; } } -#ifdef OCSP_DAEMON +#ifdef HTTP_DAEMON if (multi && acbio != NULL) - spawn_loop(); + spawn_loop(prog); if (acbio != NULL && req_timeout > 0) signal(SIGALRM, socket_timeout); #endif if (acbio != NULL) - log_message(LOG_INFO, "waiting for OCSP client connections..."); + log_message(prog, LOG_INFO, "waiting for OCSP client connections..."); redo_accept: if (acbio != NULL) { -#ifdef OCSP_DAEMON +#ifdef HTTP_DAEMON if (index_changed(rdb)) { CA_DB *newrdb = load_index(ridx_filename, NULL); @@ -612,21 +650,24 @@ redo_accept: rdb = newrdb; } else { free_index(newrdb); - log_message(LOG_ERR, "error reloading updated index: %s", + log_message(prog, LOG_ERR, "error reloading updated index: %s", ridx_filename); } } #endif req = NULL; - if (!do_responder(&req, &cbio, acbio, req_timeout)) + res = do_responder(&req, &cbio, acbio, port, req_timeout); + if (res == 0) goto redo_accept; if (req == NULL) { - resp = - OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, - NULL); - send_ocsp_response(cbio, resp); + if (res == 1) { + resp = + OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, + NULL); + send_ocsp_response(cbio, resp); + } goto done_resp; } } @@ -646,23 +687,23 @@ redo_accept: if (signfile != NULL) { if (keyfile == NULL) keyfile = signfile; - signer = load_cert(signfile, FORMAT_PEM, "signer certificate"); + signer = load_cert(signfile, FORMAT_UNDEF, "signer certificate"); if (signer == NULL) { BIO_printf(bio_err, "Error loading signer certificate\n"); goto end; } if (sign_certfile != NULL) { - if (!load_certs(sign_certfile, &sign_other, FORMAT_PEM, NULL, + if (!load_certs(sign_certfile, 0, &sign_other, NULL, "signer certificates")) goto end; } - key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL, + key = load_key(keyfile, FORMAT_UNDEF, 0, NULL, NULL, "signer private key"); if (key == NULL) goto end; - if (!OCSP_request_sign - (req, signer, key, NULL, sign_other, sign_flags)) { + if (!OCSP_request_sign(req, signer, key, NULL, + sign_other, sign_flags)) { BIO_printf(bio_err, "Error signing OCSP request\n"); goto end; } @@ -681,18 +722,21 @@ redo_accept: if (rdb != NULL) { make_ocsp_response(bio_err, &resp, req, rdb, rca_cert, rsigner, rkey, - rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig); + rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, + badsig, resp_certid_md); + if (resp == NULL) + goto end; if (cbio != NULL) send_ocsp_response(cbio, resp); } else if (host != NULL) { #ifndef OPENSSL_NO_SOCK - resp = process_responder(req, host, path, - port, use_ssl, headers, req_timeout); + resp = process_responder(req, host, port, path, opt_proxy, opt_no_proxy, + use_ssl, headers, req_timeout); if (resp == NULL) goto end; #else BIO_printf(bio_err, - "Error creating connect BIO - sockets not supported.\n"); + "Error creating connect BIO - sockets not supported\n"); goto end; #endif } else if (respin != NULL) { @@ -752,15 +796,16 @@ redo_accept: } if (store == NULL) { - store = setup_verify(CAfile, CApath, noCAfile, noCApath); + store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore); if (!store) goto end; } if (vpmtouched) X509_STORE_set1_param(store, vpm); if (verify_certfile != NULL) { - if (!load_certs(verify_certfile, &verify_other, FORMAT_PEM, NULL, - "validator certificate")) + if (!load_certs(verify_certfile, 0, &verify_other, NULL, + "validator certificates")) goto end; } @@ -798,7 +843,8 @@ redo_accept: } } - print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage); + if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage)) + ret = 1; end: ERR_print_errors(bio_err); @@ -808,6 +854,9 @@ redo_accept: sk_OPENSSL_STRING_free(rsign_sigopts); EVP_PKEY_free(key); EVP_PKEY_free(rkey); + EVP_MD_free(cert_id_md); + EVP_MD_free(rsign_md); + EVP_MD_free(resp_certid_md); X509_free(cert); sk_X509_pop_free(issuers, X509_free); X509_free(rsigner); @@ -831,41 +880,7 @@ redo_accept: return ret; } -static void -log_message(int level, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); -#ifdef OCSP_DAEMON - if (multi) { - char buf[1024]; - if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) { - syslog(level, "%s", buf); - } - if (level >= LOG_ERR) - ERR_print_errors_cb(print_syslog, &level); - } -#endif - if (!multi) { - BIO_printf(bio_err, "%s: ", prog); - BIO_vprintf(bio_err, fmt, ap); - BIO_printf(bio_err, "\n"); - } - va_end(ap); -} - -#ifdef OCSP_DAEMON - -static int print_syslog(const char *str, size_t len, void *levPtr) -{ - int level = *(int *)levPtr; - int ilen = (len > MAXERRLEN) ? MAXERRLEN : len; - - syslog(level, "%.*s", ilen, str); - - return ilen; -} +#ifdef HTTP_DAEMON static int index_changed(CA_DB *rdb) { @@ -883,131 +898,6 @@ static int index_changed(CA_DB *rdb) return 0; } -static void killall(int ret, pid_t *kidpids) -{ - int i; - - for (i = 0; i < multi; ++i) - if (kidpids[i] != 0) - (void)kill(kidpids[i], SIGTERM); - OPENSSL_free(kidpids); - sleep(1); - exit(ret); -} - -static int termsig = 0; - -static void noteterm (int sig) -{ - termsig = sig; -} - -/* - * Loop spawning up to `multi` child processes, only child processes return - * from this function. The parent process loops until receiving a termination - * signal, kills extant children and exits without returning. - */ -static void spawn_loop(void) -{ - pid_t *kidpids = NULL; - int status; - int procs = 0; - int i; - - openlog(prog, LOG_PID, LOG_DAEMON); - - if (setpgid(0, 0)) { - syslog(LOG_ERR, "fatal: error detaching from parent process group: %s", - strerror(errno)); - exit(1); - } - kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array"); - for (i = 0; i < multi; ++i) - kidpids[i] = 0; - - signal(SIGINT, noteterm); - signal(SIGTERM, noteterm); - - while (termsig == 0) { - pid_t fpid; - - /* - * Wait for a child to replace when we're at the limit. - * Slow down if a child exited abnormally or waitpid() < 0 - */ - while (termsig == 0 && procs >= multi) { - if ((fpid = waitpid(-1, &status, 0)) > 0) { - for (i = 0; i < procs; ++i) { - if (kidpids[i] == fpid) { - kidpids[i] = 0; - --procs; - break; - } - } - if (i >= multi) { - syslog(LOG_ERR, "fatal: internal error: " - "no matching child slot for pid: %ld", - (long) fpid); - killall(1, kidpids); - } - if (status != 0) { - if (WIFEXITED(status)) - syslog(LOG_WARNING, "child process: %ld, exit status: %d", - (long)fpid, WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - syslog(LOG_WARNING, "child process: %ld, term signal %d%s", - (long)fpid, WTERMSIG(status), -#ifdef WCOREDUMP - WCOREDUMP(status) ? " (core dumped)" : -#endif - ""); - sleep(1); - } - break; - } else if (errno != EINTR) { - syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno)); - killall(1, kidpids); - } - } - if (termsig) - break; - - switch(fpid = fork()) { - case -1: /* error */ - /* System critically low on memory, pause and try again later */ - sleep(30); - break; - case 0: /* child */ - OPENSSL_free(kidpids); - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - if (termsig) - _exit(0); - if (RAND_poll() <= 0) { - syslog(LOG_ERR, "fatal: RAND_poll() failed"); - _exit(1); - } - return; - default: /* parent */ - for (i = 0; i < multi; ++i) { - if (kidpids[i] == 0) { - kidpids[i] = fpid; - procs++; - break; - } - } - if (i >= multi) { - syslog(LOG_ERR, "fatal: internal error: no free child slots"); - killall(1, kidpids); - } - break; - } - } - - /* The loop above can only break on termsig */ - syslog(LOG_INFO, "terminating on signal: %d", termsig); - killall(0, kidpids); -} #endif static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, @@ -1041,7 +931,7 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, STACK_OF(OCSP_CERTID) *ids) { OCSP_CERTID *id; - X509_NAME *iname; + const X509_NAME *iname; ASN1_BIT_STRING *ikey; ASN1_INTEGER *sno; @@ -1073,7 +963,7 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, return 0; } -static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, +static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec, long maxage) @@ -1082,10 +972,13 @@ static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, const char *name; int i, status, reason; ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int ret = 1; - if (bs == NULL || req == NULL || !sk_OPENSSL_STRING_num(names) - || !sk_OCSP_CERTID_num(ids)) - return; + if (req == NULL || !sk_OPENSSL_STRING_num(names)) + return 1; + + if (bs == NULL || !sk_OCSP_CERTID_num(ids)) + return 0; for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) { id = sk_OCSP_CERTID_value(ids, i); @@ -1095,6 +988,7 @@ static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, if (!OCSP_resp_find_status(bs, id, &status, &reason, &rev, &thisupd, &nextupd)) { BIO_puts(out, "ERROR: No Status found.\n"); + ret = 0; continue; } @@ -1128,6 +1022,7 @@ static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, ASN1_GENERALIZEDTIME_print(out, rev); BIO_puts(out, "\n"); } + return ret; } static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req, @@ -1135,7 +1030,8 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req EVP_PKEY *rkey, const EVP_MD *rmd, STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(X509) *rother, unsigned long flags, - int nmin, int ndays, int badsig) + int nmin, int ndays, int badsig, + const EVP_MD *resp_md) { ASN1_TIME *thisupd = NULL, *nextupd = NULL; OCSP_CERTID *cid; @@ -1166,6 +1062,8 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req int found = 0; ASN1_OBJECT *cert_id_md_oid; const EVP_MD *cert_id_md; + OCSP_CERTID *cid_resp_md = NULL; + one = OCSP_request_onereq_get0(req, i); cid = OCSP_onereq_get0_id(one); @@ -1181,11 +1079,18 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req X509 *ca_cert = sk_X509_value(ca, jj); OCSP_CERTID *ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca_cert); - if (OCSP_id_issuer_cmp(ca_id, cid) == 0) + if (OCSP_id_issuer_cmp(ca_id, cid) == 0) { found = 1; - + if (resp_md != NULL) + cid_resp_md = OCSP_cert_to_id(resp_md, NULL, ca_cert); + } OCSP_CERTID_free(ca_id); } + OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); + inf = lookup_serial(db, serial); + + /* at this point, we can have cid be an alias of cid_resp_md */ + cid = (cid_resp_md != NULL) ? cid_resp_md : cid; if (!found) { OCSP_basic_add1_status(bs, cid, @@ -1193,8 +1098,6 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req 0, NULL, thisupd, nextupd); continue; } - OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); - inf = lookup_serial(db, serial); if (inf == NULL) { OCSP_basic_add1_status(bs, cid, V_OCSP_CERTSTATUS_UNKNOWN, @@ -1209,10 +1112,16 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req ASN1_GENERALIZEDTIME *invtm = NULL; OCSP_SINGLERESP *single; int reason = -1; + unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]); single = OCSP_basic_add1_status(bs, cid, V_OCSP_CERTSTATUS_REVOKED, reason, revtm, thisupd, nextupd); + if (single == NULL) { + *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, + NULL); + goto end; + } if (invtm != NULL) OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, invtm, 0, 0); @@ -1224,6 +1133,7 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req ASN1_TIME_free(revtm); ASN1_GENERALIZEDTIME_free(invtm); } + OCSP_CERTID_free(cid_resp_md); } OCSP_copy_nonce(bs, req); @@ -1273,10 +1183,12 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) bn = ASN1_INTEGER_to_BN(ser, NULL); OPENSSL_assert(bn); /* FIXME: should report an error at this * point and abort */ - if (BN_is_zero(bn)) + if (BN_is_zero(bn)) { itmp = OPENSSL_strdup("00"); - else + OPENSSL_assert(itmp); + } else { itmp = BN_bn2hex(bn); + } row[DB_serial] = itmp; BN_free(bn); rrow = TXT_DB_get_by_index(db->db, DB_serial, row); @@ -1284,339 +1196,66 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) return rrow; } -/* Quick and dirty OCSP server: read in and parse input request */ - -static BIO *init_responder(const char *port) -{ -#ifdef OPENSSL_NO_SOCK - BIO_printf(bio_err, - "Error setting up accept BIO - sockets not supported.\n"); - return NULL; -#else - BIO *acbio = NULL, *bufbio = NULL; - - bufbio = BIO_new(BIO_f_buffer()); - if (bufbio == NULL) - goto err; - acbio = BIO_new(BIO_s_accept()); - if (acbio == NULL - || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0 - || BIO_set_accept_port(acbio, port) < 0) { - log_message(LOG_ERR, "Error setting up accept BIO"); - goto err; - } - - BIO_set_accept_bios(acbio, bufbio); - bufbio = NULL; - if (BIO_do_accept(acbio) <= 0) { - log_message(LOG_ERR, "Error starting accept"); - goto err; - } - - return acbio; - - err: - BIO_free_all(acbio); - BIO_free(bufbio); - return NULL; -#endif -} - -#ifndef OPENSSL_NO_SOCK -/* - * Decode %xx URL-decoding in-place. Ignores mal-formed sequences. - */ -static int urldecode(char *p) -{ - unsigned char *out = (unsigned char *)p; - unsigned char *save = out; - - for (; *p; p++) { - if (*p != '%') - *out++ = *p; - else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) { - /* Don't check, can't fail because of ixdigit() call. */ - *out++ = (OPENSSL_hexchar2int(p[1]) << 4) - | OPENSSL_hexchar2int(p[2]); - p += 2; - } - else - return -1; - } - *out = '\0'; - return (int)(out - save); -} -#endif - -#ifdef OCSP_DAEMON -static void socket_timeout(int signum) -{ - if (acfd != (int)INVALID_SOCKET) - (void)shutdown(acfd, SHUT_RD); -} -#endif - static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, - int timeout) + const char *port, int timeout) { -#ifdef OPENSSL_NO_SOCK - return 0; +#ifndef OPENSSL_NO_SOCK + return http_server_get_asn1_req(ASN1_ITEM_rptr(OCSP_REQUEST), + (ASN1_VALUE **)preq, NULL, pcbio, acbio, + NULL /* found_keep_alive */, + prog, port, 1 /* accept_get */, timeout); #else - int len; - OCSP_REQUEST *req = NULL; - char inbuf[2048], reqbuf[2048]; - char *p, *q; - BIO *cbio = NULL, *getbio = NULL, *b64 = NULL; - const char *client; - + BIO_printf(bio_err, + "Error getting OCSP request - sockets not supported\n"); *preq = NULL; - - /* Connection loss before accept() is routine, ignore silently */ - if (BIO_do_accept(acbio) <= 0) - return 0; - - cbio = BIO_pop(acbio); - *pcbio = cbio; - client = BIO_get_peer_name(cbio); - -# ifdef OCSP_DAEMON - if (timeout > 0) { - (void) BIO_get_fd(cbio, &acfd); - alarm(timeout); - } -# endif - - /* Read the request line. */ - len = BIO_gets(cbio, reqbuf, sizeof(reqbuf)); - if (len <= 0) - goto out; - - if (strncmp(reqbuf, "GET ", 4) == 0) { - /* Expecting GET {sp} /URL {sp} HTTP/1.x */ - for (p = reqbuf + 4; *p == ' '; ++p) - continue; - if (*p != '/') { - log_message(LOG_INFO, "Invalid request -- bad URL: %s", client); - goto out; - } - p++; - - /* Splice off the HTTP version identifier. */ - for (q = p; *q; q++) - if (*q == ' ') - break; - if (strncmp(q, " HTTP/1.", 8) != 0) { - log_message(LOG_INFO, - "Invalid request -- bad HTTP version: %s", client); - goto out; - } - *q = '\0'; - - /* - * Skip "GET / HTTP..." requests often used by load-balancers. Note: - * 'p' was incremented above to point to the first byte *after* the - * leading slash, so with 'GET / ' it is now an empty string. - */ - if (p[0] == '\0') - goto out; - - len = urldecode(p); - if (len <= 0) { - log_message(LOG_INFO, - "Invalid request -- bad URL encoding: %s", client); - goto out; - } - if ((getbio = BIO_new_mem_buf(p, len)) == NULL - || (b64 = BIO_new(BIO_f_base64())) == NULL) { - log_message(LOG_ERR, "Could not allocate base64 bio: %s", client); - goto out; - } - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - getbio = BIO_push(b64, getbio); - } else if (strncmp(reqbuf, "POST ", 5) != 0) { - log_message(LOG_INFO, "Invalid request -- bad HTTP verb: %s", client); - goto out; - } - - /* Read and skip past the headers. */ - for (;;) { - len = BIO_gets(cbio, inbuf, sizeof(inbuf)); - if (len <= 0) - goto out; - if ((inbuf[0] == '\r') || (inbuf[0] == '\n')) - break; - } - -# ifdef OCSP_DAEMON - /* Clear alarm before we close the client socket */ - alarm(0); - timeout = 0; -# endif - - /* Try to read OCSP request */ - if (getbio != NULL) { - req = d2i_OCSP_REQUEST_bio(getbio, NULL); - BIO_free_all(getbio); - } else { - req = d2i_OCSP_REQUEST_bio(cbio, NULL); - } - - if (req == NULL) - log_message(LOG_ERR, "Error parsing OCSP request"); - - *preq = req; - -out: -# ifdef OCSP_DAEMON - if (timeout > 0) - alarm(0); - acfd = (int)INVALID_SOCKET; -# endif - return 1; + return 0; #endif } -static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) +static int send_ocsp_response(BIO *cbio, const OCSP_RESPONSE *resp) { - char http_resp[] = - "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n" - "Content-Length: %d\r\n\r\n"; - if (cbio == NULL) - return 0; - BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL)); - i2d_OCSP_RESPONSE_bio(cbio, resp); - (void)BIO_flush(cbio); - return 1; -} - #ifndef OPENSSL_NO_SOCK -static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, - const char *path, - const STACK_OF(CONF_VALUE) *headers, - OCSP_REQUEST *req, int req_timeout) -{ - int fd; - int rv; - int i; - int add_host = 1; - OCSP_REQ_CTX *ctx = NULL; - OCSP_RESPONSE *rsp = NULL; - fd_set confds; - struct timeval tv; - - if (req_timeout != -1) - BIO_set_nbio(cbio, 1); - - rv = BIO_do_connect(cbio); - - if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) { - BIO_puts(bio_err, "Error connecting BIO\n"); - return NULL; - } - - if (BIO_get_fd(cbio, &fd) < 0) { - BIO_puts(bio_err, "Can't get connection fd\n"); - goto err; - } - - if (req_timeout != -1 && rv <= 0) { - FD_ZERO(&confds); - openssl_fdset(fd, &confds); - tv.tv_usec = 0; - tv.tv_sec = req_timeout; - rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv); - if (rv == 0) { - BIO_puts(bio_err, "Timeout on connect\n"); - return NULL; - } - } - - ctx = OCSP_sendreq_new(cbio, path, NULL, -1); - if (ctx == NULL) - return NULL; - - for (i = 0; i < sk_CONF_VALUE_num(headers); i++) { - CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i); - if (add_host == 1 && strcasecmp("host", hdr->name) == 0) - add_host = 0; - if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value)) - goto err; - } - - if (add_host == 1 && OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0) - goto err; - - if (!OCSP_REQ_CTX_set1_req(ctx, req)) - goto err; - - for (;;) { - rv = OCSP_sendreq_nbio(&rsp, ctx); - if (rv != -1) - break; - if (req_timeout == -1) - continue; - FD_ZERO(&confds); - openssl_fdset(fd, &confds); - tv.tv_usec = 0; - tv.tv_sec = req_timeout; - if (BIO_should_read(cbio)) { - rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv); - } else if (BIO_should_write(cbio)) { - rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv); - } else { - BIO_puts(bio_err, "Unexpected retry condition\n"); - goto err; - } - if (rv == 0) { - BIO_puts(bio_err, "Timeout on request\n"); - break; - } - if (rv == -1) { - BIO_puts(bio_err, "Select error\n"); - break; - } - - } - err: - OCSP_REQ_CTX_free(ctx); - - return rsp; + return http_server_send_asn1_resp(cbio, + 0 /* no keep-alive */, + "application/ocsp-response", + ASN1_ITEM_rptr(OCSP_RESPONSE), + (const ASN1_VALUE *)resp); +#else + BIO_printf(bio_err, + "Error sending OCSP response - sockets not supported\n"); + return 0; +#endif } -OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, - const char *host, const char *path, - const char *port, int use_ssl, - STACK_OF(CONF_VALUE) *headers, +#ifndef OPENSSL_NO_SOCK +OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, const char *host, + const char *port, const char *path, + const char *proxy, const char *no_proxy, + int use_ssl, STACK_OF(CONF_VALUE) *headers, int req_timeout) { - BIO *cbio = NULL; SSL_CTX *ctx = NULL; OCSP_RESPONSE *resp = NULL; - cbio = BIO_new_connect(host); - if (cbio == NULL) { - BIO_printf(bio_err, "Error creating connect BIO\n"); - goto end; - } - if (port != NULL) - BIO_set_conn_port(cbio, port); if (use_ssl == 1) { - BIO *sbio; ctx = SSL_CTX_new(TLS_client_method()); if (ctx == NULL) { BIO_printf(bio_err, "Error creating SSL context.\n"); goto end; } - SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); - sbio = BIO_new_ssl(ctx, 1); - cbio = BIO_push(sbio, cbio); } - resp = query_responder(cbio, host, path, headers, req, req_timeout); + resp = (OCSP_RESPONSE *) + app_http_post_asn1(host, port, path, proxy, no_proxy, + ctx, headers, "application/ocsp-request", + (ASN1_VALUE *)req, ASN1_ITEM_rptr(OCSP_REQUEST), + "application/ocsp-response", + req_timeout, ASN1_ITEM_rptr(OCSP_RESPONSE)); + if (resp == NULL) BIO_printf(bio_err, "Error querying OCSP responder\n"); + end: - BIO_free_all(cbio); SSL_CTX_free(ctx); return resp; } diff --git a/apps/openssl.c b/apps/openssl.c index f35d57f2648c..a3056c799f85 100644 --- a/apps/openssl.c +++ b/apps/openssl.c @@ -1,18 +1,18 @@ /* * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <internal/cryptlib.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <openssl/bio.h> #include <openssl/crypto.h> +#include <openssl/trace.h> #include <openssl/lhash.h> #include <openssl/conf.h> #include <openssl/x509.h> @@ -27,20 +27,8 @@ # include <unixio.h> #endif #include "apps.h" -#define INCLUDE_FUNCTION_TABLE #include "progs.h" -/* Structure to hold the number of columns to be displayed and the - * field width used to display them. - */ -typedef struct { - int columns; - int width; -} DISPLAY_COLUMNS; - -/* Special sentinel to exit the program. */ -#define EXIT_THE_PROGRAM (-1) - /* * The LHASH callbacks ("hash" & "cmp") have been replaced by functions with * the base prototypes (we cast each variable inside the function to the @@ -49,32 +37,27 @@ typedef struct { */ static LHASH_OF(FUNCTION) *prog_init(void); static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]); -static void list_pkey(void); -static void list_pkey_meth(void); -static void list_type(FUNC_TYPE ft, int one); -static void list_disabled(void); char *default_config_file = NULL; BIO *bio_in = NULL; BIO *bio_out = NULL; BIO *bio_err = NULL; -static void calculate_columns(DISPLAY_COLUMNS *dc) +static void warn_deprecated(const FUNCTION *fp) { - FUNCTION *f; - int len, maxlen = 0; - - for (f = functions; f->name != NULL; ++f) - if (f->type == FT_general || f->type == FT_md || f->type == FT_cipher) - if ((len = strlen(f->name)) > maxlen) - maxlen = len; - - dc->width = maxlen + 2; - dc->columns = (80 - 1) / dc->width; + if (fp->deprecated_version != NULL) + BIO_printf(bio_err, "The command %s was deprecated in version %s.", + fp->name, fp->deprecated_version); + else + BIO_printf(bio_err, "The command %s is deprecated.", fp->name); + if (strcmp(fp->deprecated_alternative, DEPRECATED_NO_ALTERNATIVE) != 0) + BIO_printf(bio_err, " Use '%s' instead.", fp->deprecated_alternative); + BIO_printf(bio_err, "\n"); } static int apps_startup(void) { + const char *use_libctx = NULL; #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif @@ -84,53 +67,186 @@ static int apps_startup(void) | OPENSSL_INIT_LOAD_CONFIG, NULL)) return 0; - setup_ui_method(); + (void)setup_ui_method(); + (void)setup_engine_loader(); + + /* + * NOTE: This is an undocumented feature required for testing only. + * There are no guarantees that it will exist in future builds. + */ + use_libctx = getenv("OPENSSL_TEST_LIBCTX"); + if (use_libctx != NULL) { + /* Set this to "1" to create a global libctx */ + if (strcmp(use_libctx, "1") == 0) { + if (app_create_libctx() == NULL) + return 0; + } + } return 1; } static void apps_shutdown(void) { + app_providers_cleanup(); + OSSL_LIB_CTX_free(app_get0_libctx()); + destroy_engine_loader(); destroy_ui_method(); - destroy_prefix_method(); } -static char *make_config_name(void) + +#ifndef OPENSSL_NO_TRACE +typedef struct tracedata_st { + BIO *bio; + unsigned int ingroup:1; +} tracedata; + +static size_t internal_trace_cb(const char *buf, size_t cnt, + int category, int cmd, void *vdata) { - const char *t; - size_t len; - char *p; - - if ((t = getenv("OPENSSL_CONF")) != NULL) - return OPENSSL_strdup(t); - - t = X509_get_default_cert_area(); - len = strlen(t) + 1 + strlen(OPENSSL_CONF) + 1; - p = app_malloc(len, "config filename buffer"); - strcpy(p, t); -#ifndef OPENSSL_SYS_VMS - strcat(p, "/"); -#endif - strcat(p, OPENSSL_CONF); + int ret = 0; + tracedata *trace_data = vdata; + char buffer[256], *hex; + CRYPTO_THREAD_ID tid; + + switch (cmd) { + case OSSL_TRACE_CTRL_BEGIN: + if (trace_data->ingroup) { + BIO_printf(bio_err, "ERROR: tracing already started\n"); + return 0; + } + trace_data->ingroup = 1; + + tid = CRYPTO_THREAD_get_current_id(); + hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid)); + BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ", + hex == NULL ? "<null>" : hex, + OSSL_trace_get_category_name(category)); + OPENSSL_free(hex); + BIO_set_prefix(trace_data->bio, buffer); + break; + case OSSL_TRACE_CTRL_WRITE: + if (!trace_data->ingroup) { + BIO_printf(bio_err, "ERROR: writing when tracing not started\n"); + return 0; + } + + ret = BIO_write(trace_data->bio, buf, cnt); + break; + case OSSL_TRACE_CTRL_END: + if (!trace_data->ingroup) { + BIO_printf(bio_err, "ERROR: finishing when tracing not started\n"); + return 0; + } + trace_data->ingroup = 0; + + BIO_set_prefix(trace_data->bio, NULL); + + break; + } + + return ret < 0 ? 0 : ret; +} + +DEFINE_STACK_OF(tracedata) +static STACK_OF(tracedata) *trace_data_stack; - return p; +static void tracedata_free(tracedata *data) +{ + BIO_free_all(data->bio); + OPENSSL_free(data); } +static STACK_OF(tracedata) *trace_data_stack; + +static void cleanup_trace(void) +{ + sk_tracedata_pop_free(trace_data_stack, tracedata_free); +} + +static void setup_trace_category(int category) +{ + BIO *channel; + tracedata *trace_data; + BIO *bio = NULL; + + if (OSSL_trace_enabled(category)) + return; + + bio = BIO_new(BIO_f_prefix()); + channel = BIO_push(bio, dup_bio_err(FORMAT_TEXT)); + trace_data = OPENSSL_zalloc(sizeof(*trace_data)); + + if (trace_data == NULL + || bio == NULL + || (trace_data->bio = channel) == NULL + || OSSL_trace_set_callback(category, internal_trace_cb, + trace_data) == 0 + || sk_tracedata_push(trace_data_stack, trace_data) == 0) { + + fprintf(stderr, + "warning: unable to setup trace callback for category '%s'.\n", + OSSL_trace_get_category_name(category)); + + OSSL_trace_set_callback(category, NULL, NULL); + BIO_free_all(channel); + } +} + +static void setup_trace(const char *str) +{ + char *val; + + /* + * We add this handler as early as possible to ensure it's executed + * as late as possible, i.e. after the TRACE code has done its cleanup + * (which happens last in OPENSSL_cleanup). + */ + atexit(cleanup_trace); + + trace_data_stack = sk_tracedata_new_null(); + val = OPENSSL_strdup(str); + + if (val != NULL) { + char *valp = val; + char *item; + + for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) { + int category = OSSL_trace_get_category_num(item); + + if (category == OSSL_TRACE_CATEGORY_ALL) { + while (++category < OSSL_TRACE_CATEGORY_NUM) + setup_trace_category(category); + break; + } else if (category > 0) { + setup_trace_category(category); + } else { + fprintf(stderr, + "warning: unknown trace category: '%s'.\n", item); + } + } + } + + OPENSSL_free(val); +} +#endif /* OPENSSL_NO_TRACE */ + +static char *help_argv[] = { "help", NULL }; + int main(int argc, char *argv[]) { FUNCTION f, *fp; LHASH_OF(FUNCTION) *prog = NULL; - char *p, *pname; - char buf[1024]; - const char *prompt; + char *pname; + const char *fname; ARGS arg; - int first, n, i, ret = 0; + int global_help = 0; + int ret = 0; arg.argv = NULL; arg.size = 0; /* Set up some of the environment. */ - default_config_file = make_config_name(); bio_in = dup_bio_in(FORMAT_TEXT); bio_out = dup_bio_out(FORMAT_TEXT); bio_err = dup_bio_err(FORMAT_TEXT); @@ -138,319 +254,75 @@ int main(int argc, char *argv[]) #if defined(OPENSSL_SYS_VMS) && defined(__DECC) argv = copy_argv(&argc, argv); #elif defined(_WIN32) - /* - * Replace argv[] with UTF-8 encoded strings. - */ + /* Replace argv[] with UTF-8 encoded strings. */ win32_utf8argv(&argc, &argv); #endif - p = getenv("OPENSSL_DEBUG_MEMORY"); - if (p != NULL && strcmp(p, "on") == 0) - CRYPTO_set_mem_debug(1); - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); - - if (getenv("OPENSSL_FIPS")) { - BIO_printf(bio_err, "FIPS mode not supported.\n"); - return 1; - } - - if (!apps_startup()) { - BIO_printf(bio_err, - "FATAL: Startup failure (dev note: apps_startup() failed)\n"); - ERR_print_errors(bio_err); - ret = 1; - goto end; - } +#ifndef OPENSSL_NO_TRACE + setup_trace(getenv("OPENSSL_TRACE")); +#endif - prog = prog_init(); - if (prog == NULL) { + if ((fname = "apps_startup", !apps_startup()) + || (fname = "prog_init", (prog = prog_init()) == NULL)) { BIO_printf(bio_err, - "FATAL: Startup failure (dev note: prog_init() failed)\n"); + "FATAL: Startup failure (dev note: %s()) for %s\n", + fname, argv[0]); ERR_print_errors(bio_err); ret = 1; goto end; } pname = opt_progname(argv[0]); + default_config_file = CONF_get1_default_config_file(); + if (default_config_file == NULL) + app_bail_out("%s: could not get default config file\n", pname); + /* first check the program name */ f.name = pname; fp = lh_FUNCTION_retrieve(prog, &f); - if (fp != NULL) { - argv[0] = pname; - ret = fp->func(argc, argv); - goto end; - } - - /* If there is stuff on the command line, run with that. */ - if (argc != 1) { + if (fp == NULL) { + /* We assume we've been called as 'openssl ...' */ + global_help = argc > 1 + && (strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0 + || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--h") == 0); argc--; argv++; - ret = do_cmd(prog, argc, argv); - if (ret < 0) - ret = 0; - goto end; + opt_appname(argc == 1 || global_help ? "help" : argv[0]); + } else { + argv[0] = pname; } - /* ok, lets enter interactive mode */ - for (;;) { - ret = 0; - /* Read a line, continue reading if line ends with \ */ - for (p = buf, n = sizeof(buf), i = 0, first = 1; n > 0; first = 0) { - prompt = first ? "OpenSSL> " : "> "; - p[0] = '\0'; -#ifndef READLINE - fputs(prompt, stdout); - fflush(stdout); - if (!fgets(p, n, stdin)) - goto end; - if (p[0] == '\0') - goto end; - i = strlen(p); - if (i <= 1) - break; - if (p[i - 2] != '\\') - break; - i -= 2; - p += i; - n -= i; -#else - { - extern char *readline(const char *); - extern void add_history(const char *cp); - char *text; - - text = readline(prompt); - if (text == NULL) - goto end; - i = strlen(text); - if (i == 0 || i > n) - break; - if (text[i - 1] != '\\') { - p += strlen(strcpy(p, text)); - free(text); - add_history(buf); - break; - } - - text[i - 1] = '\0'; - p += strlen(strcpy(p, text)); - free(text); - n -= i; - } -#endif - } + /* If there's a command, run with that, otherwise "help". */ + ret = argc == 0 || global_help + ? do_cmd(prog, 1, help_argv) + : do_cmd(prog, argc, argv); - if (!chopup_args(&arg, buf)) { - BIO_printf(bio_err, "Can't parse (no memory?)\n"); - break; - } - - ret = do_cmd(prog, arg.argc, arg.argv); - if (ret == EXIT_THE_PROGRAM) { - ret = 0; - goto end; - } - if (ret != 0) - BIO_printf(bio_err, "error in %s\n", arg.argv[0]); - (void)BIO_flush(bio_out); - (void)BIO_flush(bio_err); - } - ret = 1; end: OPENSSL_free(default_config_file); lh_FUNCTION_free(prog); OPENSSL_free(arg.argv); - app_RAND_write(); + if (!app_RAND_write()) + ret = EXIT_FAILURE; BIO_free(bio_in); BIO_free_all(bio_out); apps_shutdown(); -#ifndef OPENSSL_NO_CRYPTO_MDEBUG - if (CRYPTO_mem_leaks(bio_err) <= 0) - ret = 1; -#endif - BIO_free(bio_err); + BIO_free_all(bio_err); EXIT(ret); } -static void list_cipher_fn(const EVP_CIPHER *c, - const char *from, const char *to, void *arg) -{ - if (c != NULL) { - BIO_printf(arg, "%s\n", EVP_CIPHER_name(c)); - } else { - if (from == NULL) - from = "<undefined>"; - if (to == NULL) - to = "<undefined>"; - BIO_printf(arg, "%s => %s\n", from, to); - } -} - -static void list_md_fn(const EVP_MD *m, - const char *from, const char *to, void *arg) -{ - if (m != NULL) { - BIO_printf(arg, "%s\n", EVP_MD_name(m)); - } else { - if (from == NULL) - from = "<undefined>"; - if (to == NULL) - to = "<undefined>"; - BIO_printf((BIO *)arg, "%s => %s\n", from, to); - } -} - -static void list_missing_help(void) -{ - const FUNCTION *fp; - const OPTIONS *o; - - for (fp = functions; fp->name != NULL; fp++) { - if ((o = fp->help) != NULL) { - /* If there is help, list what flags are not documented. */ - for ( ; o->name != NULL; o++) { - if (o->helpstr == NULL) - BIO_printf(bio_out, "%s %s\n", fp->name, o->name); - } - } else if (fp->func != dgst_main) { - /* If not aliased to the dgst command, */ - BIO_printf(bio_out, "%s *\n", fp->name); - } - } -} - -static void list_options_for_command(const char *command) -{ - const FUNCTION *fp; - const OPTIONS *o; - - for (fp = functions; fp->name != NULL; fp++) - if (strcmp(fp->name, command) == 0) - break; - if (fp->name == NULL) { - BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n", - command); - return; - } - - if ((o = fp->help) == NULL) - return; - - for ( ; o->name != NULL; o++) { - if (o->name == OPT_HELP_STR - || o->name == OPT_MORE_STR - || o->name[0] == '\0') - continue; - BIO_printf(bio_out, "%s %c\n", o->name, o->valtype); - } -} - - -/* Unified enum for help and list commands. */ -typedef enum HELPLIST_CHOICE { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ONE, - OPT_COMMANDS, OPT_DIGEST_COMMANDS, OPT_OPTIONS, - OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS, - OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_DISABLED, OPT_MISSING_HELP -} HELPLIST_CHOICE; - -const OPTIONS list_options[] = { - {"help", OPT_HELP, '-', "Display this summary"}, - {"1", OPT_ONE, '-', "List in one column"}, - {"commands", OPT_COMMANDS, '-', "List of standard commands"}, - {"digest-commands", OPT_DIGEST_COMMANDS, '-', - "List of message digest commands"}, - {"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-', - "List of message digest algorithms"}, - {"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"}, - {"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-', - "List of cipher algorithms"}, - {"public-key-algorithms", OPT_PK_ALGORITHMS, '-', - "List of public key algorithms"}, - {"public-key-methods", OPT_PK_METHOD, '-', - "List of public key methods"}, - {"disabled", OPT_DISABLED, '-', - "List of disabled features"}, - {"missing-help", OPT_MISSING_HELP, '-', - "List missing detailed help strings"}, - {"options", OPT_OPTIONS, 's', - "List options for specified command"}, - {NULL} -}; - -int list_main(int argc, char **argv) -{ - char *prog; - HELPLIST_CHOICE o; - int one = 0, done = 0; - - prog = opt_init(argc, argv, list_options); - while ((o = opt_next()) != OPT_EOF) { - switch (o) { - case OPT_EOF: /* Never hit, but suppresses warning */ - case OPT_ERR: -opthelp: - BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); - return 1; - case OPT_HELP: - opt_help(list_options); - break; - case OPT_ONE: - one = 1; - break; - case OPT_COMMANDS: - list_type(FT_general, one); - break; - case OPT_DIGEST_COMMANDS: - list_type(FT_md, one); - break; - case OPT_DIGEST_ALGORITHMS: - EVP_MD_do_all_sorted(list_md_fn, bio_out); - break; - case OPT_CIPHER_COMMANDS: - list_type(FT_cipher, one); - break; - case OPT_CIPHER_ALGORITHMS: - EVP_CIPHER_do_all_sorted(list_cipher_fn, bio_out); - break; - case OPT_PK_ALGORITHMS: - list_pkey(); - break; - case OPT_PK_METHOD: - list_pkey_meth(); - break; - case OPT_DISABLED: - list_disabled(); - break; - case OPT_MISSING_HELP: - list_missing_help(); - break; - case OPT_OPTIONS: - list_options_for_command(opt_arg()); - break; - } - done = 1; - } - if (opt_num_rest() != 0) { - BIO_printf(bio_err, "Extra arguments given.\n"); - goto opthelp; - } - - if (!done) - goto opthelp; - - return 0; -} - typedef enum HELP_CHOICE { OPT_hERR = -1, OPT_hEOF = 0, OPT_hHELP } HELP_CHOICE; const OPTIONS help_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: help [options]\n"}, - {OPT_HELP_STR, 1, '-', " help [command]\n"}, + {OPT_HELP_STR, 1, '-', "Usage: help [options] [command]\n"}, + + OPT_SECTION("General"), {"help", OPT_hHELP, '-', "Display this summary"}, + + OPT_PARAMETERS(), + {"command", 0, 0, "Name of command to display help (optional)"}, {NULL} }; @@ -463,6 +335,7 @@ int help_main(int argc, char **argv) char *prog; HELP_CHOICE o; DISPLAY_COLUMNS dc; + char *new_argv[3]; prog = opt_init(argc, argv, help_options); while ((o = opt_next()) != OPT_hEOF) { @@ -477,9 +350,8 @@ int help_main(int argc, char **argv) } } + /* One optional argument, the command to get help for. */ if (opt_num_rest() == 1) { - char *new_argv[3]; - new_argv[0] = opt_rest()[0]; new_argv[1] = "--help"; new_argv[2] = NULL; @@ -490,8 +362,8 @@ int help_main(int argc, char **argv) return 1; } - calculate_columns(&dc); - BIO_printf(bio_err, "Standard commands"); + calculate_columns(functions, &dc); + BIO_printf(bio_err, "%s:\n\nStandard commands", prog); i = 0; tp = FT_none; for (fp = functions; fp->name != NULL; fp++) { @@ -520,37 +392,13 @@ int help_main(int argc, char **argv) return 0; } -static void list_type(FUNC_TYPE ft, int one) -{ - FUNCTION *fp; - int i = 0; - DISPLAY_COLUMNS dc = {0}; - - if (!one) - calculate_columns(&dc); - - for (fp = functions; fp->name != NULL; fp++) { - if (fp->type != ft) - continue; - if (one) { - BIO_printf(bio_out, "%s\n", fp->name); - } else { - if (i % dc.columns == 0 && i > 0) - BIO_printf(bio_out, "\n"); - BIO_printf(bio_out, "%-*s", dc.width, fp->name); - i++; - } - } - if (!one) - BIO_printf(bio_out, "\n\n"); -} - static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) { FUNCTION f, *fp; if (argc <= 0 || argv[0] == NULL) return 0; + memset(&f, 0, sizeof(f)); f.name = argv[0]; fp = lh_FUNCTION_retrieve(prog, &f); if (fp == NULL) { @@ -565,6 +413,8 @@ static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) } } if (fp != NULL) { + if (fp->deprecated_alternative != NULL) + warn_deprecated(fp); return fp->func(argc, argv); } if ((strncmp(argv[0], "no-", 3)) == 0) { @@ -580,61 +430,12 @@ static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) BIO_printf(bio_out, "%s\n", argv[0] + 3); return 1; } - if (strcmp(argv[0], "quit") == 0 || strcmp(argv[0], "q") == 0 || - strcmp(argv[0], "exit") == 0 || strcmp(argv[0], "bye") == 0) - /* Special value to mean "exit the program. */ - return EXIT_THE_PROGRAM; BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n", argv[0]); return 1; } -static void list_pkey(void) -{ - int i; - - for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { - const EVP_PKEY_ASN1_METHOD *ameth; - int pkey_id, pkey_base_id, pkey_flags; - const char *pinfo, *pem_str; - ameth = EVP_PKEY_asn1_get0(i); - EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags, - &pinfo, &pem_str, ameth); - if (pkey_flags & ASN1_PKEY_ALIAS) { - BIO_printf(bio_out, "Name: %s\n", OBJ_nid2ln(pkey_id)); - BIO_printf(bio_out, "\tAlias for: %s\n", - OBJ_nid2ln(pkey_base_id)); - } else { - BIO_printf(bio_out, "Name: %s\n", pinfo); - BIO_printf(bio_out, "\tType: %s Algorithm\n", - pkey_flags & ASN1_PKEY_DYNAMIC ? - "External" : "Builtin"); - BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id)); - if (pem_str == NULL) - pem_str = "(none)"; - BIO_printf(bio_out, "\tPEM string: %s\n", pem_str); - } - - } -} - -static void list_pkey_meth(void) -{ - size_t i; - size_t meth_count = EVP_PKEY_meth_get_count(); - - for (i = 0; i < meth_count; i++) { - const EVP_PKEY_METHOD *pmeth = EVP_PKEY_meth_get0(i); - int pkey_id, pkey_flags; - - EVP_PKEY_meth_get0_info(&pkey_id, &pkey_flags, pmeth); - BIO_printf(bio_out, "%s\n", OBJ_nid2ln(pkey_id)); - BIO_printf(bio_out, "\tType: %s Algorithm\n", - pkey_flags & ASN1_PKEY_DYNAMIC ? "External" : "Builtin"); - } -} - static int function_cmp(const FUNCTION * a, const FUNCTION * b) { return strncmp(a->name, b->name, 8); @@ -655,155 +456,6 @@ static int SortFnByName(const void *_f1, const void *_f2) return strcmp(f1->name, f2->name); } -static void list_disabled(void) -{ - BIO_puts(bio_out, "Disabled algorithms:\n"); -#ifdef OPENSSL_NO_ARIA - BIO_puts(bio_out, "ARIA\n"); -#endif -#ifdef OPENSSL_NO_BF - BIO_puts(bio_out, "BF\n"); -#endif -#ifdef OPENSSL_NO_BLAKE2 - BIO_puts(bio_out, "BLAKE2\n"); -#endif -#ifdef OPENSSL_NO_CAMELLIA - BIO_puts(bio_out, "CAMELLIA\n"); -#endif -#ifdef OPENSSL_NO_CAST - BIO_puts(bio_out, "CAST\n"); -#endif -#ifdef OPENSSL_NO_CMAC - BIO_puts(bio_out, "CMAC\n"); -#endif -#ifdef OPENSSL_NO_CMS - BIO_puts(bio_out, "CMS\n"); -#endif -#ifdef OPENSSL_NO_COMP - BIO_puts(bio_out, "COMP\n"); -#endif -#ifdef OPENSSL_NO_DES - BIO_puts(bio_out, "DES\n"); -#endif -#ifdef OPENSSL_NO_DGRAM - BIO_puts(bio_out, "DGRAM\n"); -#endif -#ifdef OPENSSL_NO_DH - BIO_puts(bio_out, "DH\n"); -#endif -#ifdef OPENSSL_NO_DSA - BIO_puts(bio_out, "DSA\n"); -#endif -#if defined(OPENSSL_NO_DTLS) - BIO_puts(bio_out, "DTLS\n"); -#endif -#if defined(OPENSSL_NO_DTLS1) - BIO_puts(bio_out, "DTLS1\n"); -#endif -#if defined(OPENSSL_NO_DTLS1_2) - BIO_puts(bio_out, "DTLS1_2\n"); -#endif -#ifdef OPENSSL_NO_EC - BIO_puts(bio_out, "EC\n"); -#endif -#ifdef OPENSSL_NO_EC2M - BIO_puts(bio_out, "EC2M\n"); -#endif -#ifdef OPENSSL_NO_ENGINE - BIO_puts(bio_out, "ENGINE\n"); -#endif -#ifdef OPENSSL_NO_GOST - BIO_puts(bio_out, "GOST\n"); -#endif -#ifdef OPENSSL_NO_HEARTBEATS - BIO_puts(bio_out, "HEARTBEATS\n"); -#endif -#ifdef OPENSSL_NO_IDEA - BIO_puts(bio_out, "IDEA\n"); -#endif -#ifdef OPENSSL_NO_MD2 - BIO_puts(bio_out, "MD2\n"); -#endif -#ifdef OPENSSL_NO_MD4 - BIO_puts(bio_out, "MD4\n"); -#endif -#ifdef OPENSSL_NO_MD5 - BIO_puts(bio_out, "MD5\n"); -#endif -#ifdef OPENSSL_NO_MDC2 - BIO_puts(bio_out, "MDC2\n"); -#endif -#ifdef OPENSSL_NO_OCB - BIO_puts(bio_out, "OCB\n"); -#endif -#ifdef OPENSSL_NO_OCSP - BIO_puts(bio_out, "OCSP\n"); -#endif -#ifdef OPENSSL_NO_PSK - BIO_puts(bio_out, "PSK\n"); -#endif -#ifdef OPENSSL_NO_RC2 - BIO_puts(bio_out, "RC2\n"); -#endif -#ifdef OPENSSL_NO_RC4 - BIO_puts(bio_out, "RC4\n"); -#endif -#ifdef OPENSSL_NO_RC5 - BIO_puts(bio_out, "RC5\n"); -#endif -#ifdef OPENSSL_NO_RMD160 - BIO_puts(bio_out, "RMD160\n"); -#endif -#ifdef OPENSSL_NO_RSA - BIO_puts(bio_out, "RSA\n"); -#endif -#ifdef OPENSSL_NO_SCRYPT - BIO_puts(bio_out, "SCRYPT\n"); -#endif -#ifdef OPENSSL_NO_SCTP - BIO_puts(bio_out, "SCTP\n"); -#endif -#ifdef OPENSSL_NO_SEED - BIO_puts(bio_out, "SEED\n"); -#endif -#ifdef OPENSSL_NO_SM2 - BIO_puts(bio_out, "SM2\n"); -#endif -#ifdef OPENSSL_NO_SM3 - BIO_puts(bio_out, "SM3\n"); -#endif -#ifdef OPENSSL_NO_SM4 - BIO_puts(bio_out, "SM4\n"); -#endif -#ifdef OPENSSL_NO_SOCK - BIO_puts(bio_out, "SOCK\n"); -#endif -#ifdef OPENSSL_NO_SRP - BIO_puts(bio_out, "SRP\n"); -#endif -#ifdef OPENSSL_NO_SRTP - BIO_puts(bio_out, "SRTP\n"); -#endif -#ifdef OPENSSL_NO_SSL3 - BIO_puts(bio_out, "SSL3\n"); -#endif -#ifdef OPENSSL_NO_TLS1 - BIO_puts(bio_out, "TLS1\n"); -#endif -#ifdef OPENSSL_NO_TLS1_1 - BIO_puts(bio_out, "TLS1_1\n"); -#endif -#ifdef OPENSSL_NO_TLS1_2 - BIO_puts(bio_out, "TLS1_2\n"); -#endif -#ifdef OPENSSL_NO_WHIRLPOOL - BIO_puts(bio_out, "WHIRLPOOL\n"); -#endif -#ifndef ZLIB - BIO_puts(bio_out, "ZLIB\n"); -#endif -} - static LHASH_OF(FUNCTION) *prog_init(void) { static LHASH_OF(FUNCTION) *ret = NULL; diff --git a/apps/openssl.cnf b/apps/openssl.cnf index 4acca4b0446f..03330e0120a2 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -1,7 +1,9 @@ # # OpenSSL example configuration file. -# This is mostly being used for generation of certificate requests. +# See doc/man5/config.pod for more info. # +# This is mostly being used for generation of certificate requests, +# but may be used for auto loading of providers # Note that you can include other files from the main configuration # file using the .include directive. @@ -11,9 +13,15 @@ # defined. HOME = . + # Use this in order to automatically load providers. +openssl_conf = openssl_init + +# Comment out the next line to ignore configuration errors +config_diagnostics = 1 + # Extra OBJECT IDENTIFIER info: -#oid_file = $ENV::HOME/.oid -oid_section = new_oids +# oid_file = $ENV::HOME/.oid +oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the @@ -23,7 +31,6 @@ oid_section = new_oids # X.509v3 extensions in its main [= default] section.) [ new_oids ] - # We can add new OIDs in here for use by 'ca', 'req' and 'ts'. # Add a simple OID like this: # testoid1=1.2.3.4 @@ -35,6 +42,36 @@ tsa_policy1 = 1.2.3.4.1 tsa_policy2 = 1.2.3.4.5.6 tsa_policy3 = 1.2.3.4.5.7 +# For FIPS +# Optionally include a file that is generated by the OpenSSL fipsinstall +# application. This file contains configuration data required by the OpenSSL +# fips provider. It contains a named section e.g. [fips_sect] which is +# referenced from the [provider_sect] below. +# Refer to the OpenSSL security policy for more information. +# .include fipsmodule.cnf + +[openssl_init] +providers = provider_sect + +# List of providers to load +[provider_sect] +default = default_sect +# The fips section name should match the section name inside the +# included fipsmodule.cnf. +# fips = fips_sect + +# If no providers are activated explicitly, the default one is activated implicitly. +# See man 7 OSSL_PROVIDER-default for more details. +# +# If you add a section explicitly activating any other provider(s), you most +# probably need to explicitly activate the default provider, otherwise it +# becomes unavailable in openssl. As a consequence applications depending on +# OpenSSL may not work correctly which could lead to significant system +# problems including inability to remotely access the system. +[default_sect] +# activate = 1 + + #################################################################### [ ca ] default_ca = CA_default # The default ca section @@ -171,27 +208,9 @@ unstructuredName = An optional company name basicConstraints=CA:FALSE -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer @@ -206,13 +225,6 @@ authorityKeyIdentifier=keyid,issuer # Copy subject details # issuerAltName=issuer:copy -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - # This is required for TSA certificates. # extendedKeyUsage = critical,timeStamping @@ -242,9 +254,6 @@ basicConstraints = critical,CA:true # left out by default. # keyUsage = cRLSign, keyCertSign -# Some might want this also -# nsCertType = sslCA, emailCA - # Include email address in subject alt name: another PKIX recommendation # subjectAltName=email:copy # Copy issuer details @@ -272,27 +281,9 @@ authorityKeyIdentifier=keyid:always basicConstraints=CA:FALSE -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer @@ -307,13 +298,6 @@ authorityKeyIdentifier=keyid,issuer # Copy subject details # issuerAltName=issuer:copy -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - # This really needs to be in place for it to be a proxy certificate. proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo @@ -348,3 +332,59 @@ ess_cert_id_chain = no # Must the ESS cert id chain be included? # (optional, default: no) ess_cert_id_alg = sha1 # algorithm to compute certificate # identifier (optional, default: sha1) + +[insta] # CMP using Insta Demo CA +# Message transfer +server = pki.certificate.fi:8700 +# proxy = # set this as far as needed, e.g., http://192.168.1.1:8080 +# tls_use = 0 +path = pkix/ + +# Server authentication +recipient = "/C=FI/O=Insta Demo/CN=Insta Demo CA" # or set srvcert or issuer +ignore_keyusage = 1 # potentially needed quirk +unprotected_errors = 1 # potentially needed quirk +extracertsout = insta.extracerts.pem + +# Client authentication +ref = 3078 # user identification +secret = pass:insta # can be used for both client and server side + +# Generic message options +cmd = ir # default operation, can be overridden on cmd line with, e.g., kur + +# Certificate enrollment +subject = "/CN=openssl-cmp-test" +newkey = insta.priv.pem +out_trusted = insta.ca.crt +certout = insta.cert.pem + +[pbm] # Password-based protection for Insta CA +# Server and client authentication +ref = $insta::ref # 3078 +secret = $insta::secret # pass:insta + +[signature] # Signature-based protection for Insta CA +# Server authentication +trusted = insta.ca.crt # does not include keyUsage digitalSignature + +# Client authentication +secret = # disable PBM +key = $insta::newkey # insta.priv.pem +cert = $insta::certout # insta.cert.pem + +[ir] +cmd = ir + +[cr] +cmd = cr + +[kur] +# Certificate update +cmd = kur +oldcert = $insta::certout # insta.cert.pem + +[rr] +# Certificate revocation +cmd = rr +oldcert = $insta::certout # insta.cert.pem diff --git a/apps/passwd.c b/apps/passwd.c index af08ccd4ac0f..64b2e76c147a 100644 --- a/apps/passwd.c +++ b/apps/passwd.c @@ -1,7 +1,7 @@ /* * Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -16,13 +16,13 @@ #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/rand.h> -#ifndef OPENSSL_NO_DES +#if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0) # include <openssl/des.h> #endif #include <openssl/md5.h> #include <openssl/sha.h> -static unsigned const char cov_2char[64] = { +static const unsigned char cov_2char[64] = { /* from crypto/des/fcrypt.c */ 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, @@ -38,7 +38,6 @@ static const char ascii_dollar[] = { 0x24, 0x00 }; typedef enum { passwd_unset = 0, - passwd_crypt, passwd_md5, passwd_apr1, passwd_sha256, @@ -51,32 +50,43 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, int reverse, size_t pw_maxlen, passwd_modes mode); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_IN, OPT_NOVERIFY, OPT_QUIET, OPT_TABLE, OPT_REVERSE, OPT_APR1, - OPT_1, OPT_5, OPT_6, OPT_CRYPT, OPT_AIXMD5, OPT_SALT, OPT_STDIN, - OPT_R_ENUM + OPT_1, OPT_5, OPT_6, OPT_AIXMD5, OPT_SALT, OPT_STDIN, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS passwd_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [password]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Read passwords from file"}, {"noverify", OPT_NOVERIFY, '-', "Never verify when reading password from terminal"}, + {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, + + OPT_SECTION("Output"), {"quiet", OPT_QUIET, '-', "No warnings"}, {"table", OPT_TABLE, '-', "Format output as table"}, {"reverse", OPT_REVERSE, '-', "Switch table columns"}, + + OPT_SECTION("Cryptographic"), {"salt", OPT_SALT, 's', "Use provided salt"}, - {"stdin", OPT_STDIN, '-', "Read passwords from stdin"}, {"6", OPT_6, '-', "SHA512-based password algorithm"}, {"5", OPT_5, '-', "SHA256-based password algorithm"}, {"apr1", OPT_APR1, '-', "MD5-based password algorithm, Apache variant"}, {"1", OPT_1, '-', "MD5-based password algorithm"}, {"aixmd5", OPT_AIXMD5, '-', "AIX MD5-based password algorithm"}, -#ifndef OPENSSL_NO_DES - {"crypt", OPT_CRYPT, '-', "Standard Unix password algorithm (default)"}, -#endif + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"password", 0, 0, "Password text to digest (optional)"}, {NULL} }; @@ -154,13 +164,6 @@ int passwd_main(int argc, char **argv) goto opthelp; mode = passwd_aixmd5; break; - case OPT_CRYPT: -#ifndef OPENSSL_NO_DES - if (mode != passwd_unset) - goto opthelp; - mode = passwd_crypt; -#endif - break; case OPT_SALT: passed_salt = 1; salt = opt_arg(); @@ -175,11 +178,16 @@ int passwd_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* All remaining arguments are the password text */ argc = opt_num_rest(); argv = opt_rest(); - if (*argv != NULL) { if (pw_source_defined) goto opthelp; @@ -187,16 +195,14 @@ int passwd_main(int argc, char **argv) passwds = argv; } + if (!app_RAND_load()) + goto end; + if (mode == passwd_unset) { /* use default */ - mode = passwd_crypt; + mode = passwd_md5; } -#ifdef OPENSSL_NO_DES - if (mode == passwd_crypt) - goto opthelp; -#endif - if (infile != NULL && in_stdin) { BIO_printf(bio_err, "%s: Can't combine -in and -stdin\n", prog); goto end; @@ -212,9 +218,6 @@ int passwd_main(int argc, char **argv) goto end; } - if (mode == passwd_crypt) - pw_maxlen = 8; - if (passwds == NULL) { /* no passwords on the command line */ @@ -413,7 +416,7 @@ static char *md5crypt(const char *passwd, const char *magic, const char *salt) if (!EVP_DigestInit_ex(md2, EVP_md5(), NULL)) goto err; if (!EVP_DigestUpdate(md2, - (i & 1) ? (unsigned const char *)passwd : buf, + (i & 1) ? (const unsigned char *)passwd : buf, (i & 1) ? passwd_len : sizeof(buf))) goto err; if (i % 3) { @@ -425,7 +428,7 @@ static char *md5crypt(const char *passwd, const char *magic, const char *salt) goto err; } if (!EVP_DigestUpdate(md2, - (i & 1) ? buf : (unsigned const char *)passwd, + (i & 1) ? buf : (const unsigned char *)passwd, (i & 1) ? sizeof(buf) : passwd_len)) goto err; if (!EVP_DigestFinal_ex(md2, buf, NULL)) @@ -515,7 +518,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) EVP_MD_CTX *md = NULL, *md2 = NULL; const EVP_MD *sha = NULL; size_t passwd_len, salt_len, magic_len; - unsigned int rounds = 5000; /* Default */ + unsigned int rounds = ROUNDS_DEFAULT; /* Default */ char rounds_custom = 0; char *p_bytes = NULL; char *s_bytes = NULL; @@ -627,7 +630,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) n = passwd_len; while (n) { if (!EVP_DigestUpdate(md, - (n & 1) ? buf : (unsigned const char *)passwd, + (n & 1) ? buf : (const unsigned char *)passwd, (n & 1) ? buf_size : passwd_len)) goto err; n >>= 1; @@ -673,7 +676,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) if (!EVP_DigestInit_ex(md2, sha, NULL)) goto err; if (!EVP_DigestUpdate(md2, - (n & 1) ? (unsigned const char *)p_bytes : buf, + (n & 1) ? (const unsigned char *)p_bytes : buf, (n & 1) ? passwd_len : buf_size)) goto err; if (n % 3) { @@ -685,7 +688,7 @@ static char *shacrypt(const char *passwd, const char *magic, const char *salt) goto err; } if (!EVP_DigestUpdate(md2, - (n & 1) ? buf : (unsigned const char *)p_bytes, + (n & 1) ? buf : (const unsigned char *)p_bytes, (n & 1) ? buf_size : passwd_len)) goto err; if (!EVP_DigestFinal_ex(md2, buf, NULL)) @@ -785,11 +788,6 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, size_t saltlen = 0; size_t i; -#ifndef OPENSSL_NO_DES - if (mode == passwd_crypt) - saltlen = 2; -#endif /* !OPENSSL_NO_DES */ - if (mode == passwd_md5 || mode == passwd_apr1 || mode == passwd_aixmd5) saltlen = 8; @@ -828,10 +826,6 @@ static int do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, assert(strlen(passwd) <= pw_maxlen); /* now compute password hash */ -#ifndef OPENSSL_NO_DES - if (mode == passwd_crypt) - hash = DES_crypt(passwd, *salt_p); -#endif if (mode == passwd_md5 || mode == passwd_apr1) hash = md5crypt(passwd, (mode == passwd_md5 ? "1" : "apr1"), *salt_p); if (mode == passwd_aixmd5) diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 8c5d963b8c65..b442d358f8b7 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c @@ -1,13 +1,14 @@ /* - * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -17,6 +18,8 @@ #include <openssl/err.h> #include <openssl/pem.h> #include <openssl/pkcs12.h> +#include <openssl/provider.h> +#include <openssl/kdf.h> #define NOKEYS 0x1 #define NOCERTS 0x2 @@ -26,7 +29,13 @@ #define PASSWD_BUF_SIZE 2048 +#define WARN_EXPORT(opt) \ + BIO_printf(bio_err, "Warning: -%s option ignored with -export\n", opt); +#define WARN_NO_EXPORT(opt) \ + BIO_printf(bio_err, "Warning: -%s option ignored without -export\n", opt); + static int get_cert_chain(X509 *cert, X509_STORE *store, + STACK_OF(X509) *untrusted_certs, STACK_OF(X509) **chain); int dump_certs_keys_p12(BIO *out, const PKCS12 *p12, const char *pass, int passlen, int options, @@ -46,100 +55,131 @@ int cert_load(BIO *in, STACK_OF(X509) *sk); static int set_pbe(int *ppbe, const char *str); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_CIPHER, OPT_NOKEYS, OPT_KEYEX, OPT_KEYSIG, OPT_NOCERTS, OPT_CLCERTS, OPT_CACERTS, OPT_NOOUT, OPT_INFO, OPT_CHAIN, OPT_TWOPASS, OPT_NOMACVER, - OPT_DESCERT, OPT_EXPORT, OPT_NOITER, OPT_MACITER, OPT_NOMACITER, - OPT_NOMAC, OPT_LMK, OPT_NODES, OPT_MACALG, OPT_CERTPBE, OPT_KEYPBE, - OPT_INKEY, OPT_CERTFILE, OPT_NAME, OPT_CSP, OPT_CANAME, +#ifndef OPENSSL_NO_DES + OPT_DESCERT, +#endif + OPT_EXPORT, OPT_ITER, OPT_NOITER, OPT_MACITER, OPT_NOMACITER, + OPT_NOMAC, OPT_LMK, OPT_NODES, OPT_NOENC, OPT_MACALG, OPT_CERTPBE, OPT_KEYPBE, + OPT_INKEY, OPT_CERTFILE, OPT_UNTRUSTED, OPT_PASSCERTS, + OPT_NAME, OPT_CSP, OPT_CANAME, OPT_IN, OPT_OUT, OPT_PASSIN, OPT_PASSOUT, OPT_PASSWORD, OPT_CAPATH, - OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_ENGINE, - OPT_R_ENUM + OPT_CAFILE, OPT_CASTORE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_ENGINE, + OPT_R_ENUM, OPT_PROV_ENUM, +#ifndef OPENSSL_NO_DES + OPT_LEGACY_ALG +#endif } OPTION_CHOICE; const OPTIONS pkcs12_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"in", OPT_IN, '<', "Input file"}, + {"out", OPT_OUT, '>', "Output file"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, + {"password", OPT_PASSWORD, 's', "Set PKCS#12 import/export password source"}, + {"twopass", OPT_TWOPASS, '-', "Separate MAC, encryption passwords"}, {"nokeys", OPT_NOKEYS, '-', "Don't output private keys"}, - {"keyex", OPT_KEYEX, '-', "Set MS key exchange type"}, - {"keysig", OPT_KEYSIG, '-', "Set MS key signature type"}, {"nocerts", OPT_NOCERTS, '-', "Don't output certificates"}, - {"clcerts", OPT_CLCERTS, '-', "Only output client certificates"}, - {"cacerts", OPT_CACERTS, '-', "Only output CA certificates"}, - {"noout", OPT_NOOUT, '-', "Don't output anything, just verify"}, - {"info", OPT_INFO, '-', "Print info about PKCS#12 structure"}, - {"chain", OPT_CHAIN, '-', "Add certificate chain"}, - {"twopass", OPT_TWOPASS, '-', "Separate MAC, encryption passwords"}, - {"nomacver", OPT_NOMACVER, '-', "Don't verify MAC"}, -#ifndef OPENSSL_NO_RC2 - {"descert", OPT_DESCERT, '-', - "Encrypt output with 3DES (default RC2-40)"}, - {"certpbe", OPT_CERTPBE, 's', - "Certificate PBE algorithm (default RC2-40)"}, -#else - {"descert", OPT_DESCERT, '-', "Encrypt output with 3DES (the default)"}, - {"certpbe", OPT_CERTPBE, 's', "Certificate PBE algorithm (default 3DES)"}, + {"noout", OPT_NOOUT, '-', "Don't output anything, just verify PKCS#12 input"}, +#ifndef OPENSSL_NO_DES + {"legacy", OPT_LEGACY_ALG, '-', +# ifdef OPENSSL_NO_RC2 + "Use legacy encryption algorithm 3DES_CBC for keys and certs" +# else + "Use legacy encryption: 3DES_CBC for keys, RC2_CBC for certs" +# endif + }, #endif - {"export", OPT_EXPORT, '-', "Output PKCS12 file"}, - {"noiter", OPT_NOITER, '-', "Don't use encryption iteration"}, - {"maciter", OPT_MACITER, '-', "Use MAC iteration"}, - {"nomaciter", OPT_NOMACITER, '-', "Don't use MAC iteration"}, - {"nomac", OPT_NOMAC, '-', "Don't generate MAC"}, - {"LMK", OPT_LMK, '-', - "Add local machine keyset attribute to private key"}, - {"nodes", OPT_NODES, '-', "Don't encrypt private keys"}, - {"macalg", OPT_MACALG, 's', - "Digest algorithm used in MAC (default SHA1)"}, - {"keypbe", OPT_KEYPBE, 's', "Private key PBE algorithm (default 3DES)"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + OPT_PROV_OPTIONS, OPT_R_OPTIONS, - {"inkey", OPT_INKEY, 's', "Private key if not infile"}, - {"certfile", OPT_CERTFILE, '<', "Load certs from file"}, - {"name", OPT_NAME, 's', "Use name as friendly name"}, - {"CSP", OPT_CSP, 's', "Microsoft CSP name"}, - {"caname", OPT_CANAME, 's', - "Use name as CA friendly name (can be repeated)"}, - {"in", OPT_IN, '<', "Input filename"}, - {"out", OPT_OUT, '>', "Output filename"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - {"password", OPT_PASSWORD, 's', "Set import/export password source"}, - {"CApath", OPT_CAPATH, '/', "PEM-format directory of CA's"}, + + OPT_SECTION("PKCS#12 import (parsing PKCS#12)"), + {"info", OPT_INFO, '-', "Print info about PKCS#12 structure"}, + {"nomacver", OPT_NOMACVER, '-', "Don't verify integrity MAC"}, + {"clcerts", OPT_CLCERTS, '-', "Only output client certificates"}, + {"cacerts", OPT_CACERTS, '-', "Only output CA certificates"}, + {"", OPT_CIPHER, '-', "Any supported cipher for output encryption"}, + {"noenc", OPT_NOENC, '-', "Don't encrypt private keys"}, + {"nodes", OPT_NODES, '-', "Don't encrypt private keys; deprecated"}, + + OPT_SECTION("PKCS#12 output (export)"), + {"export", OPT_EXPORT, '-', "Create PKCS12 file"}, + {"inkey", OPT_INKEY, 's', "Private key, else read from -in input file"}, + {"certfile", OPT_CERTFILE, '<', "Extra certificates for PKCS12 output"}, + {"passcerts", OPT_PASSCERTS, 's', "Certificate file pass phrase source"}, + {"chain", OPT_CHAIN, '-', "Build and add certificate chain for EE cert,"}, + {OPT_MORE_STR, 0, 0, + "which is the 1st cert from -in matching the private key (if given)"}, + {"untrusted", OPT_UNTRUSTED, '<', "Untrusted certificates for chain building"}, {"CAfile", OPT_CAFILE, '<', "PEM-format file of CA's"}, + {"CApath", OPT_CAPATH, '/', "PEM-format directory of CA's"}, + {"CAstore", OPT_CASTORE, ':', "URI to store of CA's"}, {"no-CAfile", OPT_NOCAFILE, '-', "Do not load the default certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', "Do not load certificates from the default certificates directory"}, - {"", OPT_CIPHER, '-', "Any supported cipher"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store"}, + {"name", OPT_NAME, 's', "Use name as friendly name"}, + {"caname", OPT_CANAME, 's', + "Use name as CA friendly name (can be repeated)"}, + {"CSP", OPT_CSP, 's', "Microsoft CSP name"}, + {"LMK", OPT_LMK, '-', + "Add local machine keyset attribute to private key"}, + {"keyex", OPT_KEYEX, '-', "Set key type to MS key exchange"}, + {"keysig", OPT_KEYSIG, '-', "Set key type to MS key signature"}, + {"keypbe", OPT_KEYPBE, 's', "Private key PBE algorithm (default AES-256 CBC)"}, + {"certpbe", OPT_CERTPBE, 's', + "Certificate PBE algorithm (default PBES2 with PBKDF2 and AES-256 CBC)"}, +#ifndef OPENSSL_NO_DES + {"descert", OPT_DESCERT, '-', + "Encrypt output with 3DES (default PBES2 with PBKDF2 and AES-256 CBC)"}, #endif + {"macalg", OPT_MACALG, 's', + "Digest algorithm to use in MAC (default SHA256)"}, + {"iter", OPT_ITER, 'p', "Specify the iteration count for encryption and MAC"}, + {"noiter", OPT_NOITER, '-', "Don't use encryption iteration"}, + {"nomaciter", OPT_NOMACITER, '-', "Don't use MAC iteration)"}, + {"maciter", OPT_MACITER, '-', "Unused, kept for backwards compatibility"}, + {"nomac", OPT_NOMAC, '-', "Don't generate MAC"}, {NULL} }; int pkcs12_main(int argc, char **argv) { char *infile = NULL, *outfile = NULL, *keyname = NULL, *certfile = NULL; + char *untrusted = NULL, *ciphername = NULL, *enc_flag = NULL; + char *passcertsarg = NULL, *passcerts = NULL; char *name = NULL, *csp_name = NULL; char pass[PASSWD_BUF_SIZE] = "", macpass[PASSWD_BUF_SIZE] = ""; - int export_cert = 0, options = 0, chain = 0, twopass = 0, keytype = 0; - int iter = PKCS12_DEFAULT_ITER, maciter = PKCS12_DEFAULT_ITER; -#ifndef OPENSSL_NO_RC2 - int cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; -#else - int cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; + int export_pkcs12 = 0, options = 0, chain = 0, twopass = 0, keytype = 0; +#ifndef OPENSSL_NO_DES + int use_legacy = 0; #endif - int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; + /* use library defaults for the iter, maciter, cert, and key PBE */ + int iter = 0, maciter = 0; + int cert_pbe = NID_undef; + int key_pbe = NID_undef; int ret = 1, macver = 1, add_lmk = 0, private = 0; int noprompt = 0; char *passinarg = NULL, *passoutarg = NULL, *passarg = NULL; char *passin = NULL, *passout = NULL, *macalg = NULL; char *cpass = NULL, *mpass = NULL, *badpass = NULL; - const char *CApath = NULL, *CAfile = NULL, *prog; - int noCApath = 0, noCAfile = 0; + const char *CApath = NULL, *CAfile = NULL, *CAstore = NULL, *prog; + int noCApath = 0, noCAfile = 0, noCAstore = 0; ENGINE *e = NULL; BIO *in = NULL, *out = NULL; PKCS12 *p12 = NULL; STACK_OF(OPENSSL_STRING) *canames = NULL; - const EVP_CIPHER *enc = EVP_des_ede3_cbc(); + EVP_CIPHER *default_enc = (EVP_CIPHER *)EVP_aes_256_cbc(); + EVP_CIPHER *enc = (EVP_CIPHER *)default_enc; OPTION_CHOICE o; prog = opt_init(argc, argv, pkcs12_options); @@ -187,34 +227,47 @@ int pkcs12_main(int argc, char **argv) case OPT_NOMACVER: macver = 0; break; +#ifndef OPENSSL_NO_DES case OPT_DESCERT: cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; break; +#endif case OPT_EXPORT: - export_cert = 1; + export_pkcs12 = 1; + break; + case OPT_NODES: + case OPT_NOENC: + /* + * |enc_flag| stores the name of the option used so it + * can be printed if an error message is output. + */ + enc_flag = opt_flag() + 1; + enc = NULL; + ciphername = NULL; break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &enc)) - goto opthelp; + ciphername = opt_unknown(); + enc_flag = opt_unknown(); + break; + case OPT_ITER: + maciter = iter = opt_int_arg(); break; case OPT_NOITER: iter = 1; break; case OPT_MACITER: - maciter = PKCS12_DEFAULT_ITER; + /* no-op */ break; case OPT_NOMACITER: maciter = 1; break; case OPT_NOMAC: + cert_pbe = -1; maciter = -1; break; case OPT_MACALG: macalg = opt_arg(); break; - case OPT_NODES: - enc = NULL; - break; case OPT_CERTPBE: if (!set_pbe(&cert_pbe, opt_arg())) goto opthelp; @@ -233,6 +286,12 @@ int pkcs12_main(int argc, char **argv) case OPT_CERTFILE: certfile = opt_arg(); break; + case OPT_UNTRUSTED: + untrusted = opt_arg(); + break; + case OPT_PASSCERTS: + passcertsarg = opt_arg(); + break; case OPT_NAME: name = opt_arg(); break; @@ -266,28 +325,145 @@ int pkcs12_main(int argc, char **argv) case OPT_CAPATH: CApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_CAFILE: CAfile = opt_arg(); break; case OPT_NOCAPATH: noCApath = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_NOCAFILE: noCAfile = 1; break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; +#ifndef OPENSSL_NO_DES + case OPT_LEGACY_ALG: + use_legacy = 1; + break; +#endif + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (!app_RAND_load()) + goto end; + + if (ciphername != NULL) { + if (!opt_cipher_any(ciphername, &enc)) + goto opthelp; + } + if (export_pkcs12) { + if ((options & INFO) != 0) + WARN_EXPORT("info"); + if (macver == 0) + WARN_EXPORT("nomacver"); + if ((options & CLCERTS) != 0) + WARN_EXPORT("clcerts"); + if ((options & CACERTS) != 0) + WARN_EXPORT("cacerts"); + if (enc != default_enc) + BIO_printf(bio_err, + "Warning: output encryption option -%s ignored with -export\n", enc_flag); + } else { + if (keyname != NULL) + WARN_NO_EXPORT("inkey"); + if (certfile != NULL) + WARN_NO_EXPORT("certfile"); + if (passcertsarg != NULL) + WARN_NO_EXPORT("passcerts"); + if (chain) + WARN_NO_EXPORT("chain"); + if (untrusted != NULL) + WARN_NO_EXPORT("untrusted"); + if (CAfile != NULL) + WARN_NO_EXPORT("CAfile"); + if (CApath != NULL) + WARN_NO_EXPORT("CApath"); + if (CAstore != NULL) + WARN_NO_EXPORT("CAstore"); + if (noCAfile) + WARN_NO_EXPORT("no-CAfile"); + if (noCApath) + WARN_NO_EXPORT("no-CApath"); + if (noCAstore) + WARN_NO_EXPORT("no-CAstore"); + if (name != NULL) + WARN_NO_EXPORT("name"); + if (canames != NULL) + WARN_NO_EXPORT("caname"); + if (csp_name != NULL) + WARN_NO_EXPORT("CSP"); + if (add_lmk) + WARN_NO_EXPORT("LMK"); + if (keytype == KEY_EX) + WARN_NO_EXPORT("keyex"); + if (keytype == KEY_SIG) + WARN_NO_EXPORT("keysig"); + if (key_pbe != NID_undef) + WARN_NO_EXPORT("keypbe"); + if (cert_pbe != NID_undef && cert_pbe != -1) + WARN_NO_EXPORT("certpbe and -descert"); + if (macalg != NULL) + WARN_NO_EXPORT("macalg"); + if (iter != 0) + WARN_NO_EXPORT("iter and -noiter"); + if (maciter == 1) + WARN_NO_EXPORT("nomaciter"); + if (cert_pbe == -1 && maciter == -1) + WARN_NO_EXPORT("nomac"); + } +#ifndef OPENSSL_NO_DES + if (use_legacy) { + /* load the legacy provider if not loaded already*/ + if (!OSSL_PROVIDER_available(app_get0_libctx(), "legacy")) { + if (!app_provider_load(app_get0_libctx(), "legacy")) + goto end; + /* load the default provider explicitly */ + if (!app_provider_load(app_get0_libctx(), "default")) + goto end; + } + if (cert_pbe == NID_undef) { + /* Adapt default algorithm */ +# ifndef OPENSSL_NO_RC2 + cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; +# else + cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; +# endif + } + + if (key_pbe == NID_undef) + key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; + if (enc == default_enc) + enc = (EVP_CIPHER *)EVP_des_ede3_cbc(); + if (macalg == NULL) + macalg = "sha1"; + } +#endif + private = 1; + if (!app_passwd(passcertsarg, NULL, &passcerts, NULL)) { + BIO_printf(bio_err, "Error getting certificate file password\n"); + goto end; + } + if (passarg != NULL) { - if (export_cert) + if (export_pkcs12) passoutarg = passarg; else passinarg = passarg; @@ -299,7 +475,7 @@ int pkcs12_main(int argc, char **argv) } if (cpass == NULL) { - if (export_cert) + if (export_pkcs12) cpass = passout; else cpass = passin; @@ -309,7 +485,7 @@ int pkcs12_main(int argc, char **argv) mpass = cpass; noprompt = 1; if (twopass) { - if (export_cert) + if (export_pkcs12) BIO_printf(bio_err, "Option -twopass cannot be used with -passout or -password\n"); else BIO_printf(bio_err, "Option -twopass cannot be used with -passin or -password\n"); @@ -325,7 +501,7 @@ int pkcs12_main(int argc, char **argv) if (1) { #ifndef OPENSSL_NO_UI_CONSOLE if (EVP_read_pw_string( - macpass, sizeof(macpass), "Enter MAC Password:", export_cert)) { + macpass, sizeof(macpass), "Enter MAC Password:", export_pkcs12)) { BIO_printf(bio_err, "Can't read Password\n"); goto end; } @@ -336,96 +512,126 @@ int pkcs12_main(int argc, char **argv) } } - if (export_cert) { + if (export_pkcs12) { EVP_PKEY *key = NULL; - X509 *ucert = NULL, *x = NULL; + X509 *ee_cert = NULL, *x = NULL; STACK_OF(X509) *certs = NULL; - const EVP_MD *macmd = NULL; + STACK_OF(X509) *untrusted_certs = NULL; + EVP_MD *macmd = NULL; unsigned char *catmp = NULL; int i; if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { - BIO_printf(bio_err, "Nothing to do!\n"); + BIO_printf(bio_err, "Nothing to export due to -noout or -nocerts and -nokeys\n"); goto export_end; } - if (options & NOCERTS) + if ((options & NOCERTS) != 0) { chain = 0; + BIO_printf(bio_err, "Warning: -chain option ignored with -nocerts\n"); + } if (!(options & NOKEYS)) { key = load_key(keyname ? keyname : infile, - FORMAT_PEM, 1, passin, e, "private key"); + FORMAT_PEM, 1, passin, e, + keyname ? + "private key from -inkey file" : + "private key from -in file"); if (key == NULL) goto export_end; } - /* Load in all certs in input file */ + /* Load all certs in input file */ if (!(options & NOCERTS)) { - if (!load_certs(infile, &certs, FORMAT_PEM, NULL, - "certificates")) + if (!load_certs(infile, 1, &certs, passin, + "certificates from -in file")) goto export_end; + if (sk_X509_num(certs) < 1) { + BIO_printf(bio_err, "No certificate in -in file %s\n", infile); + goto export_end; + } if (key != NULL) { /* Look for matching private key */ for (i = 0; i < sk_X509_num(certs); i++) { x = sk_X509_value(certs, i); if (X509_check_private_key(x, key)) { - ucert = x; + ee_cert = x; /* Zero keyid and alias */ - X509_keyid_set1(ucert, NULL, 0); - X509_alias_set1(ucert, NULL, 0); + X509_keyid_set1(ee_cert, NULL, 0); + X509_alias_set1(ee_cert, NULL, 0); /* Remove from list */ (void)sk_X509_delete(certs, i); break; } } - if (ucert == NULL) { + if (ee_cert == NULL) { BIO_printf(bio_err, - "No certificate matches private key\n"); + "No cert in -in file '%s' matches private key\n", + infile); goto export_end; } } - } - /* Add any more certificates asked for */ - if (certfile != NULL) { - if (!load_certs(certfile, &certs, FORMAT_PEM, NULL, - "certificates from certfile")) + /* Load any untrusted certificates for chain building */ + if (untrusted != NULL) { + if (!load_certs(untrusted, 0, &untrusted_certs, passcerts, + "untrusted certificates")) goto export_end; } - /* If chaining get chain from user cert */ + /* If chaining get chain from end entity cert */ if (chain) { int vret; STACK_OF(X509) *chain2; X509_STORE *store; - if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) + X509 *ee_cert_tmp = ee_cert; + + /* Assume the first cert if we haven't got anything else */ + if (ee_cert_tmp == NULL && certs != NULL) + ee_cert_tmp = sk_X509_value(certs, 0); + + if (ee_cert_tmp == NULL) { + BIO_printf(bio_err, + "No end entity certificate to check with -chain\n"); + goto export_end; + } + + if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) == NULL) goto export_end; - vret = get_cert_chain(ucert, store, &chain2); + vret = get_cert_chain(ee_cert_tmp, store, untrusted_certs, &chain2); X509_STORE_free(store); if (vret == X509_V_OK) { - /* Exclude verified certificate */ - for (i = 1; i < sk_X509_num(chain2); i++) - sk_X509_push(certs, sk_X509_value(chain2, i)); - /* Free first certificate */ - X509_free(sk_X509_value(chain2, 0)); - sk_X509_free(chain2); + int add_certs; + /* Remove from chain2 the first (end entity) certificate */ + X509_free(sk_X509_shift(chain2)); + /* Add the remaining certs (except for duplicates) */ + add_certs = X509_add_certs(certs, chain2, X509_ADD_FLAG_UP_REF + | X509_ADD_FLAG_NO_DUP); + sk_X509_pop_free(chain2, X509_free); + if (!add_certs) + goto export_end; } else { if (vret != X509_V_ERR_UNSPECIFIED) - BIO_printf(bio_err, "Error %s getting chain.\n", + BIO_printf(bio_err, "Error getting chain: %s\n", X509_verify_cert_error_string(vret)); - else - ERR_print_errors(bio_err); goto export_end; } } - /* Add any CA names */ + /* Add any extra certificates asked for */ + if (certfile != NULL) { + if (!load_certs(certfile, 0, &certs, passcerts, + "extra certificates from -certfile")) + goto export_end; + } + /* Add any CA names */ for (i = 0; i < sk_OPENSSL_STRING_num(canames); i++) { catmp = (unsigned char *)sk_OPENSSL_STRING_value(canames, i); X509_alias_set1(sk_X509_value(certs, i), catmp, -1); @@ -439,7 +645,7 @@ int pkcs12_main(int argc, char **argv) if (add_lmk && key != NULL) EVP_PKEY_add1_attr_by_NID(key, NID_LocalKeySet, 0, NULL, -1); - if (!noprompt) { + if (!noprompt && !(enc == NULL && maciter == -1)) { /* To avoid bit rot */ if (1) { #ifndef OPENSSL_NO_UI_CONSOLE @@ -458,21 +664,27 @@ int pkcs12_main(int argc, char **argv) if (!twopass) OPENSSL_strlcpy(macpass, pass, sizeof(macpass)); - p12 = PKCS12_create(cpass, name, key, ucert, certs, - key_pbe, cert_pbe, iter, -1, keytype); + p12 = PKCS12_create_ex(cpass, name, key, ee_cert, certs, + key_pbe, cert_pbe, iter, -1, keytype, + app_get0_libctx(), app_get0_propq()); - if (!p12) { - ERR_print_errors(bio_err); + if (p12 == NULL) { + BIO_printf(bio_err, "Error creating PKCS12 structure for %s\n", + outfile); goto export_end; } - if (macalg) { + if (macalg != NULL) { if (!opt_md(macalg, &macmd)) goto opthelp; } if (maciter != -1) - PKCS12_set_mac(p12, mpass, -1, NULL, 0, maciter, macmd); + if (!PKCS12_set_mac(p12, mpass, -1, NULL, 0, maciter, macmd)) { + BIO_printf(bio_err, "Error creating PKCS12 MAC; no PKCS12KDF support?\n"); + BIO_printf(bio_err, "Use -nomac if MAC not required and PKCS12KDF support not available.\n"); + goto export_end; + } assert(private); @@ -487,9 +699,12 @@ int pkcs12_main(int argc, char **argv) export_end: EVP_PKEY_free(key); + EVP_MD_free(macmd); sk_X509_pop_free(certs, X509_free); - X509_free(ucert); + sk_X509_pop_free(untrusted_certs, X509_free); + X509_free(ee_cert); + ERR_print_errors(bio_err); goto end; } @@ -501,7 +716,12 @@ int pkcs12_main(int argc, char **argv) if (out == NULL) goto end; - if ((p12 = d2i_PKCS12_bio(in, NULL)) == NULL) { + p12 = PKCS12_init_ex(NID_pkcs7_data, app_get0_libctx(), app_get0_propq()); + if (p12 == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if ((p12 = d2i_PKCS12_bio(in, &p12)) == NULL) { ERR_print_errors(bio_err); goto end; } @@ -544,6 +764,16 @@ int pkcs12_main(int argc, char **argv) tsalt != NULL ? ASN1_STRING_length(tsalt) : 0L); } if (macver) { + EVP_KDF *pkcs12kdf; + + pkcs12kdf = EVP_KDF_fetch(app_get0_libctx(), "PKCS12KDF", + app_get0_propq()); + if (pkcs12kdf == NULL) { + BIO_printf(bio_err, "Error verifying PKCS12 MAC; no PKCS12KDF support.\n"); + BIO_printf(bio_err, "Use -nomacver if MAC verification is not required.\n"); + goto end; + } + EVP_KDF_free(pkcs12kdf); /* If we enter empty password try no password first */ if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) { /* If mac and crypto pass the same set it to NULL too */ @@ -557,6 +787,14 @@ int pkcs12_main(int argc, char **argv) */ unsigned char *utmp; int utmplen; + unsigned long err = ERR_peek_error(); + + if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 + && ERR_GET_REASON(err) == PKCS12_R_MAC_ABSENT) { + BIO_printf(bio_err, "Warning: MAC is absent!\n"); + goto dump; + } + utmp = OPENSSL_asc2uni(mpass, -1, NULL, &utmplen); if (utmp == NULL) goto end; @@ -574,6 +812,7 @@ int pkcs12_main(int argc, char **argv) } } + dump: assert(private); if (!dump_certs_keys_p12(out, p12, cpass, -1, options, passout, enc)) { BIO_printf(bio_err, "Error outputting keys and certificates\n"); @@ -588,6 +827,7 @@ int pkcs12_main(int argc, char **argv) BIO_free_all(out); sk_OPENSSL_STRING_free(canames); OPENSSL_free(badpass); + OPENSSL_free(passcerts); OPENSSL_free(passin); OPENSSL_free(passout); return ret; @@ -725,6 +965,16 @@ int dump_certs_pkeys_bag(BIO *out, const PKCS12_SAFEBAG *bag, X509_free(x509); break; + case NID_secretBag: + if (options & INFO) + BIO_printf(bio_err, "Secret bag\n"); + print_attribs(out, attrs, "Bag Attributes"); + BIO_printf(bio_err, "Bag Type: "); + i2a_ASN1_OBJECT(bio_err, PKCS12_SAFEBAG_get0_bag_type(bag)); + BIO_printf(bio_err, "\nBag Value: "); + print_attribute(out, PKCS12_SAFEBAG_get0_bag_obj(bag)); + return 1; + case NID_safeContentsBag: if (options & INFO) BIO_printf(bio_err, "Safe Contents bag\n"); @@ -744,18 +994,19 @@ int dump_certs_pkeys_bag(BIO *out, const PKCS12_SAFEBAG *bag, /* Given a single certificate return a verified chain or NULL if error */ static int get_cert_chain(X509 *cert, X509_STORE *store, + STACK_OF(X509) *untrusted_certs, STACK_OF(X509) **chain) { X509_STORE_CTX *store_ctx = NULL; STACK_OF(X509) *chn = NULL; int i = 0; - store_ctx = X509_STORE_CTX_new(); + store_ctx = X509_STORE_CTX_new_ex(app_get0_libctx(), app_get0_propq()); if (store_ctx == NULL) { i = X509_V_ERR_UNSPECIFIED; goto end; } - if (!X509_STORE_CTX_init(store_ctx, store, cert, NULL)) { + if (!X509_STORE_CTX_init(store_ctx, store, cert, untrusted_certs)) { i = X509_V_ERR_UNSPECIFIED; goto end; } @@ -863,12 +1114,13 @@ static int alg_print(const X509_ALGOR *alg) int cert_load(BIO *in, STACK_OF(X509) *sk) { - int ret; + int ret = 0; X509 *cert; - ret = 0; + while ((cert = PEM_read_bio_X509(in, NULL, NULL, NULL))) { ret = 1; - sk_X509_push(sk, cert); + if (!sk_X509_push(sk, cert)) + return 0; } if (ret) ERR_clear_error(); @@ -889,6 +1141,11 @@ void print_attribute(BIO *out, const ASN1_TYPE *av) OPENSSL_free(value); break; + case V_ASN1_UTF8STRING: + BIO_printf(out, "%.*s\n", av->value.utf8string->length, + av->value.utf8string->data); + break; + case V_ASN1_OCTET_STRING: hex_prin(out, av->value.octet_string->data, av->value.octet_string->length); diff --git a/apps/pkcs7.c b/apps/pkcs7.c index c3e9f5c69260..ba11e8151ae9 100644 --- a/apps/pkcs7.c +++ b/apps/pkcs7.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -21,15 +21,24 @@ #include <openssl/pem.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_NOOUT, - OPT_TEXT, OPT_PRINT, OPT_PRINT_CERTS, OPT_ENGINE + OPT_TEXT, OPT_PRINT, OPT_PRINT_CERTS, OPT_ENGINE, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS pkcs7_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, + {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, + + OPT_SECTION("Output"), {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, {"out", OPT_OUT, '>', "Output file"}, {"noout", OPT_NOOUT, '-', "Don't output encoded data"}, @@ -37,21 +46,21 @@ const OPTIONS pkcs7_options[] = { {"print", OPT_PRINT, '-', "Print out all fields of the PKCS7 structure"}, {"print_certs", OPT_PRINT_CERTS, '-', "Print_certs print any certs or crl in the input"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + + OPT_PROV_OPTIONS, {NULL} }; int pkcs7_main(int argc, char **argv) { ENGINE *e = NULL; - PKCS7 *p7 = NULL; + PKCS7 *p7 = NULL, *p7i; BIO *in = NULL, *out = NULL; int informat = FORMAT_PEM, outformat = FORMAT_PEM; char *infile = NULL, *outfile = NULL, *prog; int i, print_certs = 0, text = 0, noout = 0, p7_print = 0, ret = 1; OPTION_CHOICE o; + OSSL_LIB_CTX *libctx = app_get0_libctx(); prog = opt_init(argc, argv, pkcs7_options); while ((o = opt_next()) != OPT_EOF) { @@ -94,8 +103,14 @@ int pkcs7_main(int argc, char **argv) case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; @@ -104,11 +119,18 @@ int pkcs7_main(int argc, char **argv) if (in == NULL) goto end; + p7 = PKCS7_new_ex(libctx, app_get0_propq()); + if (p7 == NULL) { + BIO_printf(bio_err, "unable to allocate PKCS7 object\n"); + ERR_print_errors(bio_err); + goto end; + } + if (informat == FORMAT_ASN1) - p7 = d2i_PKCS7_bio(in, NULL); + p7i = d2i_PKCS7_bio(in, &p7); else - p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); - if (p7 == NULL) { + p7i = PEM_read_bio_PKCS7(in, &p7, NULL, NULL); + if (p7i == NULL) { BIO_printf(bio_err, "unable to load PKCS7 object\n"); ERR_print_errors(bio_err); goto end; diff --git a/apps/pkcs8.c b/apps/pkcs8.c index 205536560ac1..6b09b909eb7a 100644 --- a/apps/pkcs8.c +++ b/apps/pkcs8.c @@ -1,7 +1,7 @@ /* - * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -18,7 +18,7 @@ #include <openssl/pkcs12.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, OPT_TOPK8, OPT_NOITER, OPT_NOCRYPT, #ifndef OPENSSL_NO_SCRYPT @@ -26,35 +26,44 @@ typedef enum OPTION_choice { #endif OPT_V2, OPT_V1, OPT_V2PRF, OPT_ITER, OPT_PASSIN, OPT_PASSOUT, OPT_TRADITIONAL, - OPT_R_ENUM + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS pkcs8_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format (DER or PEM)"}, - {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"}, - {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, - {"topk8", OPT_TOPK8, '-', "Output PKCS8 file"}, - {"noiter", OPT_NOITER, '-', "Use 1 as iteration count"}, - {"nocrypt", OPT_NOCRYPT, '-', "Use or expect unencrypted private key"}, - OPT_R_OPTIONS, - {"v2", OPT_V2, 's', "Use PKCS#5 v2.0 and cipher"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif {"v1", OPT_V1, 's', "Use PKCS#5 v1.5 and cipher"}, + {"v2", OPT_V2, 's', "Use PKCS#5 v2.0 and cipher"}, {"v2prf", OPT_V2PRF, 's', "Set the PRF algorithm to use with PKCS#5 v2.0"}, - {"iter", OPT_ITER, 'p', "Specify the iteration count"}, + + OPT_SECTION("Input"), + {"in", OPT_IN, '<', "Input file"}, + {"inform", OPT_INFORM, 'F', "Input format (DER or PEM)"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"nocrypt", OPT_NOCRYPT, '-', "Use or expect unencrypted private key"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"}, + {"topk8", OPT_TOPK8, '-', "Output PKCS8 file"}, {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, {"traditional", OPT_TRADITIONAL, '-', "use traditional format private key"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + {"iter", OPT_ITER, 'p', "Specify the iteration count"}, + {"noiter", OPT_NOITER, '-', "Use 1 as iteration count"}, + #ifndef OPENSSL_NO_SCRYPT + OPT_SECTION("Scrypt"), {"scrypt", OPT_SCRYPT, '-', "Use scrypt algorithm"}, {"scrypt_N", OPT_SCRYPT_N, 's', "Set scrypt N parameter"}, {"scrypt_r", OPT_SCRYPT_R, 's', "Set scrypt r parameter"}, {"scrypt_p", OPT_SCRYPT_P, 's', "Set scrypt p parameter"}, #endif + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, {NULL} }; @@ -65,8 +74,8 @@ int pkcs8_main(int argc, char **argv) EVP_PKEY *pkey = NULL; PKCS8_PRIV_KEY_INFO *p8inf = NULL; X509_SIG *p8 = NULL; - const EVP_CIPHER *cipher = NULL; - char *infile = NULL, *outfile = NULL; + EVP_CIPHER *cipher = NULL; + char *infile = NULL, *outfile = NULL, *ciphername = NULL; char *passinarg = NULL, *passoutarg = NULL, *prog; #ifndef OPENSSL_NO_UI_CONSOLE char pass[APP_PASS_LEN]; @@ -74,7 +83,7 @@ int pkcs8_main(int argc, char **argv) char *passin = NULL, *passout = NULL, *p8pass = NULL; OPTION_CHOICE o; int nocrypt = 0, ret = 1, iter = PKCS12_DEFAULT_ITER; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, topk8 = 0, pbe_nid = -1; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, topk8 = 0, pbe_nid = -1; int private = 0, traditional = 0; #ifndef OPENSSL_NO_SCRYPT long scrypt_N = 0, scrypt_r = 0, scrypt_p = 0; @@ -119,12 +128,15 @@ int pkcs8_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_TRADITIONAL: traditional = 1; break; case OPT_V2: - if (!opt_cipher(opt_arg(), &cipher)) - goto opthelp; + ciphername = opt_arg(); break; case OPT_V1: pbe_nid = OBJ_txt2nid(opt_arg()); @@ -142,11 +154,10 @@ int pkcs8_main(int argc, char **argv) goto opthelp; } if (cipher == NULL) - cipher = EVP_aes_256_cbc(); + cipher = (EVP_CIPHER *)EVP_aes_256_cbc(); break; case OPT_ITER: - if (!opt_int(opt_arg(), &iter)) - goto opthelp; + iter = opt_int_arg(); break; case OPT_PASSIN: passinarg = opt_arg(); @@ -163,7 +174,7 @@ int pkcs8_main(int argc, char **argv) scrypt_r = 8; scrypt_p = 1; if (cipher == NULL) - cipher = EVP_aes_256_cbc(); + cipher = (EVP_CIPHER *)EVP_aes_256_cbc(); break; case OPT_SCRYPT_N: if (!opt_long(opt_arg(), &scrypt_N) || scrypt_N <= 0) @@ -180,11 +191,20 @@ int pkcs8_main(int argc, char **argv) #endif } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; private = 1; + if (!app_RAND_load()) + goto end; + + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &cipher)) + goto opthelp; + } if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { BIO_printf(bio_err, "Error getting passwords\n"); @@ -192,9 +212,10 @@ int pkcs8_main(int argc, char **argv) } if ((pbe_nid == -1) && cipher == NULL) - cipher = EVP_aes_256_cbc(); + cipher = (EVP_CIPHER *)EVP_aes_256_cbc(); - in = bio_open_default(infile, 'r', informat); + in = bio_open_default(infile, 'r', + informat == FORMAT_UNDEF ? FORMAT_PEM : informat); if (in == NULL) goto end; out = bio_open_owner(outfile, outformat, private); @@ -278,7 +299,7 @@ int pkcs8_main(int argc, char **argv) } if (nocrypt) { - if (informat == FORMAT_PEM) { + if (informat == FORMAT_PEM || informat == FORMAT_UNDEF) { p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL); } else if (informat == FORMAT_ASN1) { p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL); @@ -287,7 +308,7 @@ int pkcs8_main(int argc, char **argv) goto end; } } else { - if (informat == FORMAT_PEM) { + if (informat == FORMAT_PEM || informat == FORMAT_UNDEF) { p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); } else if (informat == FORMAT_ASN1) { p8 = d2i_PKCS8_bio(in, NULL); @@ -349,6 +370,7 @@ int pkcs8_main(int argc, char **argv) X509_SIG_free(p8); PKCS8_PRIV_KEY_INFO_free(p8inf); EVP_PKEY_free(pkey); + EVP_CIPHER_free(cipher); release_engine(e); BIO_free_all(out); BIO_free(in); diff --git a/apps/pkey.c b/apps/pkey.c index 0dd5590bdc0b..196678533c1d 100644 --- a/apps/pkey.c +++ b/apps/pkey.c @@ -1,7 +1,7 @@ /* - * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -11,54 +11,77 @@ #include <string.h> #include "apps.h" #include "progs.h" +#include "ec_common.h" #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/evp.h> +#include <openssl/core_names.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB, - OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL, OPT_CHECK, OPT_PUB_CHECK + OPT_TEXT, OPT_NOOUT, OPT_CIPHER, OPT_TRADITIONAL, OPT_CHECK, OPT_PUB_CHECK, + OPT_EC_PARAM_ENC, OPT_EC_CONV_FORM, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS pkey_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'f', "Input format (DER or PEM)"}, - {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - {"in", OPT_IN, 's', "Input key"}, - {"out", OPT_OUT, '>', "Output file"}, - {"pubin", OPT_PUBIN, '-', - "Read public key from input (default is private key)"}, - {"pubout", OPT_PUBOUT, '-', "Output public key, not private"}, - {"text_pub", OPT_TEXT_PUB, '-', "Only output public key components"}, - {"text", OPT_TEXT, '-', "Output in plaintext as well"}, - {"noout", OPT_NOOUT, '-', "Don't output the key"}, - {"", OPT_MD, '-', "Any supported cipher"}, - {"traditional", OPT_TRADITIONAL, '-', - "Use traditional format for private keys"}, #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif + OPT_PROV_OPTIONS, + {"check", OPT_CHECK, '-', "Check key consistency"}, {"pubcheck", OPT_PUB_CHECK, '-', "Check public key consistency"}, + + OPT_SECTION("Input"), + {"in", OPT_IN, 's', "Input key"}, + {"inform", OPT_INFORM, 'f', + "Key input format (ENGINE, other values ignored)"}, + {"passin", OPT_PASSIN, 's', "Key input pass phrase source"}, + {"pubin", OPT_PUBIN, '-', + "Read only public components from key input"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file for encoded and/or text output"}, + {"outform", OPT_OUTFORM, 'F', "Output encoding format (DER or PEM)"}, + {"", OPT_CIPHER, '-', "Any supported cipher to be used for encryption"}, + {"passout", OPT_PASSOUT, 's', "Output PEM file pass phrase source"}, + {"traditional", OPT_TRADITIONAL, '-', + "Use traditional format for private key PEM output"}, + {"pubout", OPT_PUBOUT, '-', "Restrict encoded output to public components"}, + {"noout", OPT_NOOUT, '-', "Do not output the key in encoded form"}, + {"text", OPT_TEXT, '-', "Output key components in plaintext"}, + {"text_pub", OPT_TEXT_PUB, '-', + "Output only public key components in text form"}, + {"ec_conv_form", OPT_EC_CONV_FORM, 's', + "Specifies the EC point conversion form in the encoding"}, + {"ec_param_enc", OPT_EC_PARAM_ENC, 's', + "Specifies the way the EC parameters are encoded"}, + {NULL} }; int pkey_main(int argc, char **argv) { - BIO *in = NULL, *out = NULL; + BIO *out = NULL; ENGINE *e = NULL; EVP_PKEY *pkey = NULL; - const EVP_CIPHER *cipher = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; char *infile = NULL, *outfile = NULL, *passin = NULL, *passout = NULL; - char *passinarg = NULL, *passoutarg = NULL, *prog; + char *passinarg = NULL, *passoutarg = NULL, *ciphername = NULL, *prog; OPTION_CHOICE o; - int informat = FORMAT_PEM, outformat = FORMAT_PEM; - int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0, ret = 1; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM; + int pubin = 0, pubout = 0, text_pub = 0, text = 0, noout = 0, ret = 1; int private = 0, traditional = 0, check = 0, pub_check = 0; +#ifndef OPENSSL_NO_EC + char *asn1_encoding = NULL; + char *point_format = NULL; +#endif prog = opt_init(argc, argv, pkey_options); while ((o = opt_next()) != OPT_EOF) { @@ -96,13 +119,13 @@ int pkey_main(int argc, char **argv) outfile = opt_arg(); break; case OPT_PUBIN: - pubin = pubout = pubtext = 1; + pubin = pubout = 1; break; case OPT_PUBOUT: pubout = 1; break; case OPT_TEXT_PUB: - pubtext = text = 1; + text_pub = 1; break; case OPT_TEXT: text = 1; @@ -119,19 +142,69 @@ int pkey_main(int argc, char **argv) case OPT_PUB_CHECK: pub_check = 1; break; - case OPT_MD: - if (!opt_cipher(opt_unknown(), &cipher)) + case OPT_CIPHER: + ciphername = opt_unknown(); + break; + case OPT_EC_CONV_FORM: +#ifdef OPENSSL_NO_EC + goto opthelp; +#else + point_format = opt_arg(); + if (!opt_string(point_format, point_format_options)) goto opthelp; + break; +#endif + case OPT_EC_PARAM_ENC: +#ifdef OPENSSL_NO_EC + goto opthelp; +#else + asn1_encoding = opt_arg(); + if (!opt_string(asn1_encoding, asn1_encoding_options)) + goto opthelp; + break; +#endif + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; - private = !noout && !pubout ? 1 : 0; - if (text && !pubtext) - private = 1; + if (text && text_pub) + BIO_printf(bio_err, + "Warning: The -text option is ignored with -text_pub\n"); + if (traditional && (noout || outformat != FORMAT_PEM)) + BIO_printf(bio_err, + "Warning: The -traditional is ignored since there is no PEM output\n"); + + /* -pubout and -text is the same as -text_pub */ + if (!text_pub && pubout && text) { + text = 0; + text_pub = 1; + } + + private = (!noout && !pubout) || (text && !text_pub); + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &cipher)) + goto opthelp; + } + if (cipher == NULL) { + if (passoutarg != NULL) + BIO_printf(bio_err, + "Warning: The -passout option is ignored without a cipher option\n"); + } else { + if (noout || outformat != FORMAT_PEM) { + BIO_printf(bio_err, + "Error: Cipher options are supported only for PEM output\n"); + goto end; + } + } if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { BIO_printf(bio_err, "Error getting passwords\n"); goto end; @@ -148,9 +221,28 @@ int pkey_main(int argc, char **argv) if (pkey == NULL) goto end; +#ifndef OPENSSL_NO_EC + if (asn1_encoding != NULL || point_format != NULL) { + OSSL_PARAM params[3], *p = params; + + if (!EVP_PKEY_is_a(pkey, "EC")) + goto end; + + if (asn1_encoding != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, + asn1_encoding, 0); + if (point_format != NULL) + *p++ = OSSL_PARAM_construct_utf8_string( + OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + point_format, 0); + *p = OSSL_PARAM_construct_end(); + if (EVP_PKEY_set_params(pkey, params) <= 0) + goto end; + } +#endif + if (check || pub_check) { int r; - EVP_PKEY_CTX *ctx; ctx = EVP_PKEY_CTX_new(pkey, e); if (ctx == NULL) { @@ -158,7 +250,7 @@ int pkey_main(int argc, char **argv) goto end; } - if (check) + if (check && !pubin) r = EVP_PKEY_check(ctx); else r = EVP_PKEY_public_check(ctx); @@ -170,17 +262,10 @@ int pkey_main(int argc, char **argv) * Note: at least for RSA keys if this function returns * -1, there will be no error reasons. */ - unsigned long err; - - BIO_printf(out, "Key is invalid\n"); - - while ((err = ERR_peek_error()) != 0) { - BIO_printf(out, "Detailed error: %s\n", - ERR_reason_error_string(err)); - ERR_get_error(); /* remove err from error stack */ - } + BIO_printf(bio_err, "Key is invalid\n"); + ERR_print_errors(bio_err); + goto end; } - EVP_PKEY_CTX_free(ctx); } if (!noout) { @@ -202,6 +287,11 @@ int pkey_main(int argc, char **argv) } } } else if (outformat == FORMAT_ASN1) { + if (text || text_pub) { + BIO_printf(bio_err, + "Error: Text output cannot be combined with DER output\n"); + goto end; + } if (pubout) { if (!i2d_PUBKEY_bio(out, pkey)) goto end; @@ -216,15 +306,13 @@ int pkey_main(int argc, char **argv) } } - if (text) { - if (pubtext) { - if (EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) - goto end; - } else { - assert(private); - if (EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0) - goto end; - } + if (text_pub) { + if (EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) + goto end; + } else if (text) { + assert(private); + if (EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0) + goto end; } ret = 0; @@ -232,10 +320,11 @@ int pkey_main(int argc, char **argv) end: if (ret != 0) ERR_print_errors(bio_err); + EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); + EVP_CIPHER_free(cipher); release_engine(e); BIO_free_all(out); - BIO_free(in); OPENSSL_free(passin); OPENSSL_free(passout); diff --git a/apps/pkeyparam.c b/apps/pkeyparam.c index 41c3f532b345..b02882ccc296 100644 --- a/apps/pkeyparam.c +++ b/apps/pkeyparam.c @@ -1,7 +1,7 @@ /* - * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -9,6 +9,7 @@ #include <stdio.h> #include <string.h> +#include <stdlib.h> #include "apps.h" #include "progs.h" #include <openssl/pem.h> @@ -16,21 +17,29 @@ #include <openssl/evp.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_IN, OPT_OUT, OPT_TEXT, OPT_NOOUT, - OPT_ENGINE, OPT_CHECK + OPT_ENGINE, OPT_CHECK, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS pkeyparam_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, - {"text", OPT_TEXT, '-', "Print parameters as text"}, - {"noout", OPT_NOOUT, '-', "Don't output encoded parameters"}, #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif {"check", OPT_CHECK, '-', "Check key param consistency"}, + + OPT_SECTION("Input"), + {"in", OPT_IN, '<', "Input file"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"text", OPT_TEXT, '-', "Print parameters as text"}, + {"noout", OPT_NOOUT, '-', "Don't output encoded parameters"}, + + OPT_PROV_OPTIONS, {NULL} }; @@ -39,7 +48,8 @@ int pkeyparam_main(int argc, char **argv) ENGINE *e = NULL; BIO *in = NULL, *out = NULL; EVP_PKEY *pkey = NULL; - int text = 0, noout = 0, ret = 1, check = 0; + EVP_PKEY_CTX *ctx = NULL; + int text = 0, noout = 0, ret = EXIT_FAILURE, check = 0, r; OPTION_CHOICE o; char *infile = NULL, *outfile = NULL, *prog; @@ -73,8 +83,14 @@ int pkeyparam_main(int argc, char **argv) case OPT_CHECK: check = 1; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; @@ -85,7 +101,8 @@ int pkeyparam_main(int argc, char **argv) out = bio_open_default(outfile, 'w', FORMAT_PEM); if (out == NULL) goto end; - pkey = PEM_read_bio_Parameters(in, NULL); + pkey = PEM_read_bio_Parameters_ex(in, NULL, app_get0_libctx(), + app_get0_propq()); if (pkey == NULL) { BIO_printf(bio_err, "Error reading parameters\n"); ERR_print_errors(bio_err); @@ -93,10 +110,11 @@ int pkeyparam_main(int argc, char **argv) } if (check) { - int r; - EVP_PKEY_CTX *ctx; - - ctx = EVP_PKEY_CTX_new(pkey, e); + if (e == NULL) + ctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), pkey, + app_get0_propq()); + else + ctx = EVP_PKEY_CTX_new(pkey, e); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; @@ -111,17 +129,10 @@ int pkeyparam_main(int argc, char **argv) * Note: at least for RSA keys if this function returns * -1, there will be no error reasons. */ - unsigned long err; - - BIO_printf(out, "Parameters are invalid\n"); - - while ((err = ERR_peek_error()) != 0) { - BIO_printf(out, "Detailed error: %s\n", - ERR_reason_error_string(err)); - ERR_get_error(); /* remove err from error stack */ - } + BIO_printf(bio_err, "Parameters are invalid\n"); + ERR_print_errors(bio_err); + goto end; } - EVP_PKEY_CTX_free(ctx); } if (!noout) @@ -130,9 +141,10 @@ int pkeyparam_main(int argc, char **argv) if (text) EVP_PKEY_print_params(out, pkey, 0, NULL); - ret = 0; + ret = EXIT_SUCCESS; end: + EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); release_engine(e); BIO_free_all(out); diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c index 831e14dab4b3..518a74166153 100644 --- a/apps/pkeyutl.c +++ b/apps/pkeyutl.c @@ -1,7 +1,7 @@ /* - * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -13,6 +13,7 @@ #include <openssl/err.h> #include <openssl/pem.h> #include <openssl/evp.h> +#include <sys/stat.h> #define KEY_NONE 0 #define KEY_PRIVKEY 1 @@ -22,7 +23,9 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, const char *keyfile, int keyform, int key_type, char *passinarg, int pkey_op, ENGINE *e, - const int impl); + const int impl, int rawin, EVP_PKEY **ppkey, + EVP_MD_CTX *mctx, const char *digestname, + OSSL_LIB_CTX *libctx, const char *propq); static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, ENGINE *e); @@ -31,69 +34,100 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, unsigned char *out, size_t *poutlen, const unsigned char *in, size_t inlen); +static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, + EVP_PKEY *pkey, BIO *in, + int filesize, unsigned char *sig, int siglen, + unsigned char **out, size_t *poutlen); + typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_ENGINE, OPT_ENGINE_IMPL, OPT_IN, OPT_OUT, OPT_PUBIN, OPT_CERTIN, OPT_ASN1PARSE, OPT_HEXDUMP, OPT_SIGN, OPT_VERIFY, OPT_VERIFYRECOVER, OPT_REV, OPT_ENCRYPT, OPT_DECRYPT, OPT_DERIVE, OPT_SIGFILE, OPT_INKEY, OPT_PEERKEY, OPT_PASSIN, - OPT_PEERFORM, OPT_KEYFORM, OPT_PKEYOPT, OPT_KDF, OPT_KDFLEN, - OPT_R_ENUM + OPT_PEERFORM, OPT_KEYFORM, OPT_PKEYOPT, OPT_PKEYOPT_PASSIN, OPT_KDF, + OPT_KDFLEN, OPT_R_ENUM, OPT_PROV_ENUM, + OPT_CONFIG, + OPT_RAWIN, OPT_DIGEST } OPTION_CHOICE; const OPTIONS pkeyutl_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, + {"engine_impl", OPT_ENGINE_IMPL, '-', + "Also use engine given by -engine for crypto operations"}, +#endif + {"sign", OPT_SIGN, '-', "Sign input data with private key"}, + {"verify", OPT_VERIFY, '-', "Verify with public key"}, + {"encrypt", OPT_ENCRYPT, '-', "Encrypt input data with public key"}, + {"decrypt", OPT_DECRYPT, '-', "Decrypt input data with private key"}, + {"derive", OPT_DERIVE, '-', "Derive shared secret"}, + OPT_CONFIG_OPTION, + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file - default stdin"}, - {"out", OPT_OUT, '>', "Output file - default stdout"}, + {"rawin", OPT_RAWIN, '-', "Indicate the input data is in raw form"}, {"pubin", OPT_PUBIN, '-', "Input is a public key"}, + {"inkey", OPT_INKEY, 's', "Input private key file"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"peerkey", OPT_PEERKEY, 's', "Peer key file used in key derivation"}, + {"peerform", OPT_PEERFORM, 'E', "Peer key format (DER/PEM/P12/ENGINE)"}, {"certin", OPT_CERTIN, '-', "Input is a cert with a public key"}, + {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, + {"sigfile", OPT_SIGFILE, '<', "Signature file (verify operation only)"}, + {"keyform", OPT_KEYFORM, 'E', "Private key format (ENGINE, other values ignored)"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file - default stdout"}, {"asn1parse", OPT_ASN1PARSE, '-', "asn1parse the output data"}, {"hexdump", OPT_HEXDUMP, '-', "Hex dump output"}, - {"sign", OPT_SIGN, '-', "Sign input data with private key"}, - {"verify", OPT_VERIFY, '-', "Verify with public key"}, {"verifyrecover", OPT_VERIFYRECOVER, '-', "Verify with public key, recover original data"}, - {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, - {"encrypt", OPT_ENCRYPT, '-', "Encrypt input data with public key"}, - {"decrypt", OPT_DECRYPT, '-', "Decrypt input data with private key"}, - {"derive", OPT_DERIVE, '-', "Derive shared secret"}, + + OPT_SECTION("Signing/Derivation"), + {"digest", OPT_DIGEST, 's', + "Specify the digest algorithm when signing the raw input data"}, + {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, + {"pkeyopt_passin", OPT_PKEYOPT_PASSIN, 's', + "Public key option that is read as a passphrase argument opt:passphrase"}, {"kdf", OPT_KDF, 's', "Use KDF algorithm"}, {"kdflen", OPT_KDFLEN, 'p', "KDF algorithm output length"}, - {"sigfile", OPT_SIGFILE, '<', "Signature file (verify operation only)"}, - {"inkey", OPT_INKEY, 's', "Input private key file"}, - {"peerkey", OPT_PEERKEY, 's', "Peer key file used in key derivation"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"peerform", OPT_PEERFORM, 'E', "Peer key format - default PEM"}, - {"keyform", OPT_KEYFORM, 'E', "Private key format - default PEM"}, - {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, - {"engine_impl", OPT_ENGINE_IMPL, '-', - "Also use engine given by -engine for crypto operations"}, -#endif + OPT_PROV_OPTIONS, {NULL} }; int pkeyutl_main(int argc, char **argv) { + CONF *conf = NULL; BIO *in = NULL, *out = NULL; ENGINE *e = NULL; EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; char *infile = NULL, *outfile = NULL, *sigfile = NULL, *passinarg = NULL; char hexdump = 0, asn1parse = 0, rev = 0, *prog; unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL; OPTION_CHOICE o; - int buf_inlen = 0, siglen = -1, keyform = FORMAT_PEM, peerform = FORMAT_PEM; + int buf_inlen = 0, siglen = -1; + int keyform = FORMAT_UNDEF, peerform = FORMAT_UNDEF; int keysize = -1, pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY; int engine_impl = 0; int ret = 1, rv = -1; size_t buf_outlen; const char *inkey = NULL; const char *peerkey = NULL; - const char *kdfalg = NULL; + const char *kdfalg = NULL, *digestname = NULL; int kdflen = 0; STACK_OF(OPENSSL_STRING) *pkeyopts = NULL; + STACK_OF(OPENSSL_STRING) *pkeyopts_passin = NULL; + int rawin = 0; + EVP_MD_CTX *mctx = NULL; + EVP_MD *md = NULL; + int filesize = -1; + OSSL_LIB_CTX *libctx = app_get0_libctx(); prog = opt_init(argc, argv, pkeyutl_options); while ((o = opt_next()) != OPT_EOF) { @@ -129,17 +163,26 @@ int pkeyutl_main(int argc, char **argv) passinarg = opt_arg(); break; case OPT_PEERFORM: - if (!opt_format(opt_arg(), OPT_FMT_PDE, &peerform)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &peerform)) goto opthelp; break; case OPT_KEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PDE, &keyform)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) goto opthelp; break; case OPT_R_CASES: if (!opt_rand(o)) goto end; break; + case OPT_CONFIG: + conf = app_load_config_modules(opt_arg()); + if (conf == NULL) + goto end; + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; @@ -192,12 +235,51 @@ int pkeyutl_main(int argc, char **argv) goto end; } break; + case OPT_PKEYOPT_PASSIN: + if ((pkeyopts_passin == NULL && + (pkeyopts_passin = sk_OPENSSL_STRING_new_null()) == NULL) || + sk_OPENSSL_STRING_push(pkeyopts_passin, opt_arg()) == 0) { + BIO_puts(bio_err, "out of memory\n"); + goto end; + } + break; + case OPT_RAWIN: + rawin = 1; + break; + case OPT_DIGEST: + digestname = opt_arg(); + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (!app_RAND_load()) + goto end; + + if (rawin && pkey_op != EVP_PKEY_OP_SIGN && pkey_op != EVP_PKEY_OP_VERIFY) { + BIO_printf(bio_err, + "%s: -rawin can only be used with -sign or -verify\n", + prog); + goto opthelp; + } + + if (digestname != NULL && !rawin) { + BIO_printf(bio_err, + "%s: -digest can only be used with -rawin\n", + prog); + goto opthelp; + } + + if (rawin && rev) { + BIO_printf(bio_err, "%s: -rev cannot be used with raw input\n", + prog); + goto opthelp; + } + if (kdfalg != NULL) { if (kdflen == 0) { BIO_printf(bio_err, @@ -213,16 +295,22 @@ int pkeyutl_main(int argc, char **argv) "%s: no peer key given (-peerkey parameter).\n", prog); goto opthelp; } + + if (rawin) { + if ((mctx = EVP_MD_CTX_new()) == NULL) { + BIO_printf(bio_err, "Error: out of memory\n"); + goto end; + } + } ctx = init_ctx(kdfalg, &keysize, inkey, keyform, key_type, - passinarg, pkey_op, e, engine_impl); + passinarg, pkey_op, e, engine_impl, rawin, &pkey, + mctx, digestname, libctx, app_get0_propq()); if (ctx == NULL) { BIO_printf(bio_err, "%s: Error initializing context\n", prog); - ERR_print_errors(bio_err); goto end; } if (peerkey != NULL && !setup_peer(ctx, peerform, peerkey, e)) { BIO_printf(bio_err, "%s: Error setting up peer key\n", prog); - ERR_print_errors(bio_err); goto end; } if (pkeyopts != NULL) { @@ -235,11 +323,58 @@ int pkeyutl_main(int argc, char **argv) if (pkey_ctrl_string(ctx, opt) <= 0) { BIO_printf(bio_err, "%s: Can't set parameter \"%s\":\n", prog, opt); - ERR_print_errors(bio_err); goto end; } } } + if (pkeyopts_passin != NULL) { + int num = sk_OPENSSL_STRING_num(pkeyopts_passin); + int i; + + for (i = 0; i < num; i++) { + char *opt = sk_OPENSSL_STRING_value(pkeyopts_passin, i); + char *passin = strchr(opt, ':'); + char *passwd; + + if (passin == NULL) { + /* Get password interactively */ + char passwd_buf[4096]; + int r; + + BIO_snprintf(passwd_buf, sizeof(passwd_buf), "Enter %s: ", opt); + r = EVP_read_pw_string(passwd_buf, sizeof(passwd_buf) - 1, + passwd_buf, 0); + if (r < 0) { + if (r == -2) + BIO_puts(bio_err, "user abort\n"); + else + BIO_puts(bio_err, "entry failed\n"); + goto end; + } + passwd = OPENSSL_strdup(passwd_buf); + if (passwd == NULL) { + BIO_puts(bio_err, "out of memory\n"); + goto end; + } + } else { + /* Get password as a passin argument: First split option name + * and passphrase argument into two strings */ + *passin = 0; + passin++; + if (app_passwd(passin, NULL, &passwd, NULL) == 0) { + BIO_printf(bio_err, "failed to get '%s'\n", opt); + goto end; + } + } + + if (EVP_PKEY_CTX_ctrl_str(ctx, opt, passwd) <= 0) { + BIO_printf(bio_err, "%s: Can't set parameter \"%s\":\n", + prog, opt); + goto end; + } + OPENSSL_free(passwd); + } + } if (sigfile != NULL && (pkey_op != EVP_PKEY_OP_VERIFY)) { BIO_printf(bio_err, @@ -255,6 +390,12 @@ int pkeyutl_main(int argc, char **argv) if (pkey_op != EVP_PKEY_OP_DERIVE) { in = bio_open_default(infile, 'r', FORMAT_BINARY); + if (infile != NULL) { + struct stat st; + + if (stat(infile, &st) == 0 && st.st_size <= INT_MAX) + filesize = (int)st.st_size; + } if (in == NULL) goto end; } @@ -277,7 +418,8 @@ int pkeyutl_main(int argc, char **argv) } } - if (in != NULL) { + /* Raw input data is handled elsewhere */ + if (in != NULL && !rawin) { /* Read the input data */ buf_inlen = bio_to_mem(&buf_in, keysize * 10, in); if (buf_inlen < 0) { @@ -296,8 +438,9 @@ int pkeyutl_main(int argc, char **argv) } } - /* Sanity check the input */ - if (buf_inlen > EVP_MAX_MD_SIZE + /* Sanity check the input if the input is not raw */ + if (!rawin + && buf_inlen > EVP_MAX_MD_SIZE && (pkey_op == EVP_PKEY_OP_SIGN || pkey_op == EVP_PKEY_OP_VERIFY)) { BIO_printf(bio_err, @@ -306,8 +449,13 @@ int pkeyutl_main(int argc, char **argv) } if (pkey_op == EVP_PKEY_OP_VERIFY) { - rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen, - buf_in, (size_t)buf_inlen); + if (rawin) { + rv = do_raw_keyop(pkey_op, mctx, pkey, in, filesize, sig, siglen, + NULL, 0); + } else { + rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen, + buf_in, (size_t)buf_inlen); + } if (rv == 1) { BIO_puts(out, "Signature Verified Successfully\n"); ret = 0; @@ -316,18 +464,24 @@ int pkeyutl_main(int argc, char **argv) } goto end; } - if (kdflen != 0) { - buf_outlen = kdflen; - rv = 1; + if (rawin) { + /* rawin allocates the buffer in do_raw_keyop() */ + rv = do_raw_keyop(pkey_op, mctx, pkey, in, filesize, NULL, 0, + &buf_out, (size_t *)&buf_outlen); } else { - rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, - buf_in, (size_t)buf_inlen); - } - if (rv > 0 && buf_outlen != 0) { - buf_out = app_malloc(buf_outlen, "buffer output"); - rv = do_keyop(ctx, pkey_op, - buf_out, (size_t *)&buf_outlen, - buf_in, (size_t)buf_inlen); + if (kdflen != 0) { + buf_outlen = kdflen; + rv = 1; + } else { + rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, + buf_in, (size_t)buf_inlen); + } + if (rv > 0 && buf_outlen != 0) { + buf_out = app_malloc(buf_outlen, "buffer output"); + rv = do_keyop(ctx, pkey_op, + buf_out, (size_t *)&buf_outlen, + buf_in, (size_t)buf_inlen); + } } if (rv <= 0) { if (pkey_op != EVP_PKEY_OP_DERIVE) { @@ -335,14 +489,13 @@ int pkeyutl_main(int argc, char **argv) } else { BIO_puts(bio_err, "Key derivation failed\n"); } - ERR_print_errors(bio_err); goto end; } ret = 0; if (asn1parse) { if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1)) - ERR_print_errors(bio_err); + ERR_print_errors(bio_err); /* but still return success */ } else if (hexdump) { BIO_dump(out, (char *)buf_out, buf_outlen); } else { @@ -350,7 +503,11 @@ int pkeyutl_main(int argc, char **argv) } end: + if (ret != 0) + ERR_print_errors(bio_err); + EVP_MD_CTX_free(mctx); EVP_PKEY_CTX_free(ctx); + EVP_MD_free(md); release_engine(e); BIO_free(in); BIO_free_all(out); @@ -358,13 +515,17 @@ int pkeyutl_main(int argc, char **argv) OPENSSL_free(buf_out); OPENSSL_free(sig); sk_OPENSSL_STRING_free(pkeyopts); + sk_OPENSSL_STRING_free(pkeyopts_passin); + NCONF_free(conf); return ret; } static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, const char *keyfile, int keyform, int key_type, char *passinarg, int pkey_op, ENGINE *e, - const int engine_impl) + const int engine_impl, int rawin, + EVP_PKEY **ppkey, EVP_MD_CTX *mctx, const char *digestname, + OSSL_LIB_CTX *libctx, const char *propq) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; @@ -372,6 +533,7 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, char *passin = NULL; int rv = -1; X509 *x; + if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) || (pkey_op == EVP_PKEY_OP_DERIVE)) && (key_type != KEY_PRIVKEY && kdfalg == NULL)) { @@ -384,11 +546,11 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, } switch (key_type) { case KEY_PRIVKEY: - pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); + pkey = load_key(keyfile, keyform, 0, passin, e, "private key"); break; case KEY_PUBKEY: - pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "Public Key"); + pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "public key"); break; case KEY_CERT: @@ -420,42 +582,68 @@ static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, goto end; } } - ctx = EVP_PKEY_CTX_new_id(kdfnid, impl); + if (impl != NULL) + ctx = EVP_PKEY_CTX_new_id(kdfnid, impl); + else + ctx = EVP_PKEY_CTX_new_from_name(libctx, kdfalg, propq); } else { if (pkey == NULL) goto end; - *pkeysize = EVP_PKEY_size(pkey); - ctx = EVP_PKEY_CTX_new(pkey, impl); + + *pkeysize = EVP_PKEY_get_size(pkey); + if (impl != NULL) + ctx = EVP_PKEY_CTX_new(pkey, impl); + else + ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); + if (ppkey != NULL) + *ppkey = pkey; EVP_PKEY_free(pkey); } if (ctx == NULL) goto end; - switch (pkey_op) { - case EVP_PKEY_OP_SIGN: - rv = EVP_PKEY_sign_init(ctx); - break; + if (rawin) { + EVP_MD_CTX_set_pkey_ctx(mctx, ctx); - case EVP_PKEY_OP_VERIFY: - rv = EVP_PKEY_verify_init(ctx); - break; + switch (pkey_op) { + case EVP_PKEY_OP_SIGN: + rv = EVP_DigestSignInit_ex(mctx, NULL, digestname, libctx, propq, + pkey, NULL); + break; - case EVP_PKEY_OP_VERIFYRECOVER: - rv = EVP_PKEY_verify_recover_init(ctx); - break; + case EVP_PKEY_OP_VERIFY: + rv = EVP_DigestVerifyInit_ex(mctx, NULL, digestname, libctx, propq, + pkey, NULL); + break; + } - case EVP_PKEY_OP_ENCRYPT: - rv = EVP_PKEY_encrypt_init(ctx); - break; + } else { + switch (pkey_op) { + case EVP_PKEY_OP_SIGN: + rv = EVP_PKEY_sign_init(ctx); + break; - case EVP_PKEY_OP_DECRYPT: - rv = EVP_PKEY_decrypt_init(ctx); - break; + case EVP_PKEY_OP_VERIFY: + rv = EVP_PKEY_verify_init(ctx); + break; - case EVP_PKEY_OP_DERIVE: - rv = EVP_PKEY_derive_init(ctx); - break; + case EVP_PKEY_OP_VERIFYRECOVER: + rv = EVP_PKEY_verify_recover_init(ctx); + break; + + case EVP_PKEY_OP_ENCRYPT: + rv = EVP_PKEY_encrypt_init(ctx); + break; + + case EVP_PKEY_OP_DECRYPT: + rv = EVP_PKEY_decrypt_init(ctx); + break; + + case EVP_PKEY_OP_DERIVE: + rv = EVP_PKEY_derive_init(ctx); + break; + } } if (rv <= 0) { @@ -478,18 +666,15 @@ static int setup_peer(EVP_PKEY_CTX *ctx, int peerform, const char *file, if (peerform == FORMAT_ENGINE) engine = e; - peer = load_pubkey(file, peerform, 0, NULL, engine, "Peer Key"); + peer = load_pubkey(file, peerform, 0, NULL, engine, "peer key"); if (peer == NULL) { BIO_printf(bio_err, "Error reading peer key %s\n", file); - ERR_print_errors(bio_err); return 0; } - ret = EVP_PKEY_derive_set_peer(ctx, peer); + ret = EVP_PKEY_derive_set_peer(ctx, peer) > 0; EVP_PKEY_free(peer); - if (ret <= 0) - ERR_print_errors(bio_err); return ret; } @@ -522,3 +707,95 @@ static int do_keyop(EVP_PKEY_CTX *ctx, int pkey_op, } return rv; } + +#define TBUF_MAXSIZE 2048 + +static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, + EVP_PKEY *pkey, BIO *in, + int filesize, unsigned char *sig, int siglen, + unsigned char **out, size_t *poutlen) +{ + int rv = 0; + unsigned char tbuf[TBUF_MAXSIZE]; + unsigned char *mbuf = NULL; + int buf_len = 0; + + /* Some algorithms only support oneshot digests */ + if (EVP_PKEY_get_id(pkey) == EVP_PKEY_ED25519 + || EVP_PKEY_get_id(pkey) == EVP_PKEY_ED448) { + if (filesize < 0) { + BIO_printf(bio_err, + "Error: unable to determine file size for oneshot operation\n"); + goto end; + } + mbuf = app_malloc(filesize, "oneshot sign/verify buffer"); + switch(pkey_op) { + case EVP_PKEY_OP_VERIFY: + buf_len = BIO_read(in, mbuf, filesize); + if (buf_len != filesize) { + BIO_printf(bio_err, "Error reading raw input data\n"); + goto end; + } + rv = EVP_DigestVerify(mctx, sig, (size_t)siglen, mbuf, buf_len); + break; + case EVP_PKEY_OP_SIGN: + buf_len = BIO_read(in, mbuf, filesize); + if (buf_len != filesize) { + BIO_printf(bio_err, "Error reading raw input data\n"); + goto end; + } + rv = EVP_DigestSign(mctx, NULL, poutlen, mbuf, buf_len); + if (rv == 1 && out != NULL) { + *out = app_malloc(*poutlen, "buffer output"); + rv = EVP_DigestSign(mctx, *out, poutlen, mbuf, buf_len); + } + break; + } + goto end; + } + + switch(pkey_op) { + case EVP_PKEY_OP_VERIFY: + for (;;) { + buf_len = BIO_read(in, tbuf, TBUF_MAXSIZE); + if (buf_len == 0) + break; + if (buf_len < 0) { + BIO_printf(bio_err, "Error reading raw input data\n"); + goto end; + } + rv = EVP_DigestVerifyUpdate(mctx, tbuf, (size_t)buf_len); + if (rv != 1) { + BIO_printf(bio_err, "Error verifying raw input data\n"); + goto end; + } + } + rv = EVP_DigestVerifyFinal(mctx, sig, (size_t)siglen); + break; + case EVP_PKEY_OP_SIGN: + for (;;) { + buf_len = BIO_read(in, tbuf, TBUF_MAXSIZE); + if (buf_len == 0) + break; + if (buf_len < 0) { + BIO_printf(bio_err, "Error reading raw input data\n"); + goto end; + } + rv = EVP_DigestSignUpdate(mctx, tbuf, (size_t)buf_len); + if (rv != 1) { + BIO_printf(bio_err, "Error signing raw input data\n"); + goto end; + } + } + rv = EVP_DigestSignFinal(mctx, NULL, poutlen); + if (rv == 1 && out != NULL) { + *out = app_malloc(*poutlen, "buffer output"); + rv = EVP_DigestSignFinal(mctx, *out, poutlen); + } + break; + } + + end: + OPENSSL_free(mbuf); + return rv; +} diff --git a/apps/prime.c b/apps/prime.c index 694479764696..e269493d5cd7 100644 --- a/apps/prime.c +++ b/apps/prime.c @@ -1,7 +1,7 @@ /* - * Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,28 +14,36 @@ #include <openssl/bn.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_HEX, OPT_GENERATE, OPT_BITS, OPT_SAFE, OPT_CHECKS + OPT_COMMON, + OPT_HEX, OPT_GENERATE, OPT_BITS, OPT_SAFE, OPT_CHECKS, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS prime_options[] = { {OPT_HELP_STR, 1, '-', "Usage: %s [options] [number...]\n"}, - {OPT_HELP_STR, 1, '-', - " number Number to check for primality\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"bits", OPT_BITS, 'p', "Size of number in bits"}, + {"checks", OPT_CHECKS, 'p', "Number of checks"}, + + OPT_SECTION("Output"), {"hex", OPT_HEX, '-', "Hex output"}, {"generate", OPT_GENERATE, '-', "Generate a prime"}, - {"bits", OPT_BITS, 'p', "Size of number in bits"}, {"safe", OPT_SAFE, '-', "When used with -generate, generate a safe prime"}, - {"checks", OPT_CHECKS, 'p', "Number of checks"}, + + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"number", 0, 0, "Number(s) to check for primality if not generating"}, {NULL} }; int prime_main(int argc, char **argv) { BIGNUM *bn = NULL; - int hex = 0, checks = 20, generate = 0, bits = 0, safe = 0, ret = 1; + int hex = 0, generate = 0, bits = 0, safe = 0, ret = 1; char *prog; OPTION_CHOICE o; @@ -64,20 +72,23 @@ opthelp: safe = 1; break; case OPT_CHECKS: - checks = atoi(opt_arg()); + /* ignore parameter and argument */ + opt_arg(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; break; } } + + /* Optional arguments are numbers to check. */ argc = opt_num_rest(); argv = opt_rest(); - if (generate) { - if (argc != 0) { - BIO_printf(bio_err, "Extra arguments given.\n"); + if (argc != 0) goto opthelp; - } } else if (argc == 0) { - BIO_printf(bio_err, "%s: No prime specified\n", prog); goto opthelp; } @@ -121,7 +132,7 @@ opthelp: BN_print(bio_out, bn); BIO_printf(bio_out, " (%s) %s prime\n", argv[0], - BN_is_prime_ex(bn, checks, NULL, NULL) + BN_check_prime(bn, NULL, NULL) ? "is" : "is not"); } } diff --git a/apps/progs.pl b/apps/progs.pl index 57671405dda0..29f9be13ca08 100644 --- a/apps/progs.pl +++ b/apps/progs.pl @@ -1,7 +1,7 @@ #! /usr/bin/env perl -# Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. # -# Licensed under the OpenSSL license (the "License"). You may not use +# 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 @@ -14,17 +14,22 @@ use warnings; use lib '.'; use configdata qw/@disablables %unified_info/; +my $opt = shift @ARGV; +die "Unrecognised option, must be -C or -H\n" + unless ($opt eq '-H' || $opt eq '-C'); + my %commands = (); my $cmdre = qr/^\s*int\s+([a-z_][a-z0-9_]*)_main\(\s*int\s+argc\s*,/; my $apps_openssl = shift @ARGV; -my $YEAR = [localtime()]->[5] + 1900; +my $YEAR = [gmtime($ENV{SOURCE_DATE_EPOCH} || time())]->[5] + 1900; # because the program apps/openssl has object files as sources, and # they then have the corresponding C files as source, we need to chain # the lookups in %unified_info my @openssl_source = map { @{$unified_info{sources}->{$_}} } - grep { /\.o$/ } + grep { /\.o$/ + && !$unified_info{attributes}->{sources}->{$apps_openssl}->{$_}->{nocheck} } @{$unified_info{sources}->{$apps_openssl}}; foreach my $filename (@openssl_source) { @@ -38,144 +43,178 @@ foreach my $filename (@openssl_source) { @ARGV = sort keys %commands; -print <<"EOF"; +if ($opt eq '-H') { + print <<"EOF"; /* * WARNING: do not edit! * Generated by apps/progs.pl * * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 */ -typedef enum FUNC_TYPE { - FT_none, FT_general, FT_md, FT_cipher, FT_pkey, - FT_md_alg, FT_cipher_alg -} FUNC_TYPE; - -typedef struct function_st { - FUNC_TYPE type; - const char *name; - int (*func)(int argc, char *argv[]); - const OPTIONS *help; -} FUNCTION; - -DEFINE_LHASH_OF(FUNCTION); +#include "function.h" EOF -foreach (@ARGV) { - printf "extern int %s_main(int argc, char *argv[]);\n", $_; -} -print "\n"; + foreach (@ARGV) { + printf "extern int %s_main(int argc, char *argv[]);\n", $_; + } + print "\n"; -foreach (@ARGV) { - printf "extern const OPTIONS %s_options[];\n", $_; -} -print "\n"; - -my %cmd_disabler = ( - ciphers => "sock", - genrsa => "rsa", - rsautl => "rsa", - gendsa => "dsa", - dsaparam => "dsa", - gendh => "dh", - dhparam => "dh", - ecparam => "ec", - pkcs12 => "des", -); - -print "#ifdef INCLUDE_FUNCTION_TABLE\n"; -print "static FUNCTION functions[] = {\n"; -foreach my $cmd ( @ARGV ) { - my $str = " {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options},\n"; - if ($cmd =~ /^s_/) { - print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n"; - } elsif (grep { $cmd eq $_ } @disablables) { - print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n"; - } elsif (my $disabler = $cmd_disabler{$cmd}) { - print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n"; - } else { - print $str; + foreach (@ARGV) { + printf "extern const OPTIONS %s_options[];\n", $_; } + print "\n"; + print "extern FUNCTION functions[];\n"; } -my %md_disabler = ( - blake2b512 => "blake2", - blake2s256 => "blake2", -); -foreach my $cmd ( - "md2", "md4", "md5", - "gost", - "sha1", "sha224", "sha256", "sha384", - "sha512", "sha512-224", "sha512-256", - "sha3-224", "sha3-256", "sha3-384", "sha3-512", - "shake128", "shake256", - "mdc2", "rmd160", "blake2b512", "blake2s256", - "sm3" -) { - my $str = " {FT_md, \"$cmd\", dgst_main},\n"; - if (grep { $cmd eq $_ } @disablables) { - print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n"; - } elsif (my $disabler = $md_disabler{$cmd}) { - print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n"; - } else { - print $str; +if ($opt eq '-C') { + print <<"EOF"; +/* + * WARNING: do not edit! + * Generated by apps/progs.pl + * + * Copyright 1995-$YEAR 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 "progs.h" + +EOF + + my %cmd_disabler = ( + ciphers => "sock", + genrsa => "rsa", + gendsa => "dsa", + dsaparam => "dsa", + gendh => "dh", + dhparam => "dh", + ecparam => "ec", + ); + my %cmd_deprecated = ( +# The format of this table is: +# [0] = alternative command to use instead +# [1] = deprecented in this version +# [2] = preprocessor conditional for exclusing irrespective of deprecation +# rsa => [ "pkey", "3_0", "rsa" ], +# genrsa => [ "genpkey", "3_0", "rsa" ], + rsautl => [ "pkeyutl", "3_0", "rsa" ], +# dhparam => [ "pkeyparam", "3_0", "dh" ], +# dsaparam => [ "pkeyparam", "3_0", "dsa" ], +# dsa => [ "pkey", "3_0", "dsa" ], +# gendsa => [ "genpkey", "3_0", "dsa" ], +# ec => [ "pkey", "3_0", "ec" ], +# ecparam => [ "pkeyparam", "3_0", "ec" ], + ); + + print "FUNCTION functions[] = {\n"; + foreach my $cmd ( @ARGV ) { + my $str = + " {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options, NULL, NULL},\n"; + if ($cmd =~ /^s_/) { + print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n"; + } elsif (my $deprecated = $cmd_deprecated{$cmd}) { + my @dep = @{$deprecated}; + my $daltprg = $dep[0]; + my $dver = $dep[1]; + my $dsys = $dep[2]; + print "#if !defined(OPENSSL_NO_DEPRECATED_" . $dver . ")"; + if ($dsys) { + print " && !defined(OPENSSL_NO_" . uc($dsys) . ")"; + } + $dver =~ s/_/./g; + my $dalt = "\"" . $daltprg . "\", \"" . $dver . "\""; + $str =~ s/NULL, NULL/$dalt/; + print "\n${str}#endif\n"; + } elsif (grep { $cmd eq $_ } @disablables) { + print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n"; + } elsif (my $disabler = $cmd_disabler{$cmd}) { + print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n"; + } else { + print $str; + } } -} -my %cipher_disabler = ( - des3 => "des", - desx => "des", - cast5 => "cast", -); -foreach my $cmd ( - "aes-128-cbc", "aes-128-ecb", - "aes-192-cbc", "aes-192-ecb", - "aes-256-cbc", "aes-256-ecb", - "aria-128-cbc", "aria-128-cfb", - "aria-128-ctr", "aria-128-ecb", "aria-128-ofb", - "aria-128-cfb1", "aria-128-cfb8", - "aria-192-cbc", "aria-192-cfb", - "aria-192-ctr", "aria-192-ecb", "aria-192-ofb", - "aria-192-cfb1", "aria-192-cfb8", - "aria-256-cbc", "aria-256-cfb", - "aria-256-ctr", "aria-256-ecb", "aria-256-ofb", - "aria-256-cfb1", "aria-256-cfb8", - "camellia-128-cbc", "camellia-128-ecb", - "camellia-192-cbc", "camellia-192-ecb", - "camellia-256-cbc", "camellia-256-ecb", - "base64", "zlib", - "des", "des3", "desx", "idea", "seed", "rc4", "rc4-40", - "rc2", "bf", "cast", "rc5", - "des-ecb", "des-ede", "des-ede3", - "des-cbc", "des-ede-cbc","des-ede3-cbc", - "des-cfb", "des-ede-cfb","des-ede3-cfb", - "des-ofb", "des-ede-ofb","des-ede3-ofb", - "idea-cbc","idea-ecb", "idea-cfb", "idea-ofb", - "seed-cbc","seed-ecb", "seed-cfb", "seed-ofb", - "rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc", - "bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb", - "cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb", - "cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb", - "sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr" -) { - my $str = " {FT_cipher, \"$cmd\", enc_main, enc_options},\n"; - (my $algo = $cmd) =~ s/-.*//g; - if ($cmd eq "zlib") { - print "#ifdef ZLIB\n${str}#endif\n"; - } elsif (grep { $algo eq $_ } @disablables) { - print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n"; - } elsif (my $disabler = $cipher_disabler{$algo}) { - print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n"; - } else { - print $str; + my %md_disabler = ( + blake2b512 => "blake2", + blake2s256 => "blake2", + ); + foreach my $cmd ( + "md2", "md4", "md5", + "sha1", "sha224", "sha256", "sha384", + "sha512", "sha512-224", "sha512-256", + "sha3-224", "sha3-256", "sha3-384", "sha3-512", + "shake128", "shake256", + "mdc2", "rmd160", "blake2b512", "blake2s256", + "sm3" + ) { + my $str = " {FT_md, \"$cmd\", dgst_main, NULL, NULL},\n"; + if (grep { $cmd eq $_ } @disablables) { + print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n"; + } elsif (my $disabler = $md_disabler{$cmd}) { + print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n"; + } else { + print $str; + } } -} -print " {0, NULL, NULL}\n};\n"; -print "#endif\n"; + my %cipher_disabler = ( + des3 => "des", + desx => "des", + cast5 => "cast", + ); + foreach my $cmd ( + "aes-128-cbc", "aes-128-ecb", + "aes-192-cbc", "aes-192-ecb", + "aes-256-cbc", "aes-256-ecb", + "aria-128-cbc", "aria-128-cfb", + "aria-128-ctr", "aria-128-ecb", "aria-128-ofb", + "aria-128-cfb1", "aria-128-cfb8", + "aria-192-cbc", "aria-192-cfb", + "aria-192-ctr", "aria-192-ecb", "aria-192-ofb", + "aria-192-cfb1", "aria-192-cfb8", + "aria-256-cbc", "aria-256-cfb", + "aria-256-ctr", "aria-256-ecb", "aria-256-ofb", + "aria-256-cfb1", "aria-256-cfb8", + "camellia-128-cbc", "camellia-128-ecb", + "camellia-192-cbc", "camellia-192-ecb", + "camellia-256-cbc", "camellia-256-ecb", + "base64", "zlib", + "des", "des3", "desx", "idea", "seed", "rc4", "rc4-40", + "rc2", "bf", "cast", "rc5", + "des-ecb", "des-ede", "des-ede3", + "des-cbc", "des-ede-cbc","des-ede3-cbc", + "des-cfb", "des-ede-cfb","des-ede3-cfb", + "des-ofb", "des-ede-ofb","des-ede3-ofb", + "idea-cbc","idea-ecb", "idea-cfb", "idea-ofb", + "seed-cbc","seed-ecb", "seed-cfb", "seed-ofb", + "rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc", + "bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb", + "cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb", + "cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb", + "sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr" + ) { + my $str = " {FT_cipher, \"$cmd\", enc_main, enc_options, NULL},\n"; + (my $algo = $cmd) =~ s/-.*//g; + if ($cmd eq "zlib") { + print "#ifdef ZLIB\n${str}#endif\n"; + } elsif (grep { $algo eq $_ } @disablables) { + print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n"; + } elsif (my $disabler = $cipher_disabler{$algo}) { + print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n"; + } else { + print $str; + } + } + + print " {0, NULL, NULL, NULL, NULL}\n};\n"; +} diff --git a/apps/rand.c b/apps/rand.c index 4c6181507bd5..cbf495d5bc53 100644 --- a/apps/rand.c +++ b/apps/rand.c @@ -1,7 +1,7 @@ /* - * Copyright 1998-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -19,22 +19,30 @@ #include <openssl/rand.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_OUT, OPT_ENGINE, OPT_BASE64, OPT_HEX, - OPT_R_ENUM + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS rand_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [flags] num\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] num\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"out", OPT_OUT, '>', "Output file"}, - OPT_R_OPTIONS, - {"base64", OPT_BASE64, '-', "Base64 encode output"}, - {"hex", OPT_HEX, '-', "Hex encode output"}, #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"base64", OPT_BASE64, '-', "Base64 encode output"}, + {"hex", OPT_HEX, '-', "Hex encode output"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"num", 0, 0, "Number of bytes to generate"}, {NULL} }; @@ -74,18 +82,26 @@ int rand_main(int argc, char **argv) case OPT_HEX: format = FORMAT_TEXT; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* Optional argument is number of bytes to generate. */ argc = opt_num_rest(); argv = opt_rest(); if (argc == 1) { if (!opt_int(argv[0], &num) || num <= 0) - goto end; - } else if (argc > 0) { - BIO_printf(bio_err, "Extra arguments given.\n"); + goto opthelp; + } else if (argc != 0) { goto opthelp; } + if (!app_RAND_load()) + goto end; + out = bio_open_default(outfile, 'w', format); if (out == NULL) goto end; diff --git a/apps/rehash.c b/apps/rehash.c index fc1dffe97497..e4a4e14fd497 100644 --- a/apps/rehash.c +++ b/apps/rehash.c @@ -1,8 +1,8 @@ /* - * Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2013-2014 Timo Teräs <timo.teras@gmail.com> * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -42,7 +42,6 @@ # include <openssl/pem.h> # include <openssl/x509.h> - # ifndef PATH_MAX # define PATH_MAX 4096 # endif @@ -169,6 +168,12 @@ static int add_entry(enum Type type, unsigned int hash, const char *filename, *ep = nilhentry; ep->old_id = ~0; ep->filename = OPENSSL_strdup(filename); + if (ep->filename == NULL) { + OPENSSL_free(ep); + ep = NULL; + BIO_printf(bio_err, "out of memory\n"); + return 1; + } if (bp->last_entry) bp->last_entry->next = ep; if (bp->first_entry == NULL) @@ -209,7 +214,7 @@ static int handle_symlink(const char *filename, const char *fullpath) return -1; for (type = OSSL_NELEM(suffixes) - 1; type > 0; type--) { const char *suffix = suffixes[type]; - if (strncasecmp(suffix, &filename[i], strlen(suffix)) == 0) + if (OPENSSL_strncasecmp(suffix, &filename[i], strlen(suffix)) == 0) break; } i += strlen(suffixes[type]); @@ -233,7 +238,7 @@ static int do_file(const char *filename, const char *fullpath, enum Hash h) { STACK_OF (X509_INFO) *inf = NULL; X509_INFO *x; - X509_NAME *name = NULL; + const X509_NAME *name = NULL; BIO *b; const char *ext; unsigned char digest[EVP_MAX_MD_SIZE]; @@ -244,7 +249,7 @@ static int do_file(const char *filename, const char *fullpath, enum Hash h) if ((ext = strrchr(filename, '.')) == NULL) goto end; for (i = 0; i < OSSL_NELEM(extensions); i++) { - if (strcasecmp(extensions[i], ext + 1) == 0) + if (OPENSSL_strcasecmp(extensions[i], ext + 1) == 0) break; } if (i >= OSSL_NELEM(extensions)) @@ -292,10 +297,23 @@ static int do_file(const char *filename, const char *fullpath, enum Hash h) goto end; } if (name != NULL) { - if ((h == HASH_NEW) || (h == HASH_BOTH)) - errs += add_entry(type, X509_NAME_hash(name), filename, digest, 1, ~0); + if (h == HASH_NEW || h == HASH_BOTH) { + int ok; + unsigned long hash_value = + X509_NAME_hash_ex(name, + app_get0_libctx(), app_get0_propq(), &ok); + + if (ok) { + errs += add_entry(type, hash_value, filename, digest, 1, ~0); + } else { + BIO_printf(bio_err, "%s: error calculating SHA1 hash value\n", + opt_getprog()); + errs++; + } + } if ((h == HASH_OLD) || (h == HASH_BOTH)) - errs += add_entry(type, X509_NAME_hash_old(name), filename, digest, 1, ~0); + errs += add_entry(type, X509_NAME_hash_old(name), + filename, digest, 1, ~0); } end: @@ -454,19 +472,28 @@ static int do_dir(const char *dirname, enum Hash h) } typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_COMPAT, OPT_OLD, OPT_N, OPT_VERBOSE + OPT_COMMON, + OPT_COMPAT, OPT_OLD, OPT_N, OPT_VERBOSE, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS rehash_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert-directory...]\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [directory...]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, {"h", OPT_HELP, '-', "Display this summary"}, {"compat", OPT_COMPAT, '-', "Create both new- and old-style hash links"}, {"old", OPT_OLD, '-', "Use old-style hash to generate links"}, {"n", OPT_N, '-', "Do not remove existing links"}, + + OPT_SECTION("Output"), {"v", OPT_VERBOSE, '-', "Verbose output"}, + + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"directory", 0, 0, "One or more directories to process (optional)"}, {NULL} }; @@ -501,13 +528,19 @@ int rehash_main(int argc, char **argv) case OPT_VERBOSE: verbose = 1; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* Optional arguments are directories to scan. */ argc = opt_num_rest(); argv = opt_rest(); evpmd = EVP_sha1(); - evpmdsize = EVP_MD_size(evpmd); + evpmdsize = EVP_MD_get_size(evpmd); if (*argv != NULL) { while (*argv != NULL) diff --git a/apps/req.c b/apps/req.c index a603907cd5af..23757044ab7f 100644 --- a/apps/req.c +++ b/apps/req.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -14,6 +14,7 @@ #include <ctype.h> #include "apps.h" #include "progs.h" +#include <openssl/core_names.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/conf.h> @@ -25,32 +26,29 @@ #include <openssl/pem.h> #include <openssl/bn.h> #include <openssl/lhash.h> -#ifndef OPENSSL_NO_RSA -# include <openssl/rsa.h> -#endif +#include <openssl/rsa.h> #ifndef OPENSSL_NO_DSA # include <openssl/dsa.h> #endif -#define SECTION "req" - -#define BITS "default_bits" -#define KEYFILE "default_keyfile" -#define PROMPT "prompt" -#define DISTINGUISHED_NAME "distinguished_name" -#define ATTRIBUTES "attributes" -#define V3_EXTENSIONS "x509_extensions" -#define REQ_EXTENSIONS "req_extensions" -#define STRING_MASK "string_mask" -#define UTF8_IN "utf8" - -#define DEFAULT_KEY_LENGTH 2048 -#define MIN_KEY_LENGTH 512 - -static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *dn, int mutlirdn, - int attribs, unsigned long chtype); -static int build_subject(X509_REQ *req, const char *subj, unsigned long chtype, - int multirdn); +#define BITS "default_bits" +#define KEYFILE "default_keyfile" +#define PROMPT "prompt" +#define DISTINGUISHED_NAME "distinguished_name" +#define ATTRIBUTES "attributes" +#define V3_EXTENSIONS "x509_extensions" +#define REQ_EXTENSIONS "req_extensions" +#define STRING_MASK "string_mask" +#define UTF8_IN "utf8" + +#define DEFAULT_KEY_LENGTH 2048 +#define MIN_KEY_LENGTH 512 +#define DEFAULT_DAYS 30 /* default cert validity period in days */ +#define UNSET_DAYS -2 /* -1 may be used for testing expiration checks */ +#define EXT_COPY_UNSET -1 + +static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, X509_NAME *fsubj, + int mutlirdn, int attribs, unsigned long chtype); static int prompt_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect, STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect, @@ -65,91 +63,113 @@ static int add_DN_object(X509_NAME *n, char *text, const char *def, char *value, int nid, int n_min, int n_max, unsigned long chtype, int mval); static int genpkey_cb(EVP_PKEY_CTX *ctx); -static int build_data(char *text, const char *def, - char *value, int n_min, int n_max, - char *buf, const int buf_size, - const char *desc1, const char *desc2 - ); +static int build_data(char *text, const char *def, char *value, + int n_min, int n_max, char *buf, const int buf_size, + const char *desc1, const char *desc2); static int req_check_len(int len, int n_min, int n_max); static int check_end(const char *str, const char *end); static int join(char buf[], size_t buf_size, const char *name, const char *tail, const char *desc); static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr, - int *pkey_type, long *pkeylen, - char **palgnam, ENGINE *keygen_engine); + char **pkeytype, long *pkeylen, + ENGINE *keygen_engine); + +static const char *section = "req"; static CONF *req_conf = NULL; static CONF *addext_conf = NULL; static int batch = 0; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_KEYGEN_ENGINE, OPT_KEY, OPT_PUBKEY, OPT_NEW, OPT_CONFIG, OPT_KEYFORM, OPT_IN, OPT_OUT, OPT_KEYOUT, OPT_PASSIN, OPT_PASSOUT, OPT_NEWKEY, - OPT_PKEYOPT, OPT_SIGOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS, - OPT_VERIFY, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8, + OPT_PKEYOPT, OPT_SIGOPT, OPT_VFYOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS, + OPT_VERIFY, OPT_NOENC, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8, OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509, - OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, OPT_ADDEXT, OPT_EXTENSIONS, + OPT_CA, OPT_CAKEY, + OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, + OPT_COPY_EXTENSIONS, OPT_ADDEXT, OPT_EXTENSIONS, OPT_REQEXTS, OPT_PRECERT, OPT_MD, - OPT_R_ENUM + OPT_SECTION, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS req_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, + {"keygen_engine", OPT_KEYGEN_ENGINE, 's', + "Specify engine to be used for key generation operations"}, +#endif + {"in", OPT_IN, '<', "X.509 request input file (default stdin)"}, {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, - {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, - {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, - {"key", OPT_KEY, 's', "Private key to use"}, - {"keyform", OPT_KEYFORM, 'f', "Key file format"}, - {"pubkey", OPT_PUBKEY, '-', "Output public key"}, + {"verify", OPT_VERIFY, '-', "Verify self-signature on the request"}, + + OPT_SECTION("Certificate"), {"new", OPT_NEW, '-', "New request"}, {"config", OPT_CONFIG, '<', "Request template file"}, - {"keyout", OPT_KEYOUT, '>', "File to send the key to"}, - {"passin", OPT_PASSIN, 's', "Private key password source"}, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - OPT_R_OPTIONS, - {"newkey", OPT_NEWKEY, 's', "Specify as type:bits"}, - {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, - {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, - {"batch", OPT_BATCH, '-', - "Do not ask anything during request generation"}, - {"newhdr", OPT_NEWHDR, '-', "Output \"NEW\" in the header lines"}, - {"modulus", OPT_MODULUS, '-', "RSA modulus"}, - {"verify", OPT_VERIFY, '-', "Verify signature on REQ"}, - {"nodes", OPT_NODES, '-', "Don't encrypt the output key"}, - {"noout", OPT_NOOUT, '-', "Do not output REQ"}, - {"verbose", OPT_VERBOSE, '-', "Verbose output"}, + {"section", OPT_SECTION, 's', "Config section to use (default \"req\")"}, {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, {"reqopt", OPT_REQOPT, 's', "Various request text options"}, {"text", OPT_TEXT, '-', "Text form of request"}, {"x509", OPT_X509, '-', - "Output a x509 structure instead of a cert request"}, + "Output an X.509 certificate structure instead of a cert request"}, + {"CA", OPT_CA, '<', "Issuer cert to use for signing a cert, implies -x509"}, + {"CAkey", OPT_CAKEY, 's', + "Issuer private key to use with -CA; default is -CA arg"}, {OPT_MORE_STR, 1, 1, "(Required by some CA's)"}, - {"subj", OPT_SUBJ, 's', "Set or modify request subject"}, - {"subject", OPT_SUBJECT, '-', "Output the request's subject"}, + {"subj", OPT_SUBJ, 's', "Set or modify subject of request or cert"}, + {"subject", OPT_SUBJECT, '-', + "Print the subject of the output request or cert"}, {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-', - "Enable support for multivalued RDNs"}, + "Deprecated; multi-valued RDNs support is always on."}, {"days", OPT_DAYS, 'p', "Number of days cert is valid for"}, {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"}, + {"copy_extensions", OPT_COPY_EXTENSIONS, 's', + "copy extensions from request when using -x509"}, {"addext", OPT_ADDEXT, 's', "Additional cert extension key=value pair (may be given more than once)"}, {"extensions", OPT_EXTENSIONS, 's', "Cert extension section (override value in config file)"}, {"reqexts", OPT_REQEXTS, 's', "Request extension section (override value in config file)"}, - {"precert", OPT_PRECERT, '-', "Add a poison extension (implies -new)"}, + {"precert", OPT_PRECERT, '-', + "Add a poison extension to the generated cert (implies -new)"}, + + OPT_SECTION("Keys and Signing"), + {"key", OPT_KEY, 's', "Key for signing, and to include unless -in given"}, + {"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"}, + {"pubkey", OPT_PUBKEY, '-', "Output public key"}, + {"keyout", OPT_KEYOUT, '>', "File to write private key to"}, + {"passin", OPT_PASSIN, 's', "Private key and certificate password source"}, + {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, + {"newkey", OPT_NEWKEY, 's', + "Generate new key with [<alg>:]<nbits> or <alg>[:<file>] or param:<file>"}, + {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, + {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, + {"vfyopt", OPT_VFYOPT, 's', "Verification parameter in n:v form"}, {"", OPT_MD, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, - {"keygen_engine", OPT_KEYGEN_ENGINE, 's', - "Specify engine to be used for key generation operations"}, -#endif + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, + {"batch", OPT_BATCH, '-', + "Do not ask anything during request generation"}, + {"verbose", OPT_VERBOSE, '-', "Verbose output"}, + {"noenc", OPT_NOENC, '-', "Don't encrypt private keys"}, + {"nodes", OPT_NODES, '-', "Don't encrypt private keys; deprecated"}, + {"noout", OPT_NOOUT, '-', "Do not output REQ"}, + {"newhdr", OPT_NEWHDR, '-', "Output \"NEW\" in the header lines"}, + {"modulus", OPT_MODULUS, '-', "RSA modulus"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, {NULL} }; - /* * An LHASH of strings, where each string is an extension name. */ @@ -169,9 +189,8 @@ static void exts_cleanup(OPENSSL_STRING *x) } /* - * Is the |kv| key already duplicated? This is remarkably tricky to get - * right. Return 0 if unique, -1 on runtime error; 1 if found or a syntax - * error. + * Is the |kv| key already duplicated? This is remarkably tricky to get right. + * Return 0 if unique, -1 on runtime error; 1 if found or a syntax error. */ static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv) { @@ -200,7 +219,7 @@ static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv) *p = '\0'; /* Finally have a clean "key"; see if it's there [by attempt to add it]. */ - p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING*)kv); + p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING *)kv); if (p != NULL) { OPENSSL_free(p); return 1; @@ -215,36 +234,39 @@ static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv) int req_main(int argc, char **argv) { ASN1_INTEGER *serial = NULL; - BIO *in = NULL, *out = NULL; + BIO *out = NULL; ENGINE *e = NULL, *gen_eng = NULL; - EVP_PKEY *pkey = NULL; + EVP_PKEY *pkey = NULL, *CAkey = NULL; EVP_PKEY_CTX *genctx = NULL; - STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL; + STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL, *vfyopts = NULL; LHASH_OF(OPENSSL_STRING) *addexts = NULL; - X509 *x509ss = NULL; + X509 *new_x509 = NULL, *CAcert = NULL; X509_REQ *req = NULL; - const EVP_CIPHER *cipher = NULL; - const EVP_MD *md_alg = NULL, *digest = NULL; + EVP_CIPHER *cipher = NULL; + EVP_MD *md = NULL; + int ext_copy = EXT_COPY_UNSET; BIO *addext_bio = NULL; - char *extensions = NULL, *infile = NULL; - char *outfile = NULL, *keyfile = NULL; + char *extensions = NULL; + const char *infile = NULL, *CAfile = NULL, *CAkeyfile = NULL; + char *outfile = NULL, *keyfile = NULL, *digest = NULL; char *keyalgstr = NULL, *p, *prog, *passargin = NULL, *passargout = NULL; char *passin = NULL, *passout = NULL; char *nofree_passin = NULL, *nofree_passout = NULL; char *req_exts = NULL, *subj = NULL; + X509_NAME *fsubj = NULL; char *template = default_config_file, *keyout = NULL; const char *keyalg = NULL; OPTION_CHOICE o; - int ret = 1, x509 = 0, days = 0, i = 0, newreq = 0, verbose = 0; - int pkey_type = -1, private = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyform = FORMAT_PEM; - int modulus = 0, multirdn = 0, verify = 0, noout = 0, text = 0; - int nodes = 0, newhdr = 0, subject = 0, pubkey = 0, precert = 0; - long newkey = -1; + int days = UNSET_DAYS; + int ret = 1, gen_x509 = 0, i = 0, newreq = 0, verbose = 0; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyform = FORMAT_UNDEF; + int modulus = 0, multirdn = 1, verify = 0, noout = 0, text = 0; + int noenc = 0, newhdr = 0, subject = 0, pubkey = 0, precert = 0; + long newkey_len = -1; unsigned long chtype = MBSTRING_ASC, reqflag = 0; #ifndef OPENSSL_NO_DES - cipher = EVP_des_ede3_cbc(); + cipher = (EVP_CIPHER *)EVP_des_ede3_cbc(); #endif prog = opt_init(argc, argv, req_options); @@ -272,7 +294,7 @@ int req_main(int argc, char **argv) break; case OPT_KEYGEN_ENGINE: #ifndef OPENSSL_NO_ENGINE - gen_eng = ENGINE_by_id(opt_arg()); + gen_eng = setup_engine(opt_arg(), 0); if (gen_eng == NULL) { BIO_printf(bio_err, "Can't find keygen engine %s\n", *argv); goto opthelp; @@ -291,6 +313,9 @@ int req_main(int argc, char **argv) case OPT_CONFIG: template = opt_arg(); break; + case OPT_SECTION: + section = opt_arg(); + break; case OPT_KEYFORM: if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) goto opthelp; @@ -314,14 +339,19 @@ int req_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_NEWKEY: keyalg = opt_arg(); newreq = 1; break; case OPT_PKEYOPT: - if (!pkeyopts) + if (pkeyopts == NULL) pkeyopts = sk_OPENSSL_STRING_new_null(); - if (!pkeyopts || !sk_OPENSSL_STRING_push(pkeyopts, opt_arg())) + if (pkeyopts == NULL + || !sk_OPENSSL_STRING_push(pkeyopts, opt_arg())) goto opthelp; break; case OPT_SIGOPT: @@ -330,6 +360,12 @@ int req_main(int argc, char **argv) if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) goto opthelp; break; + case OPT_VFYOPT: + if (!vfyopts) + vfyopts = sk_OPENSSL_STRING_new_null(); + if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg())) + goto opthelp; + break; case OPT_BATCH: batch = 1; break; @@ -343,7 +379,8 @@ int req_main(int argc, char **argv) verify = 1; break; case OPT_NODES: - nodes = 1; + case OPT_NOENC: + noenc = 1; break; case OPT_NOOUT: noout = 1; @@ -366,10 +403,22 @@ int req_main(int argc, char **argv) text = 1; break; case OPT_X509: - x509 = 1; + gen_x509 = 1; + break; + case OPT_CA: + CAfile = opt_arg(); + gen_x509 = 1; + break; + case OPT_CAKEY: + CAkeyfile = opt_arg(); break; case OPT_DAYS: days = atoi(opt_arg()); + if (days < -1) { + BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n", + prog); + goto end; + } break; case OPT_SET_SERIAL: if (serial != NULL) { @@ -387,7 +436,14 @@ int req_main(int argc, char **argv) subj = opt_arg(); break; case OPT_MULTIVALUE_RDN: - multirdn = 1; + /* obsolete */ + break; + case OPT_COPY_EXTENSIONS: + if (!set_ext_copy(&ext_copy, opt_arg())) { + BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n", + opt_arg()); + goto end; + } break; case OPT_ADDEXT: p = opt_arg(); @@ -398,9 +454,11 @@ int req_main(int argc, char **argv) goto end; } i = duplicated(addexts, p); - if (i == 1) + if (i == 1) { + BIO_printf(bio_err, "Duplicate extension: %s\n", p); goto opthelp; - if (i < 0 || BIO_printf(addext_bio, "%s\n", opt_arg()) < 0) + } + if (i < 0 || BIO_printf(addext_bio, "%s\n", p) < 0) goto end; break; case OPT_EXTENSIONS: @@ -413,37 +471,39 @@ int req_main(int argc, char **argv) newreq = precert = 1; break; case OPT_MD: - if (!opt_md(opt_unknown(), &md_alg)) - goto opthelp; - digest = md_alg; + digest = opt_unknown(); break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; - if (days && !x509) - BIO_printf(bio_err, "Ignoring -days; not generating a certificate\n"); - if (x509 && infile == NULL) - newreq = 1; + if (!app_RAND_load()) + goto end; - /* TODO: simplify this as pkey is still always NULL here */ - private = newreq && (pkey == NULL) ? 1 : 0; + if (!gen_x509) { + if (days != UNSET_DAYS) + BIO_printf(bio_err, "Ignoring -days without -x509; not generating a certificate\n"); + if (ext_copy == EXT_COPY_NONE) + BIO_printf(bio_err, "Ignoring -copy_extensions 'none' when -x509 is not given\n"); + } + if (gen_x509 && infile == NULL) + newreq = 1; if (!app_passwd(passargin, passargout, &passin, &passout)) { BIO_printf(bio_err, "Error getting passwords\n"); goto end; } - if (verbose) - BIO_printf(bio_err, "Using configuration from %s\n", template); - if ((req_conf = app_load_config(template)) == NULL) + if ((req_conf = app_load_config_verbose(template, verbose)) == NULL) goto end; - if (addext_bio) { + if (addext_bio != NULL) { if (verbose) BIO_printf(bio_err, - "Using additional configuration from command line\n"); + "Using additional configuration from -addext options\n"); if ((addext_conf = app_load_config_bio(addext_bio, NULL)) == NULL) goto end; } @@ -455,14 +515,12 @@ int req_main(int argc, char **argv) if (p == NULL) ERR_clear_error(); if (p != NULL) { - BIO *oid_bio; + BIO *oid_bio = BIO_new_file(p, "r"); - oid_bio = BIO_new_file(p, "r"); if (oid_bio == NULL) { - /*- - BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); - ERR_print_errors(bio_err); - */ + if (verbose) + BIO_printf(bio_err, + "Problems opening '%s' for extra OIDs\n", p); } else { OBJ_create_objects(oid_bio); BIO_free(oid_bio); @@ -472,59 +530,67 @@ int req_main(int argc, char **argv) if (!add_oid_section(req_conf)) goto end; - if (md_alg == NULL) { - p = NCONF_get_string(req_conf, SECTION, "default_md"); - if (p == NULL) { + /* Check that any specified digest is fetchable */ + if (digest != NULL) { + if (!opt_md(digest, &md)) { ERR_clear_error(); - } else { - if (!opt_md(p, &md_alg)) - goto opthelp; - digest = md_alg; + goto opthelp; } + EVP_MD_free(md); + } else { + /* No digest specified, default to configuration */ + p = NCONF_get_string(req_conf, section, "default_md"); + if (p == NULL) + ERR_clear_error(); + else + digest = p; } if (extensions == NULL) { - extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS); + extensions = NCONF_get_string(req_conf, section, V3_EXTENSIONS); if (extensions == NULL) ERR_clear_error(); } if (extensions != NULL) { /* Check syntax of file */ X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); X509V3_set_nconf(&ctx, req_conf); if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) { BIO_printf(bio_err, - "Error Loading extension section %s\n", extensions); + "Error checking x509 extension section %s\n", + extensions); goto end; } } if (addext_conf != NULL) { /* Check syntax of command line extensions */ X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); X509V3_set_nconf(&ctx, addext_conf); if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) { - BIO_printf(bio_err, "Error Loading command line extensions\n"); + BIO_printf(bio_err, "Error checking extensions defined using -addext\n"); goto end; } } if (passin == NULL) { passin = nofree_passin = - NCONF_get_string(req_conf, SECTION, "input_password"); + NCONF_get_string(req_conf, section, "input_password"); if (passin == NULL) ERR_clear_error(); } if (passout == NULL) { passout = nofree_passout = - NCONF_get_string(req_conf, SECTION, "output_password"); + NCONF_get_string(req_conf, section, "output_password"); if (passout == NULL) ERR_clear_error(); } - p = NCONF_get_string(req_conf, SECTION, STRING_MASK); + p = NCONF_get_string(req_conf, section, STRING_MASK); if (p == NULL) ERR_clear_error(); @@ -534,7 +600,7 @@ int req_main(int argc, char **argv) } if (chtype != MBSTRING_UTF8) { - p = NCONF_get_string(req_conf, SECTION, UTF8_IN); + p = NCONF_get_string(req_conf, section, UTF8_IN); if (p == NULL) ERR_clear_error(); else if (strcmp(p, "yes") == 0) @@ -542,134 +608,117 @@ int req_main(int argc, char **argv) } if (req_exts == NULL) { - req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS); + req_exts = NCONF_get_string(req_conf, section, REQ_EXTENSIONS); if (req_exts == NULL) ERR_clear_error(); } if (req_exts != NULL) { /* Check syntax of file */ X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); X509V3_set_nconf(&ctx, req_conf); if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) { BIO_printf(bio_err, - "Error Loading request extension section %s\n", + "Error checking request extension section %s\n", req_exts); goto end; } } if (keyfile != NULL) { - pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); - if (pkey == NULL) { - /* load_key() has already printed an appropriate message */ + pkey = load_key(keyfile, keyform, 0, passin, e, "private key"); + if (pkey == NULL) goto end; - } else { - app_RAND_load_conf(req_conf, SECTION); - } + app_RAND_load_conf(req_conf, section); } + if (newreq && pkey == NULL) { + app_RAND_load_conf(req_conf, section); - if (newreq && (pkey == NULL)) { - app_RAND_load_conf(req_conf, SECTION); + if (!NCONF_get_number(req_conf, section, BITS, &newkey_len)) + newkey_len = DEFAULT_KEY_LENGTH; - if (!NCONF_get_number(req_conf, SECTION, BITS, &newkey)) { - newkey = DEFAULT_KEY_LENGTH; - } - - if (keyalg != NULL) { - genctx = set_keygen_ctx(keyalg, &pkey_type, &newkey, - &keyalgstr, gen_eng); - if (genctx == NULL) - goto end; - } + genctx = set_keygen_ctx(keyalg, &keyalgstr, &newkey_len, gen_eng); + if (genctx == NULL) + goto end; - if (newkey < MIN_KEY_LENGTH - && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) { - BIO_printf(bio_err, "private key length is too short,\n"); - BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n", - MIN_KEY_LENGTH, newkey); + if (newkey_len < MIN_KEY_LENGTH + && (EVP_PKEY_CTX_is_a(genctx, "RSA") + || EVP_PKEY_CTX_is_a(genctx, "RSA-PSS") + || EVP_PKEY_CTX_is_a(genctx, "DSA"))) { + BIO_printf(bio_err, "Private key length too short, needs to be at least %d bits, not %ld.\n", + MIN_KEY_LENGTH, newkey_len); goto end; } - if (pkey_type == EVP_PKEY_RSA && newkey > OPENSSL_RSA_MAX_MODULUS_BITS) + if (newkey_len > OPENSSL_RSA_MAX_MODULUS_BITS + && (EVP_PKEY_CTX_is_a(genctx, "RSA") + || EVP_PKEY_CTX_is_a(genctx, "RSA-PSS"))) BIO_printf(bio_err, "Warning: It is not recommended to use more than %d bit for RSA keys.\n" " Your key size is %ld! Larger key size may behave not as expected.\n", - OPENSSL_RSA_MAX_MODULUS_BITS, newkey); + OPENSSL_RSA_MAX_MODULUS_BITS, newkey_len); #ifndef OPENSSL_NO_DSA - if (pkey_type == EVP_PKEY_DSA && newkey > OPENSSL_DSA_MAX_MODULUS_BITS) + if (EVP_PKEY_CTX_is_a(genctx, "DSA") + && newkey_len > OPENSSL_DSA_MAX_MODULUS_BITS) BIO_printf(bio_err, "Warning: It is not recommended to use more than %d bit for DSA keys.\n" " Your key size is %ld! Larger key size may behave not as expected.\n", - OPENSSL_DSA_MAX_MODULUS_BITS, newkey); + OPENSSL_DSA_MAX_MODULUS_BITS, newkey_len); #endif - if (genctx == NULL) { - genctx = set_keygen_ctx(NULL, &pkey_type, &newkey, - &keyalgstr, gen_eng); - if (!genctx) - goto end; - } - if (pkeyopts != NULL) { char *genopt; for (i = 0; i < sk_OPENSSL_STRING_num(pkeyopts); i++) { genopt = sk_OPENSSL_STRING_value(pkeyopts, i); if (pkey_ctrl_string(genctx, genopt) <= 0) { - BIO_printf(bio_err, "parameter error \"%s\"\n", genopt); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Key parameter error \"%s\"\n", genopt); goto end; } } } - if (pkey_type == EVP_PKEY_EC) { - BIO_printf(bio_err, "Generating an EC private key\n"); - } else { - BIO_printf(bio_err, "Generating a %s private key\n", keyalgstr); - } - EVP_PKEY_CTX_set_cb(genctx, genpkey_cb); EVP_PKEY_CTX_set_app_data(genctx, bio_err); - if (EVP_PKEY_keygen(genctx, &pkey) <= 0) { - BIO_puts(bio_err, "Error Generating Key\n"); - goto end; - } + pkey = app_keygen(genctx, keyalgstr, newkey_len, verbose); EVP_PKEY_CTX_free(genctx); genctx = NULL; + } + if (keyout == NULL && keyfile == NULL) { + keyout = NCONF_get_string(req_conf, section, KEYFILE); + if (keyout == NULL) + ERR_clear_error(); + } - if (keyout == NULL) { - keyout = NCONF_get_string(req_conf, SECTION, KEYFILE); + if (pkey != NULL && (keyfile == NULL || keyout != NULL)) { + if (verbose) { + BIO_printf(bio_err, "Writing private key to "); if (keyout == NULL) - ERR_clear_error(); + BIO_printf(bio_err, "stdout\n"); + else + BIO_printf(bio_err, "'%s'\n", keyout); } - - if (keyout == NULL) - BIO_printf(bio_err, "writing new private key to stdout\n"); - else - BIO_printf(bio_err, "writing new private key to '%s'\n", keyout); - out = bio_open_owner(keyout, outformat, private); + out = bio_open_owner(keyout, outformat, newreq); if (out == NULL) goto end; - p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key"); + p = NCONF_get_string(req_conf, section, "encrypt_rsa_key"); if (p == NULL) { ERR_clear_error(); - p = NCONF_get_string(req_conf, SECTION, "encrypt_key"); + p = NCONF_get_string(req_conf, section, "encrypt_key"); if (p == NULL) ERR_clear_error(); } if ((p != NULL) && (strcmp(p, "no") == 0)) cipher = NULL; - if (nodes) + if (noenc) cipher = NULL; i = 0; loop: - assert(private); if (!PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, passout)) { if ((ERR_GET_REASON(ERR_peek_error()) == @@ -685,112 +734,151 @@ int req_main(int argc, char **argv) BIO_printf(bio_err, "-----\n"); } + /* + * subj is expected to be in the format /type0=value0/type1=value1/type2=... + * where characters may be escaped by \ + */ + if (subj != NULL + && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL) + goto end; + if (!newreq) { - in = bio_open_default(infile, 'r', informat); - if (in == NULL) + req = load_csr(infile /* if NULL, reads from stdin */, + informat, "X509 request"); + if (req == NULL) goto end; + } - if (informat == FORMAT_ASN1) - req = d2i_X509_REQ_bio(in, NULL); - else - req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); - if (req == NULL) { - BIO_printf(bio_err, "unable to load X509 request\n"); + if (CAkeyfile == NULL) + CAkeyfile = CAfile; + if (CAkeyfile != NULL) { + if (CAfile == NULL) { + BIO_printf(bio_err, + "Warning: Ignoring -CAkey option since no -CA option is given\n"); + } else { + if ((CAkey = load_key(CAkeyfile, FORMAT_UNDEF, + 0, passin, e, + CAkeyfile != CAfile + ? "issuer private key from -CAkey arg" + : "issuer private key from -CA arg")) == NULL) + goto end; + } + } + if (CAfile != NULL) { + if ((CAcert = load_cert_pass(CAfile, FORMAT_UNDEF, 1, passin, + "issuer cert from -CA arg")) == NULL) + goto end; + if (!X509_check_private_key(CAcert, CAkey)) { + BIO_printf(bio_err, + "Issuer CA certificate and key do not match\n"); goto end; } } - - if (newreq || x509) { - if (pkey == NULL) { - BIO_printf(bio_err, "you need to specify a private key\n"); + if (newreq || gen_x509) { + if (CAcert == NULL && pkey == NULL) { + BIO_printf(bio_err, "Must provide a signature key using -key or" + " provide -CA / -CAkey\n"); goto end; } if (req == NULL) { - req = X509_REQ_new(); + req = X509_REQ_new_ex(app_get0_libctx(), app_get0_propq()); if (req == NULL) { goto end; } - i = make_REQ(req, pkey, subj, multirdn, !x509, chtype); - subj = NULL; /* done processing '-subj' option */ - if (!i) { - BIO_printf(bio_err, "problems making Certificate Request\n"); + if (!make_REQ(req, pkey, fsubj, multirdn, !gen_x509, chtype)){ + BIO_printf(bio_err, "Error making certificate request\n"); goto end; } + /* Note that -x509 can take over -key and -subj option values. */ } - if (x509) { - EVP_PKEY *tmppkey; + if (gen_x509) { + EVP_PKEY *pub_key = X509_REQ_get0_pubkey(req); + EVP_PKEY *issuer_key = CAcert != NULL ? CAkey : pkey; X509V3_CTX ext_ctx; - if ((x509ss = X509_new()) == NULL) - goto end; + X509_NAME *issuer = CAcert != NULL ? X509_get_subject_name(CAcert) : + X509_REQ_get_subject_name(req); + X509_NAME *n_subj = fsubj != NULL ? fsubj : + X509_REQ_get_subject_name(req); - /* Set version to V3 */ - if ((extensions != NULL || addext_conf != NULL) - && !X509_set_version(x509ss, 2)) + if ((new_x509 = X509_new_ex(app_get0_libctx(), + app_get0_propq())) == NULL) goto end; + if (serial != NULL) { - if (!X509_set_serialNumber(x509ss, serial)) + if (!X509_set_serialNumber(new_x509, serial)) goto end; } else { - if (!rand_serial(NULL, X509_get_serialNumber(x509ss))) + if (!rand_serial(NULL, X509_get_serialNumber(new_x509))) goto end; } - if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) + if (!X509_set_issuer_name(new_x509, issuer)) goto end; - if (days == 0) { - /* set default days if it's not specified */ - days = 30; + if (days == UNSET_DAYS) { + days = DEFAULT_DAYS; } - if (!set_cert_times(x509ss, NULL, NULL, days)) + if (!set_cert_times(new_x509, NULL, NULL, days)) + goto end; + if (!X509_set_subject_name(new_x509, n_subj)) goto end; - if (!X509_set_subject_name - (x509ss, X509_REQ_get_subject_name(req))) + if (!pub_key || !X509_set_pubkey(new_x509, pub_key)) goto end; - tmppkey = X509_REQ_get0_pubkey(req); - if (!tmppkey || !X509_set_pubkey(x509ss, tmppkey)) + if (ext_copy == EXT_COPY_UNSET) { + if (infile != NULL) + BIO_printf(bio_err, "Warning: No -copy_extensions given; ignoring any extensions in the request\n"); + } else if (!copy_extensions(new_x509, req, ext_copy)) { + BIO_printf(bio_err, "Error copying extensions from request\n"); goto end; + } /* Set up V3 context struct */ - - X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0); + X509V3_set_ctx(&ext_ctx, CAcert != NULL ? CAcert : new_x509, + new_x509, NULL, NULL, X509V3_CTX_REPLACE); + /* prepare fallback for AKID, but only if issuer cert == new_x509 */ + if (CAcert == NULL) { + if (!X509V3_set_issuer_pkey(&ext_ctx, issuer_key)) + goto end; + ERR_set_mark(); + if (!X509_check_private_key(new_x509, issuer_key)) + BIO_printf(bio_err, + "Warning: Signature key and public key of cert do not match\n"); + ERR_pop_to_mark(); + } X509V3_set_nconf(&ext_ctx, req_conf); /* Add extensions */ - if (extensions != NULL && !X509V3_EXT_add_nconf(req_conf, - &ext_ctx, extensions, - x509ss)) { - BIO_printf(bio_err, "Error Loading extension section %s\n", + if (extensions != NULL + && !X509V3_EXT_add_nconf(req_conf, &ext_ctx, extensions, + new_x509)) { + BIO_printf(bio_err, "Error adding x509 extensions from section %s\n", extensions); goto end; } if (addext_conf != NULL && !X509V3_EXT_add_nconf(addext_conf, &ext_ctx, "default", - x509ss)) { - BIO_printf(bio_err, "Error Loading command line extensions\n"); + new_x509)) { + BIO_printf(bio_err, "Error adding extensions defined via -addext\n"); goto end; } /* If a pre-cert was requested, we need to add a poison extension */ if (precert) { - if (X509_add1_ext_i2d(x509ss, NID_ct_precert_poison, NULL, 1, 0) - != 1) { + if (X509_add1_ext_i2d(new_x509, NID_ct_precert_poison, + NULL, 1, 0) != 1) { BIO_printf(bio_err, "Error adding poison extension\n"); goto end; } } - i = do_X509_sign(x509ss, pkey, digest, sigopts); - if (!i) { - ERR_print_errors(bio_err); + i = do_X509_sign(new_x509, issuer_key, digest, sigopts, &ext_ctx); + if (!i) goto end; - } } else { X509V3_CTX ext_ctx; /* Set up V3 context struct */ - X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0); X509V3_set_nconf(&ext_ctx, req_conf); @@ -798,49 +886,39 @@ int req_main(int argc, char **argv) if (req_exts != NULL && !X509V3_EXT_REQ_add_nconf(req_conf, &ext_ctx, req_exts, req)) { - BIO_printf(bio_err, "Error Loading extension section %s\n", + BIO_printf(bio_err, "Error adding request extensions from section %s\n", req_exts); goto end; } if (addext_conf != NULL && !X509V3_EXT_REQ_add_nconf(addext_conf, &ext_ctx, "default", req)) { - BIO_printf(bio_err, "Error Loading command line extensions\n"); + BIO_printf(bio_err, "Error adding extensions defined via -addext\n"); goto end; } i = do_X509_REQ_sign(req, pkey, digest, sigopts); - if (!i) { - ERR_print_errors(bio_err); + if (!i) goto end; - } } } - if (subj && x509) { - BIO_printf(bio_err, "Cannot modify certificate subject\n"); - goto end; - } - - if (subj && !x509) { + if (subj != NULL && !newreq && !gen_x509) { if (verbose) { - BIO_printf(bio_err, "Modifying Request's Subject\n"); - print_name(bio_err, "old subject=", - X509_REQ_get_subject_name(req), get_nameopt()); + BIO_printf(out, "Modifying subject of certificate request\n"); + print_name(out, "Old subject=", X509_REQ_get_subject_name(req)); } - if (build_subject(req, subj, chtype, multirdn) == 0) { - BIO_printf(bio_err, "ERROR: cannot modify subject\n"); - ret = 1; + if (!X509_REQ_set_subject_name(req, fsubj)) { + BIO_printf(bio_err, "Error modifying subject of certificate request\n"); goto end; } if (verbose) { - print_name(bio_err, "new subject=", - X509_REQ_get_subject_name(req), get_nameopt()); + print_name(out, "New subject=", X509_REQ_get_subject_name(req)); } } - if (verify && !x509) { + if (verify) { EVP_PKEY *tpubkey = pkey; if (tpubkey == NULL) { @@ -849,16 +927,14 @@ int req_main(int argc, char **argv) goto end; } - i = X509_REQ_verify(req, tpubkey); + i = do_X509_REQ_verify(req, tpubkey, vfyopts); - if (i < 0) { + if (i < 0) goto end; - } else if (i == 0) { - BIO_printf(bio_err, "verify failure\n"); - ERR_print_errors(bio_err); - } else { /* if (i > 0) */ - BIO_printf(bio_err, "verify OK\n"); - } + if (i == 0) + BIO_printf(bio_err, "Certificate request self-signature verify failure\n"); + else /* i > 0 */ + BIO_printf(bio_err, "Certificate request self-signature verify OK\n"); } if (noout && !text && !modulus && !subject && !pubkey) { @@ -878,62 +954,58 @@ int req_main(int argc, char **argv) if (tpubkey == NULL) { BIO_printf(bio_err, "Error getting public key\n"); - ERR_print_errors(bio_err); goto end; } PEM_write_bio_PUBKEY(out, tpubkey); } if (text) { - if (x509) - ret = X509_print_ex(out, x509ss, get_nameopt(), reqflag); + if (gen_x509) + ret = X509_print_ex(out, new_x509, get_nameopt(), reqflag); else ret = X509_REQ_print_ex(out, req, get_nameopt(), reqflag); if (ret == 0) { - if (x509) - BIO_printf(bio_err, "Error printing certificate\n"); + if (gen_x509) + BIO_printf(bio_err, "Error printing certificate\n"); else - BIO_printf(bio_err, "Error printing certificate request\n"); - - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Error printing certificate request\n"); goto end; } } if (subject) { - if (x509) - print_name(out, "subject=", X509_get_subject_name(x509ss), - get_nameopt()); - else - print_name(out, "subject=", X509_REQ_get_subject_name(req), - get_nameopt()); + print_name(out, "subject=", gen_x509 + ? X509_get_subject_name(new_x509) + : X509_REQ_get_subject_name(req)); } if (modulus) { EVP_PKEY *tpubkey; - if (x509) - tpubkey = X509_get0_pubkey(x509ss); + if (gen_x509) + tpubkey = X509_get0_pubkey(new_x509); else tpubkey = X509_REQ_get0_pubkey(req); if (tpubkey == NULL) { - fprintf(stdout, "Modulus=unavailable\n"); + fprintf(stdout, "Modulus is unavailable\n"); goto end; } fprintf(stdout, "Modulus="); -#ifndef OPENSSL_NO_RSA - if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) { - const BIGNUM *n; - RSA_get0_key(EVP_PKEY_get0_RSA(tpubkey), &n, NULL, NULL); + if (EVP_PKEY_is_a(tpubkey, "RSA") || EVP_PKEY_is_a(tpubkey, "RSA-PSS")) { + BIGNUM *n = NULL; + + if (!EVP_PKEY_get_bn_param(tpubkey, "n", &n)) + goto end; BN_print(out, n); - } else -#endif + BN_free(n); + } else { fprintf(stdout, "Wrong Algorithm type"); + } fprintf(stdout, "\n"); } - if (!noout && !x509) { + if (!noout && !gen_x509) { if (outformat == FORMAT_ASN1) i = i2d_X509_REQ_bio(out, req); else if (newhdr) @@ -941,17 +1013,17 @@ int req_main(int argc, char **argv) else i = PEM_write_bio_X509_REQ(out, req); if (!i) { - BIO_printf(bio_err, "unable to write X509 request\n"); + BIO_printf(bio_err, "Unable to write certificate request\n"); goto end; } } - if (!noout && x509 && (x509ss != NULL)) { + if (!noout && gen_x509 && new_x509 != NULL) { if (outformat == FORMAT_ASN1) - i = i2d_X509_bio(out, x509ss); + i = i2d_X509_bio(out, new_x509); else - i = PEM_write_bio_X509(out, x509ss); + i = PEM_write_bio_X509(out, new_x509); if (!i) { - BIO_printf(bio_err, "unable to write X509 certificate\n"); + BIO_printf(bio_err, "Unable to write X509 certificate\n"); goto end; } } @@ -963,20 +1035,23 @@ int req_main(int argc, char **argv) NCONF_free(req_conf); NCONF_free(addext_conf); BIO_free(addext_bio); - BIO_free(in); BIO_free_all(out); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(genctx); sk_OPENSSL_STRING_free(pkeyopts); sk_OPENSSL_STRING_free(sigopts); + sk_OPENSSL_STRING_free(vfyopts); lh_OPENSSL_STRING_doall(addexts, exts_cleanup); lh_OPENSSL_STRING_free(addexts); #ifndef OPENSSL_NO_ENGINE - ENGINE_free(gen_eng); + release_engine(gen_eng); #endif OPENSSL_free(keyalgstr); X509_REQ_free(req); - X509_free(x509ss); + X509_NAME_free(fsubj); + X509_free(new_x509); + X509_free(CAcert); + EVP_PKEY_free(CAkey); ASN1_INTEGER_free(serial); release_engine(e); if (passin != nofree_passin) @@ -986,50 +1061,48 @@ int req_main(int argc, char **argv) return ret; } -static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn, - int attribs, unsigned long chtype) +static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, X509_NAME *fsubj, + int multirdn, int attribs, unsigned long chtype) { int ret = 0, i; char no_prompt = 0; - STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL; + STACK_OF(CONF_VALUE) *dn_sk = NULL, *attr_sk = NULL; char *tmp, *dn_sect, *attr_sect; - tmp = NCONF_get_string(req_conf, SECTION, PROMPT); + tmp = NCONF_get_string(req_conf, section, PROMPT); if (tmp == NULL) ERR_clear_error(); if ((tmp != NULL) && strcmp(tmp, "no") == 0) no_prompt = 1; - dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME); + dn_sect = NCONF_get_string(req_conf, section, DISTINGUISHED_NAME); if (dn_sect == NULL) { - BIO_printf(bio_err, "unable to find '%s' in config\n", - DISTINGUISHED_NAME); - goto err; - } - dn_sk = NCONF_get_section(req_conf, dn_sect); - if (dn_sk == NULL) { - BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect); - goto err; + ERR_clear_error(); + } else { + dn_sk = NCONF_get_section(req_conf, dn_sect); + if (dn_sk == NULL) { + BIO_printf(bio_err, "Unable to get '%s' section\n", dn_sect); + goto err; + } } - attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES); + attr_sect = NCONF_get_string(req_conf, section, ATTRIBUTES); if (attr_sect == NULL) { ERR_clear_error(); - attr_sk = NULL; } else { attr_sk = NCONF_get_section(req_conf, attr_sect); if (attr_sk == NULL) { - BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect); + BIO_printf(bio_err, "Unable to get '%s' section\n", attr_sect); goto err; } } - /* setup version number */ - if (!X509_REQ_set_version(req, 0L)) - goto err; /* version 1 */ + /* so far there is only version 1 */ + if (!X509_REQ_set_version(req, X509_REQ_VERSION_1)) + goto err; - if (subj) - i = build_subject(req, subj, chtype, multirdn); + if (fsubj != NULL) + i = X509_REQ_set_subject_name(req, fsubj); else if (no_prompt) i = auto_info(req, dn_sk, attr_sk, attribs, chtype); else @@ -1046,26 +1119,6 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn, return ret; } -/* - * subject is expected to be in the format /type0=value0/type1=value1/type2=... - * where characters may be escaped by \ - */ -static int build_subject(X509_REQ *req, const char *subject, unsigned long chtype, - int multirdn) -{ - X509_NAME *n; - - if ((n = parse_name(subject, chtype, multirdn)) == NULL) - return 0; - - if (!X509_REQ_set_subject_name(req, n)) { - X509_NAME_free(n); - return 0; - } - X509_NAME_free(n); - return 1; -} - static int prompt_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect, STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect, @@ -1079,8 +1132,7 @@ static int prompt_info(X509_REQ *req, char *type, *value; const char *def; CONF_VALUE *v; - X509_NAME *subj; - subj = X509_REQ_get_subject_name(req); + X509_NAME *subj = X509_REQ_get_subject_name(req); if (!batch) { BIO_printf(bio_err, @@ -1100,7 +1152,7 @@ static int prompt_info(X509_REQ *req, if (sk_CONF_VALUE_num(dn_sk)) { i = -1; start: - for ( ; ; ) { + for (;;) { i++; if (sk_CONF_VALUE_num(dn_sk) <= i) break; @@ -1152,7 +1204,6 @@ static int prompt_info(X509_REQ *req, n_min = -1; } - if (!join(buf, sizeof(buf), v->name, "_max", "Name")) return 0; if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) { @@ -1165,8 +1216,7 @@ static int prompt_info(X509_REQ *req, return 0; } if (X509_NAME_entry_count(subj) == 0) { - BIO_printf(bio_err, - "error, no objects specified in config file\n"); + BIO_printf(bio_err, "Error: No objects specified in config file\n"); return 0; } @@ -1181,7 +1231,7 @@ static int prompt_info(X509_REQ *req, i = -1; start2: - for ( ; ; ) { + for (;;) { i++; if ((attr_sk == NULL) || (sk_CONF_VALUE_num(attr_sk) <= i)) break; @@ -1207,7 +1257,7 @@ static int prompt_info(X509_REQ *req, value = NULL; } - if (!join(buf, sizeof(buf), type,"_min", "Name")) + if (!join(buf, sizeof(buf), type, "_min", "Name")) return 0; if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) { ERR_clear_error(); @@ -1258,10 +1308,10 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, */ for (p = v->name; *p; p++) { #ifndef CHARSET_EBCDIC - spec_char = ((*p == ':') || (*p == ',') || (*p == '.')); + spec_char = (*p == ':' || *p == ',' || *p == '.'); #else - spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[',']) - || (*p == os_toascii['.'])); + spec_char = (*p == os_toascii[':'] || *p == os_toascii[','] + || *p == os_toascii['.']); #endif if (spec_char) { p++; @@ -1289,7 +1339,7 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, } if (!X509_NAME_entry_count(subj)) { - BIO_printf(bio_err, "error, no objects specified in config file\n"); + BIO_printf(bio_err, "Error: No objects specified in config file\n"); return 0; } if (attribs) { @@ -1339,19 +1389,15 @@ static int add_attribute_object(X509_REQ *req, char *text, const char *def, if (!X509_REQ_add1_attr_by_NID(req, nid, chtype, (unsigned char *)buf, -1)) { BIO_printf(bio_err, "Error adding attribute\n"); - ERR_print_errors(bio_err); ret = 0; } return ret; } - -static int build_data(char *text, const char *def, - char *value, int n_min, int n_max, - char *buf, const int buf_size, - const char *desc1, const char *desc2 - ) +static int build_data(char *text, const char *def, char *value, + int n_min, int n_max, char *buf, const int buf_size, + const char *desc1, const char *desc2) { int i; start: @@ -1386,7 +1432,7 @@ static int build_data(char *text, const char *def, i = strlen(buf); if (buf[i - 1] != '\n') { - BIO_printf(bio_err, "weird input :-(\n"); + BIO_printf(bio_err, "Missing newline at end of input\n"); return 0; } buf[--i] = '\0'; @@ -1403,16 +1449,14 @@ static int build_data(char *text, const char *def, static int req_check_len(int len, int n_min, int n_max) { - if ((n_min > 0) && (len < n_min)) { + if (n_min > 0 && len < n_min) { BIO_printf(bio_err, - "string is too short, it needs to be at least %d bytes long\n", - n_min); + "String too short, must be at least %d bytes long\n", n_min); return 0; } - if ((n_max >= 0) && (len > n_max)) { + if (n_max >= 0 && len > n_max) { BIO_printf(bio_err, - "string is too long, it needs to be no more than %d bytes long\n", - n_max); + "String too long, must be at most %d bytes long\n", n_max); return 0; } return 1; @@ -1451,66 +1495,71 @@ static int join(char buf[], size_t buf_size, const char *name, } static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr, - int *pkey_type, long *pkeylen, - char **palgnam, ENGINE *keygen_engine) + char **pkeytype, long *pkeylen, + ENGINE *keygen_engine) { EVP_PKEY_CTX *gctx = NULL; EVP_PKEY *param = NULL; long keylen = -1; BIO *pbio = NULL; + const char *keytype = NULL; + size_t keytypelen = 0; + int expect_paramfile = 0; const char *paramfile = NULL; + /* Treat the first part of gstr, and only that */ if (gstr == NULL) { - *pkey_type = EVP_PKEY_RSA; + /* + * Special case: when no string given, default to RSA and the + * key length given by |*pkeylen|. + */ + keytype = "RSA"; keylen = *pkeylen; } else if (gstr[0] >= '0' && gstr[0] <= '9') { - *pkey_type = EVP_PKEY_RSA; - keylen = atol(gstr); - *pkeylen = keylen; - } else if (strncmp(gstr, "param:", 6) == 0) { - paramfile = gstr + 6; + /* Special case: only keylength given from string, so default to RSA */ + keytype = "RSA"; + /* The second part treatment will do the rest */ } else { const char *p = strchr(gstr, ':'); int len; - ENGINE *tmpeng; - const EVP_PKEY_ASN1_METHOD *ameth; if (p != NULL) len = p - gstr; else len = strlen(gstr); - /* - * The lookup of a the string will cover all engines so keep a note - * of the implementation. - */ - ameth = EVP_PKEY_asn1_find_str(&tmpeng, gstr, len); - - if (ameth == NULL) { - BIO_printf(bio_err, "Unknown algorithm %.*s\n", len, gstr); - return NULL; - } - - EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL, ameth); -#ifndef OPENSSL_NO_ENGINE - ENGINE_finish(tmpeng); -#endif - if (*pkey_type == EVP_PKEY_RSA) { - if (p != NULL) { - keylen = atol(p + 1); - *pkeylen = keylen; - } else { - keylen = *pkeylen; + if (strncmp(gstr, "param", len) == 0) { + expect_paramfile = 1; + if (p == NULL) { + BIO_printf(bio_err, + "Parameter file requested but no path given: %s\n", + gstr); + return NULL; } - } else if (p != NULL) { - paramfile = p + 1; + } else { + keytype = gstr; + keytypelen = len; } + + if (p != NULL) + gstr = gstr + len + 1; + else + gstr = NULL; + } + + /* Treat the second part of gstr, if there is one */ + if (gstr != NULL) { + /* If the second part starts with a digit, we assume it's a size */ + if (!expect_paramfile && gstr[0] >= '0' && gstr[0] <= '9') + keylen = atol(gstr); + else + paramfile = gstr; } if (paramfile != NULL) { pbio = BIO_new_file(paramfile, "r"); if (pbio == NULL) { - BIO_printf(bio_err, "Can't open parameter file %s\n", paramfile); + BIO_printf(bio_err, "Cannot open parameter file %s\n", paramfile); return NULL; } param = PEM_read_bio_Parameters(pbio, NULL); @@ -1532,62 +1581,83 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr, BIO_printf(bio_err, "Error reading parameter file %s\n", paramfile); return NULL; } - if (*pkey_type == -1) { - *pkey_type = EVP_PKEY_id(param); - } else if (*pkey_type != EVP_PKEY_base_id(param)) { - BIO_printf(bio_err, "Key Type does not match parameters\n"); - EVP_PKEY_free(param); - return NULL; + if (keytype == NULL) { + keytype = EVP_PKEY_get0_type_name(param); + if (keytype == NULL) { + EVP_PKEY_free(param); + BIO_puts(bio_err, "Unable to determine key type\n"); + return NULL; + } } } - if (palgnam != NULL) { - const EVP_PKEY_ASN1_METHOD *ameth; - ENGINE *tmpeng; - const char *anam; + if (keytypelen > 0) + *pkeytype = OPENSSL_strndup(keytype, keytypelen); + else + *pkeytype = OPENSSL_strdup(keytype); - ameth = EVP_PKEY_asn1_find(&tmpeng, *pkey_type); - if (ameth == NULL) { - BIO_puts(bio_err, "Internal error: can't find key algorithm\n"); - return NULL; - } - EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth); - *palgnam = OPENSSL_strdup(anam); -#ifndef OPENSSL_NO_ENGINE - ENGINE_finish(tmpeng); -#endif + if (*pkeytype == NULL) { + BIO_printf(bio_err, "Out of memory\n"); + EVP_PKEY_free(param); + return NULL; } + if (keylen >= 0) + *pkeylen = keylen; + if (param != NULL) { - gctx = EVP_PKEY_CTX_new(param, keygen_engine); - *pkeylen = EVP_PKEY_bits(param); + if (!EVP_PKEY_is_a(param, *pkeytype)) { + BIO_printf(bio_err, "Key type does not match parameters\n"); + EVP_PKEY_free(param); + return NULL; + } + + if (keygen_engine != NULL) + gctx = EVP_PKEY_CTX_new(param, keygen_engine); + else + gctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), + param, app_get0_propq()); + *pkeylen = EVP_PKEY_get_bits(param); EVP_PKEY_free(param); } else { - gctx = EVP_PKEY_CTX_new_id(*pkey_type, keygen_engine); + if (keygen_engine != NULL) { + int pkey_id = get_legacy_pkey_id(app_get0_libctx(), *pkeytype, + keygen_engine); + + if (pkey_id != NID_undef) + gctx = EVP_PKEY_CTX_new_id(pkey_id, keygen_engine); + } else { + gctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(), + *pkeytype, app_get0_propq()); + } } if (gctx == NULL) { BIO_puts(bio_err, "Error allocating keygen context\n"); - ERR_print_errors(bio_err); return NULL; } if (EVP_PKEY_keygen_init(gctx) <= 0) { BIO_puts(bio_err, "Error initializing keygen context\n"); - ERR_print_errors(bio_err); EVP_PKEY_CTX_free(gctx); return NULL; } -#ifndef OPENSSL_NO_RSA - if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) { - if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) { - BIO_puts(bio_err, "Error setting RSA keysize\n"); - ERR_print_errors(bio_err); + if (keylen == -1 && (EVP_PKEY_CTX_is_a(gctx, "RSA") + || EVP_PKEY_CTX_is_a(gctx, "RSA-PSS"))) + keylen = *pkeylen; + + if (keylen != -1) { + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t bits = keylen; + + params[0] = + OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_BITS, &bits); + if (EVP_PKEY_CTX_set_params(gctx, params) <= 0) { + BIO_puts(bio_err, "Error setting keysize\n"); EVP_PKEY_CTX_free(gctx); return NULL; } } -#endif return gctx; } @@ -1610,70 +1680,3 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx) (void)BIO_flush(b); return 1; } - -static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, - const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) -{ - EVP_PKEY_CTX *pkctx = NULL; - int i, def_nid; - - if (ctx == NULL) - return 0; - /* - * EVP_PKEY_get_default_digest_nid() returns 2 if the digest is mandatory - * for this algorithm. - */ - if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) == 2 - && def_nid == NID_undef) { - /* The signing algorithm requires there to be no digest */ - md = NULL; - } - if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey)) - return 0; - for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { - char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); - if (pkey_ctrl_string(pkctx, sigopt) <= 0) { - BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt); - ERR_print_errors(bio_err); - return 0; - } - } - return 1; -} - -int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md, - STACK_OF(OPENSSL_STRING) *sigopts) -{ - int rv; - EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - - rv = do_sign_init(mctx, pkey, md, sigopts); - if (rv > 0) - rv = X509_sign_ctx(x, mctx); - EVP_MD_CTX_free(mctx); - return rv > 0 ? 1 : 0; -} - -int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, - STACK_OF(OPENSSL_STRING) *sigopts) -{ - int rv; - EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - rv = do_sign_init(mctx, pkey, md, sigopts); - if (rv > 0) - rv = X509_REQ_sign_ctx(x, mctx); - EVP_MD_CTX_free(mctx); - return rv > 0 ? 1 : 0; -} - -int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, - STACK_OF(OPENSSL_STRING) *sigopts) -{ - int rv; - EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - rv = do_sign_init(mctx, pkey, md, sigopts); - if (rv > 0) - rv = X509_CRL_sign_ctx(x, mctx); - EVP_MD_CTX_free(mctx); - return rv > 0 ? 1 : 0; -} diff --git a/apps/rsa.c b/apps/rsa.c index aeda917cc768..0da342c38f2c 100644 --- a/apps/rsa.c +++ b/apps/rsa.c @@ -1,13 +1,17 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 */ +/* Necessary for legacy RSA public key export */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include <openssl/opensslconf.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -21,60 +25,119 @@ #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/bn.h> +#include <openssl/encoder.h> + +/* + * This include is to get OSSL_KEYMGMT_SELECT_*, which feels a bit + * much just for those macros... they might serve better as EVP macros. + */ +#include <openssl/core_dispatch.h> + +#ifndef OPENSSL_NO_RC4 +# define DEFAULT_PVK_ENCR_STRENGTH 2 +#else +# define DEFAULT_PVK_ENCR_STRENGTH 0 +#endif typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_PASSOUT, OPT_PASSIN, OPT_RSAPUBKEY_IN, OPT_RSAPUBKEY_OUT, /* Do not change the order here; see case statements below */ OPT_PVK_NONE, OPT_PVK_WEAK, OPT_PVK_STRONG, - OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_CHECK, OPT_CIPHER + OPT_NOOUT, OPT_TEXT, OPT_MODULUS, OPT_CHECK, OPT_CIPHER, + OPT_PROV_ENUM, OPT_TRADITIONAL } OPTION_CHOICE; const OPTIONS rsa_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'f', "Input format, one of DER PEM"}, - {"outform", OPT_OUTFORM, 'f', "Output format, one of DER PEM PVK"}, + {"check", OPT_CHECK, '-', "Verify key consistency"}, + {"", OPT_CIPHER, '-', "Any supported cipher"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), {"in", OPT_IN, 's', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, + {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)"}, {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"}, - {"pubout", OPT_PUBOUT, '-', "Output a public key"}, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, {"RSAPublicKey_in", OPT_RSAPUBKEY_IN, '-', "Input is an RSAPublicKey"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'f', "Output format, one of DER PEM PVK"}, + {"pubout", OPT_PUBOUT, '-', "Output a public key"}, {"RSAPublicKey_out", OPT_RSAPUBKEY_OUT, '-', "Output is an RSAPublicKey"}, + {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, {"noout", OPT_NOOUT, '-', "Don't print key out"}, {"text", OPT_TEXT, '-', "Print the key in text"}, {"modulus", OPT_MODULUS, '-', "Print the RSA key modulus"}, - {"check", OPT_CHECK, '-', "Verify key consistency"}, - {"", OPT_CIPHER, '-', "Any supported cipher"}, -#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) + {"traditional", OPT_TRADITIONAL, '-', + "Use traditional format for private keys"}, + +#ifndef OPENSSL_NO_RC4 + OPT_SECTION("PVK"), {"pvk-strong", OPT_PVK_STRONG, '-', "Enable 'Strong' PVK encoding level (default)"}, {"pvk-weak", OPT_PVK_WEAK, '-', "Enable 'Weak' PVK encoding level"}, {"pvk-none", OPT_PVK_NONE, '-', "Don't enforce PVK encoding"}, #endif -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + + OPT_PROV_OPTIONS, {NULL} }; +static int try_legacy_encoding(EVP_PKEY *pkey, int outformat, int pubout, + BIO *out) +{ + int ret = 0; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + const RSA *rsa = EVP_PKEY_get0_RSA(pkey); + + if (rsa == NULL) + return 0; + + if (outformat == FORMAT_ASN1) { + if (pubout == 2) + ret = i2d_RSAPublicKey_bio(out, rsa) > 0; + else + ret = i2d_RSA_PUBKEY_bio(out, rsa) > 0; + } else if (outformat == FORMAT_PEM) { + if (pubout == 2) + ret = PEM_write_bio_RSAPublicKey(out, rsa) > 0; + else + ret = PEM_write_bio_RSA_PUBKEY(out, rsa) > 0; +# ifndef OPENSSL_NO_DSA + } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { + ret = i2b_PublicKey_bio(out, pkey) > 0; +# endif + } +#endif + + return ret; +} + int rsa_main(int argc, char **argv) { ENGINE *e = NULL; BIO *out = NULL; - RSA *rsa = NULL; - const EVP_CIPHER *enc = NULL; - char *infile = NULL, *outfile = NULL, *prog; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *pctx; + EVP_CIPHER *enc = NULL; + char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog; char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL; - int i, private = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, check = 0; + int private = 0; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, check = 0; int noout = 0, modulus = 0, pubin = 0, pubout = 0, ret = 1; -#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) - int pvk_encr = 2; -#endif + int pvk_encr = DEFAULT_PVK_ENCR_STRENGTH; OPTION_CHOICE o; + int traditional = 0; + const char *output_type = NULL; + const char *output_structure = NULL; + int selection = 0; + OSSL_ENCODER_CTX *ectx = NULL; prog = opt_init(argc, argv, rsa_options); while ((o = opt_next()) != OPT_EOF) { @@ -126,9 +189,7 @@ int rsa_main(int argc, char **argv) case OPT_PVK_STRONG: /* pvk_encr:= 2 */ case OPT_PVK_WEAK: /* pvk_encr:= 1 */ case OPT_PVK_NONE: /* pvk_encr:= 0 */ -#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) pvk_encr = (o - OPT_PVK_NONE); -#endif break; case OPT_NOOUT: noout = 1; @@ -143,15 +204,27 @@ int rsa_main(int argc, char **argv) check = 1; break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &enc)) - goto opthelp; + ciphername = opt_unknown(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; + case OPT_TRADITIONAL: + traditional = 1; break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (ciphername != NULL) { + if (!opt_cipher(ciphername, &enc)) + goto opthelp; + } private = (text && !pubin) || (!pubout && !noout) ? 1 : 0; if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { @@ -163,34 +236,31 @@ int rsa_main(int argc, char **argv) goto end; } - { - EVP_PKEY *pkey; + if (pubin) { + int tmpformat = FORMAT_UNDEF; - if (pubin) { - int tmpformat = -1; - if (pubin == 2) { - if (informat == FORMAT_PEM) - tmpformat = FORMAT_PEMRSA; - else if (informat == FORMAT_ASN1) - tmpformat = FORMAT_ASN1RSA; - } else { - tmpformat = informat; - } - - pkey = load_pubkey(infile, tmpformat, 1, passin, e, "Public Key"); + if (pubin == 2) { + if (informat == FORMAT_PEM) + tmpformat = FORMAT_PEMRSA; + else if (informat == FORMAT_ASN1) + tmpformat = FORMAT_ASN1RSA; } else { - pkey = load_key(infile, informat, 1, passin, e, "Private Key"); + tmpformat = informat; } - if (pkey != NULL) - rsa = EVP_PKEY_get1_RSA(pkey); - EVP_PKEY_free(pkey); + pkey = load_pubkey(infile, tmpformat, 1, passin, e, "public key"); + } else { + pkey = load_key(infile, informat, 1, passin, e, "private key"); } - if (rsa == NULL) { + if (pkey == NULL) { ERR_print_errors(bio_err); goto end; } + if (!EVP_PKEY_is_a(pkey, "RSA") && !EVP_PKEY_is_a(pkey, "RSA-PSS")) { + BIO_printf(bio_err, "Not an RSA key\n"); + goto end; + } out = bio_open_owner(outfile, outformat, private); if (out == NULL) @@ -198,7 +268,8 @@ int rsa_main(int argc, char **argv) if (text) { assert(pubin || private); - if (!RSA_print(out, rsa, 0)) { + if ((pubin && EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0) + || (!pubin && EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)) { perror(outfile); ERR_print_errors(bio_err); goto end; @@ -206,30 +277,34 @@ int rsa_main(int argc, char **argv) } if (modulus) { - const BIGNUM *n; - RSA_get0_key(rsa, &n, NULL, NULL); + BIGNUM *n = NULL; + + /* Every RSA key has an 'n' */ + EVP_PKEY_get_bn_param(pkey, "n", &n); BIO_printf(out, "Modulus="); BN_print(out, n); BIO_printf(out, "\n"); + BN_free(n); } if (check) { - int r = RSA_check_key_ex(rsa, NULL); + int r; + + pctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (pctx == NULL) { + BIO_printf(bio_err, "RSA unable to create PKEY context\n"); + ERR_print_errors(bio_err); + goto end; + } + r = EVP_PKEY_check(pctx); + EVP_PKEY_CTX_free(pctx); if (r == 1) { BIO_printf(out, "RSA key ok\n"); } else if (r == 0) { - unsigned long err; - - while ((err = ERR_peek_error()) != 0 && - ERR_GET_LIB(err) == ERR_LIB_RSA && - ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY_EX && - ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { - BIO_printf(out, "RSA key error: %s\n", - ERR_reason_error_string(err)); - ERR_get_error(); /* remove err from error stack */ - } - } else if (r == -1) { + BIO_printf(bio_err, "RSA key not ok\n"); + ERR_print_errors(bio_err); + } else if (r < 0) { ERR_print_errors(bio_err); goto end; } @@ -240,71 +315,100 @@ int rsa_main(int argc, char **argv) goto end; } BIO_printf(bio_err, "writing RSA key\n"); + + /* Choose output type for the format */ if (outformat == FORMAT_ASN1) { - if (pubout || pubin) { - if (pubout == 2) - i = i2d_RSAPublicKey_bio(out, rsa); - else - i = i2d_RSA_PUBKEY_bio(out, rsa); - } else { - assert(private); - i = i2d_RSAPrivateKey_bio(out, rsa); - } + output_type = "DER"; } else if (outformat == FORMAT_PEM) { + output_type = "PEM"; + } else if (outformat == FORMAT_MSBLOB) { + output_type = "MSBLOB"; + } else if (outformat == FORMAT_PVK) { + if (pubin) { + BIO_printf(bio_err, "PVK form impossible with public key input\n"); + goto end; + } + output_type = "PVK"; + } else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + + /* Select what you want in the output */ + if (pubout || pubin) { + selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + } else { + assert(private); + selection = (OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS); + } + + /* For DER based output, select the desired output structure */ + if (outformat == FORMAT_ASN1 || outformat == FORMAT_PEM) { if (pubout || pubin) { if (pubout == 2) - i = PEM_write_bio_RSAPublicKey(out, rsa); + output_structure = "pkcs1"; /* "type-specific" would work too */ else - i = PEM_write_bio_RSA_PUBKEY(out, rsa); + output_structure = "SubjectPublicKeyInfo"; } else { assert(private); - i = PEM_write_bio_RSAPrivateKey(out, rsa, - enc, NULL, 0, NULL, passout); + if (traditional) + output_structure = "pkcs1"; /* "type-specific" would work too */ + else + output_structure = "PrivateKeyInfo"; } -#ifndef OPENSSL_NO_DSA - } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { - EVP_PKEY *pk; - pk = EVP_PKEY_new(); - if (pk == NULL) - goto end; + } - EVP_PKEY_set1_RSA(pk, rsa); - if (outformat == FORMAT_PVK) { - if (pubin) { - BIO_printf(bio_err, "PVK form impossible with public key input\n"); - EVP_PKEY_free(pk); - goto end; - } - assert(private); -# ifdef OPENSSL_NO_RC4 - BIO_printf(bio_err, "PVK format not supported\n"); - EVP_PKEY_free(pk); + /* Now, perform the encoding */ + ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, + output_type, output_structure, + NULL); + if (OSSL_ENCODER_CTX_get_num_encoders(ectx) == 0) { + if ((!pubout && !pubin) + || !try_legacy_encoding(pkey, outformat, pubout, out)) + BIO_printf(bio_err, "%s format not supported\n", output_type); + else + ret = 0; + goto end; + } + + /* Passphrase setup */ + if (enc != NULL) + OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL); + + /* Default passphrase prompter */ + if (enc != NULL || outformat == FORMAT_PVK) { + OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL); + if (passout != NULL) + /* When passout given, override the passphrase prompter */ + OSSL_ENCODER_CTX_set_passphrase(ectx, + (const unsigned char *)passout, + strlen(passout)); + } + + /* PVK is a bit special... */ + if (outformat == FORMAT_PVK) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_int("encrypt-level", &pvk_encr); + if (!OSSL_ENCODER_CTX_set_params(ectx, params)) { + BIO_printf(bio_err, "invalid PVK encryption level\n"); goto end; -# else - i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); -# endif - } else if (pubin || pubout) { - i = i2b_PublicKey_bio(out, pk); - } else { - assert(private); - i = i2b_PrivateKey_bio(out, pk); } - EVP_PKEY_free(pk); -#endif - } else { - BIO_printf(bio_err, "bad output format specified for outfile\n"); - goto end; } - if (i <= 0) { + + if (!OSSL_ENCODER_to_bio(ectx, out)) { BIO_printf(bio_err, "unable to write key\n"); ERR_print_errors(bio_err); - } else { - ret = 0; + goto end; } + ret = 0; end: + OSSL_ENCODER_CTX_free(ectx); release_engine(e); BIO_free_all(out); - RSA_free(rsa); + EVP_PKEY_free(pkey); + EVP_CIPHER_free(enc); OPENSSL_free(passin); OPENSSL_free(passout); return ret; diff --git a/apps/rsautl.c b/apps/rsautl.c index 0c0fa8eba30a..df29069bc1f4 100644 --- a/apps/rsautl.c +++ b/apps/rsautl.c @@ -1,13 +1,14 @@ /* - * Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/opensslconf.h> + #include "apps.h" #include "progs.h" #include <string.h> @@ -25,40 +26,46 @@ #define KEY_CERT 3 typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_ENGINE, OPT_IN, OPT_OUT, OPT_ASN1PARSE, OPT_HEXDUMP, - OPT_RAW, OPT_OAEP, OPT_SSL, OPT_PKCS, OPT_X931, + OPT_RSA_RAW, OPT_OAEP, OPT_PKCS, OPT_X931, OPT_SIGN, OPT_VERIFY, OPT_REV, OPT_ENCRYPT, OPT_DECRYPT, OPT_PUBIN, OPT_CERTIN, OPT_INKEY, OPT_PASSIN, OPT_KEYFORM, - OPT_R_ENUM + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS rsautl_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"sign", OPT_SIGN, '-', "Sign with private key"}, + {"verify", OPT_VERIFY, '-', "Verify with public key"}, + {"encrypt", OPT_ENCRYPT, '-', "Encrypt with public key"}, + {"decrypt", OPT_DECRYPT, '-', "Decrypt with private key"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, {"inkey", OPT_INKEY, 's', "Input key"}, - {"keyform", OPT_KEYFORM, 'E', "Private key format - default PEM"}, + {"keyform", OPT_KEYFORM, 'E', "Private key format (ENGINE, other values ignored)"}, {"pubin", OPT_PUBIN, '-', "Input is an RSA public"}, {"certin", OPT_CERTIN, '-', "Input is a cert carrying an RSA public key"}, - {"ssl", OPT_SSL, '-', "Use SSL v2 padding"}, - {"raw", OPT_RAW, '-', "Use no padding"}, + {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"raw", OPT_RSA_RAW, '-', "Use no padding"}, {"pkcs", OPT_PKCS, '-', "Use PKCS#1 v1.5 padding (default)"}, + {"x931", OPT_X931, '-', "Use ANSI X9.31 padding"}, {"oaep", OPT_OAEP, '-', "Use PKCS#1 OAEP"}, - {"sign", OPT_SIGN, '-', "Sign with private key"}, - {"verify", OPT_VERIFY, '-', "Verify with public key"}, {"asn1parse", OPT_ASN1PARSE, '-', "Run output through asn1parse; useful with -verify"}, {"hexdump", OPT_HEXDUMP, '-', "Hex dump output"}, - {"x931", OPT_X931, '-', "Use ANSI X9.31 padding"}, - {"rev", OPT_REV, '-', "Reverse the order of the input buffer"}, - {"encrypt", OPT_ENCRYPT, '-', "Encrypt with public key"}, - {"decrypt", OPT_DECRYPT, '-', "Decrypt with private key"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + OPT_PROV_OPTIONS, {NULL} }; @@ -67,14 +74,15 @@ int rsautl_main(int argc, char **argv) BIO *in = NULL, *out = NULL; ENGINE *e = NULL; EVP_PKEY *pkey = NULL; - RSA *rsa = NULL; + EVP_PKEY_CTX *ctx = NULL; X509 *x; char *infile = NULL, *outfile = NULL, *keyfile = NULL; char *passinarg = NULL, *passin = NULL, *prog; char rsa_mode = RSA_VERIFY, key_type = KEY_PRIVKEY; unsigned char *rsa_in = NULL, *rsa_out = NULL, pad = RSA_PKCS1_PADDING; - int rsa_inlen, keyformat = FORMAT_PEM, keysize, ret = 1; - int rsa_outlen = 0, hexdump = 0, asn1parse = 0, need_priv = 0, rev = 0; + size_t rsa_inlen, rsa_outlen = 0; + int keyformat = FORMAT_UNDEF, keysize, ret = 1, rv; + int hexdump = 0, asn1parse = 0, need_priv = 0, rev = 0; OPTION_CHOICE o; prog = opt_init(argc, argv, rsautl_options); @@ -90,7 +98,7 @@ int rsautl_main(int argc, char **argv) ret = 0; goto end; case OPT_KEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PDE, &keyformat)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyformat)) goto opthelp; break; case OPT_IN: @@ -108,15 +116,12 @@ int rsautl_main(int argc, char **argv) case OPT_HEXDUMP: hexdump = 1; break; - case OPT_RAW: + case OPT_RSA_RAW: pad = RSA_NO_PADDING; break; case OPT_OAEP: pad = RSA_PKCS1_OAEP_PADDING; break; - case OPT_SSL: - pad = RSA_SSLV23_PADDING; - break; case OPT_PKCS: pad = RSA_PKCS1_PADDING; break; @@ -156,12 +161,21 @@ int rsautl_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; + if (!app_RAND_load()) + goto end; + if (need_priv && (key_type != KEY_PRIVKEY)) { BIO_printf(bio_err, "A private key is needed for this operation\n"); goto end; @@ -174,15 +188,15 @@ int rsautl_main(int argc, char **argv) switch (key_type) { case KEY_PRIVKEY: - pkey = load_key(keyfile, keyformat, 0, passin, e, "Private Key"); + pkey = load_key(keyfile, keyformat, 0, passin, e, "private key"); break; case KEY_PUBKEY: - pkey = load_pubkey(keyfile, keyformat, 0, NULL, e, "Public Key"); + pkey = load_pubkey(keyfile, keyformat, 0, NULL, e, "public key"); break; case KEY_CERT: - x = load_cert(keyfile, keyformat, "Certificate"); + x = load_cert(keyfile, FORMAT_UNDEF, "Certificate"); if (x) { pkey = X509_get_pubkey(x); X509_free(x); @@ -193,15 +207,6 @@ int rsautl_main(int argc, char **argv) if (pkey == NULL) return 1; - rsa = EVP_PKEY_get1_RSA(pkey); - EVP_PKEY_free(pkey); - - if (rsa == NULL) { - BIO_printf(bio_err, "Error getting RSA key\n"); - ERR_print_errors(bio_err); - goto end; - } - in = bio_open_default(infile, 'r', FORMAT_BINARY); if (in == NULL) goto end; @@ -209,48 +214,58 @@ int rsautl_main(int argc, char **argv) if (out == NULL) goto end; - keysize = RSA_size(rsa); + keysize = EVP_PKEY_get_size(pkey); rsa_in = app_malloc(keysize * 2, "hold rsa key"); rsa_out = app_malloc(keysize, "output rsa key"); + rsa_outlen = keysize; /* Read the input data */ - rsa_inlen = BIO_read(in, rsa_in, keysize * 2); - if (rsa_inlen < 0) { + rv = BIO_read(in, rsa_in, keysize * 2); + if (rv < 0) { BIO_printf(bio_err, "Error reading input Data\n"); goto end; } + rsa_inlen = rv; if (rev) { - int i; + size_t i; unsigned char ctmp; + for (i = 0; i < rsa_inlen / 2; i++) { ctmp = rsa_in[i]; rsa_in[i] = rsa_in[rsa_inlen - 1 - i]; rsa_in[rsa_inlen - 1 - i] = ctmp; } } - switch (rsa_mode) { + if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) + goto end; + + switch (rsa_mode) { case RSA_VERIFY: - rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + rv = EVP_PKEY_verify_recover_init(ctx) > 0 + && EVP_PKEY_CTX_set_rsa_padding(ctx, pad) > 0 + && EVP_PKEY_verify_recover(ctx, rsa_out, &rsa_outlen, + rsa_in, rsa_inlen) > 0; break; - case RSA_SIGN: - rsa_outlen = - RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + rv = EVP_PKEY_sign_init(ctx) > 0 + && EVP_PKEY_CTX_set_rsa_padding(ctx, pad) > 0 + && EVP_PKEY_sign(ctx, rsa_out, &rsa_outlen, rsa_in, rsa_inlen) > 0; break; - case RSA_ENCRYPT: - rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + rv = EVP_PKEY_encrypt_init(ctx) > 0 + && EVP_PKEY_CTX_set_rsa_padding(ctx, pad) > 0 + && EVP_PKEY_encrypt(ctx, rsa_out, &rsa_outlen, rsa_in, rsa_inlen) > 0; break; - case RSA_DECRYPT: - rsa_outlen = - RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + rv = EVP_PKEY_decrypt_init(ctx) > 0 + && EVP_PKEY_CTX_set_rsa_padding(ctx, pad) > 0 + && EVP_PKEY_decrypt(ctx, rsa_out, &rsa_outlen, rsa_in, rsa_inlen) > 0; break; } - if (rsa_outlen < 0) { + if (!rv) { BIO_printf(bio_err, "RSA operation error\n"); ERR_print_errors(bio_err); goto end; @@ -266,7 +281,8 @@ int rsautl_main(int argc, char **argv) BIO_write(out, rsa_out, rsa_outlen); } end: - RSA_free(rsa); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); release_engine(e); BIO_free(in); BIO_free_all(out); diff --git a/apps/s_client.c b/apps/s_client.c index 00effc80375a..a9142386428d 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -1,8 +1,8 @@ /* - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2005 Nokia. All rights reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -38,10 +38,8 @@ typedef unsigned int u_int; #include <openssl/rand.h> #include <openssl/ocsp.h> #include <openssl/bn.h> +#include <openssl/trace.h> #include <openssl/async.h> -#ifndef OPENSSL_NO_SRP -# include <openssl/srp.h> -#endif #ifndef OPENSSL_NO_CT # include <openssl/ct.h> #endif @@ -91,27 +89,6 @@ static int restore_errno(void) return ret; } -static void do_ssl_shutdown(SSL *ssl) -{ - int ret; - - do { - /* We only do unidirectional shutdown */ - ret = SSL_shutdown(ssl); - if (ret < 0) { - switch (SSL_get_error(ssl, ret)) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_ASYNC: - case SSL_ERROR_WANT_ASYNC_JOB: - /* We just do busy waiting. Nothing clever */ - continue; - } - ret = 0; - } - } while (ret < 0); -} - /* Default PSK identity and key */ static char *psk_identity = "Client_identity"; @@ -258,117 +235,6 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) return SSL_TLSEXT_ERR_OK; } -#ifndef OPENSSL_NO_SRP - -/* This is a context that we pass to all callbacks */ -typedef struct srp_arg_st { - char *srppassin; - char *srplogin; - int msg; /* copy from c_msg */ - int debug; /* copy from c_debug */ - int amp; /* allow more groups */ - int strength; /* minimal size for N */ -} SRP_ARG; - -# define SRP_NUMBER_ITERATIONS_FOR_PRIME 64 - -static int srp_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g) -{ - BN_CTX *bn_ctx = BN_CTX_new(); - BIGNUM *p = BN_new(); - BIGNUM *r = BN_new(); - int ret = - g != NULL && N != NULL && bn_ctx != NULL && BN_is_odd(N) && - BN_is_prime_ex(N, SRP_NUMBER_ITERATIONS_FOR_PRIME, bn_ctx, NULL) == 1 && - p != NULL && BN_rshift1(p, N) && - /* p = (N-1)/2 */ - BN_is_prime_ex(p, SRP_NUMBER_ITERATIONS_FOR_PRIME, bn_ctx, NULL) == 1 && - r != NULL && - /* verify g^((N-1)/2) == -1 (mod N) */ - BN_mod_exp(r, g, p, N, bn_ctx) && - BN_add_word(r, 1) && BN_cmp(r, N) == 0; - - BN_free(r); - BN_free(p); - BN_CTX_free(bn_ctx); - return ret; -} - -/*- - * This callback is used here for two purposes: - * - extended debugging - * - making some primality tests for unknown groups - * The callback is only called for a non default group. - * - * An application does not need the call back at all if - * only the standard groups are used. In real life situations, - * client and server already share well known groups, - * thus there is no need to verify them. - * Furthermore, in case that a server actually proposes a group that - * is not one of those defined in RFC 5054, it is more appropriate - * to add the group to a static list and then compare since - * primality tests are rather cpu consuming. - */ - -static int ssl_srp_verify_param_cb(SSL *s, void *arg) -{ - SRP_ARG *srp_arg = (SRP_ARG *)arg; - BIGNUM *N = NULL, *g = NULL; - - if (((N = SSL_get_srp_N(s)) == NULL) || ((g = SSL_get_srp_g(s)) == NULL)) - return 0; - if (srp_arg->debug || srp_arg->msg || srp_arg->amp == 1) { - BIO_printf(bio_err, "SRP parameters:\n"); - BIO_printf(bio_err, "\tN="); - BN_print(bio_err, N); - BIO_printf(bio_err, "\n\tg="); - BN_print(bio_err, g); - BIO_printf(bio_err, "\n"); - } - - if (SRP_check_known_gN_param(g, N)) - return 1; - - if (srp_arg->amp == 1) { - if (srp_arg->debug) - BIO_printf(bio_err, - "SRP param N and g are not known params, going to check deeper.\n"); - - /* - * The srp_moregroups is a real debugging feature. Implementors - * should rather add the value to the known ones. The minimal size - * has already been tested. - */ - if (BN_num_bits(g) <= BN_BITS && srp_Verify_N_and_g(N, g)) - return 1; - } - BIO_printf(bio_err, "SRP param N and g rejected.\n"); - return 0; -} - -# define PWD_STRLEN 1024 - -static char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg) -{ - SRP_ARG *srp_arg = (SRP_ARG *)arg; - char *pass = app_malloc(PWD_STRLEN + 1, "SRP password buffer"); - PW_CB_DATA cb_tmp; - int l; - - cb_tmp.password = (char *)srp_arg->srppassin; - cb_tmp.prompt_info = "SRP user"; - if ((l = password_callback(pass, PWD_STRLEN, 0, &cb_tmp)) < 0) { - BIO_printf(bio_err, "Can't read Password\n"); - OPENSSL_free(pass); - return NULL; - } - *(pass + l) = '\0'; - - return pass; -} - -#endif - #ifndef OPENSSL_NO_NEXTPROTONEG /* This the context that we pass to next_proto_cb */ typedef struct tlsextnextprotoctx_st { @@ -563,7 +429,7 @@ static int tlsa_import_rrset(SSL *con, STACK_OF(OPENSSL_STRING) *rrset) } typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_BIND, OPT_UNIX, OPT_XMPPHOST, OPT_VERIFY, OPT_NAMEOPT, OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN, @@ -581,35 +447,56 @@ typedef enum OPTION_choice { OPT_SSL3, OPT_SSL_CONFIG, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS, - OPT_CERT_CHAIN, OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, OPT_VERIFYCAPATH, - OPT_KEY, OPT_RECONNECT, OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE, - OPT_CHAINCAFILE, OPT_VERIFYCAFILE, OPT_NEXTPROTONEG, OPT_ALPN, + OPT_CERT_CHAIN, OPT_KEY, OPT_RECONNECT, OPT_BUILD_CHAIN, + OPT_NEXTPROTONEG, OPT_ALPN, + OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, OPT_VERIFYCAPATH, + OPT_CAFILE, OPT_NOCAFILE, OPT_CHAINCAFILE, OPT_VERIFYCAFILE, + OPT_CASTORE, OPT_NOCASTORE, OPT_CHAINCASTORE, OPT_VERIFYCASTORE, OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME, OPT_NOSERVERNAME, OPT_ASYNC, OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_PROTOHOST, OPT_MAXFRAGLEN, OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, OPT_KEYLOG_FILE, OPT_EARLY_DATA, OPT_REQCAFILE, OPT_V_ENUM, OPT_X_ENUM, - OPT_S_ENUM, - OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_DANE_TLSA_DOMAIN, + OPT_S_ENUM, OPT_IGNORE_UNEXPECTED_EOF, + OPT_FALLBACKSCSV, OPT_NOCMDS, OPT_PROXY, OPT_PROXY_USER, OPT_PROXY_PASS, + OPT_DANE_TLSA_DOMAIN, #ifndef OPENSSL_NO_CT OPT_CT, OPT_NOCT, OPT_CTLOG_FILE, #endif OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME, OPT_ENABLE_PHA, OPT_SCTP_LABEL_BUG, - OPT_R_ENUM + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS s_client_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [host:port]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, + {"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's', + "Specify engine to be used for client certificate operations"}, +#endif + {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified section for SSL_CTX configuration"}, +#ifndef OPENSSL_NO_CT + {"ct", OPT_CT, '-', "Request and parse SCTs (also enables OCSP stapling)"}, + {"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"}, + {"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"}, +#endif + + OPT_SECTION("Network"), {"host", OPT_HOST, 's', "Use -connect instead"}, {"port", OPT_PORT, 'p', "Use -connect instead"}, {"connect", OPT_CONNECT, 's', - "TCP/IP where to connect (default is :" PORT ")"}, + "TCP/IP where to connect; default: " PORT ")"}, {"bind", OPT_BIND, 's', "bind local address for connection"}, {"proxy", OPT_PROXY, 's', "Connect to via specified proxy to the real server"}, + {"proxy_user", OPT_PROXY_USER, 's', "UserID for proxy authentication"}, + {"proxy_pass", OPT_PROXY_PASS, 's', "Proxy authentication password source"}, #ifdef AF_UNIX {"unix", OPT_UNIX, 's', "Connect over the specified Unix-domain socket"}, #endif @@ -617,20 +504,38 @@ const OPTIONS s_client_options[] = { #ifdef AF_INET6 {"6", OPT_6, '-', "Use IPv6 only"}, #endif - {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"}, - {"cert", OPT_CERT, '<', "Certificate file to use, PEM format assumed"}, + {"maxfraglen", OPT_MAXFRAGLEN, 'p', + "Enable Maximum Fragment Length Negotiation (len values: 512, 1024, 2048 and 4096)"}, + {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, + {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', + "Size used to split data for encrypt pipelines"}, + {"max_pipelines", OPT_MAX_PIPELINES, 'p', + "Maximum number of encrypt/decrypt pipelines to be used"}, + {"read_buf", OPT_READ_BUF, 'p', + "Default read buffer size to be used for connections"}, + {"fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV"}, + + OPT_SECTION("Identity"), + {"cert", OPT_CERT, '<', "Client certificate file to use"}, {"certform", OPT_CERTFORM, 'F', - "Certificate format (PEM or DER) PEM default"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, - {"key", OPT_KEY, 's', "Private key file to use, if not in -cert file"}, - {"keyform", OPT_KEYFORM, 'E', "Key format (PEM, DER or engine) PEM default"}, - {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, + "Client certificate file format (PEM/DER/P12); has no effect"}, + {"cert_chain", OPT_CERT_CHAIN, '<', + "Client certificate chain file (in PEM format)"}, + {"build_chain", OPT_BUILD_CHAIN, '-', "Build client certificate chain"}, + {"key", OPT_KEY, 's', "Private key file to use; default: -cert file"}, + {"keyform", OPT_KEYFORM, 'E', "Key format (ENGINE, other values ignored)"}, + {"pass", OPT_PASS, 's', "Private key and cert file pass phrase source"}, + {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"}, + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, + {"CAstore", OPT_CASTORE, ':', "URI to store of CA's"}, {"no-CAfile", OPT_NOCAFILE, '-', "Do not load the default certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', "Do not load certificates from the default certificates directory"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store"}, {"requestCAfile", OPT_REQCAFILE, '<', "PEM format file of CA names to send to the server"}, {"dane_tlsa_domain", OPT_DANE_TLSA_DOMAIN, 's', "DANE TLSA base domain"}, @@ -638,16 +543,19 @@ const OPTIONS s_client_options[] = { "DANE TLSA rrdata presentation form"}, {"dane_ee_no_namechecks", OPT_DANE_EE_NO_NAME, '-', "Disable name checks when matching DANE-EE(3) TLSA records"}, + {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity"}, + {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, + {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"}, + {"name", OPT_PROTOHOST, 's', + "Hostname to use for \"-starttls lmtp\", \"-starttls smtp\" or \"-starttls xmpp[-server]\""}, + + OPT_SECTION("Session"), {"reconnect", OPT_RECONNECT, '-', "Drop and re-make the connection with the same Session-ID"}, - {"showcerts", OPT_SHOWCERTS, '-', - "Show all certificates sent by the server"}, - {"debug", OPT_DEBUG, '-', "Extra output"}, - {"msg", OPT_MSG, '-', "Show protocol messages"}, - {"msgfile", OPT_MSGFILE, '>', - "File to send output of -msg or -trace, instead of stdout"}, - {"nbio_test", OPT_NBIO_TEST, '-', "More ssl protocol testing"}, - {"state", OPT_STATE, '-', "Print the ssl states"}, + {"sess_out", OPT_SESS_OUT, '>', "File to write SSL session to"}, + {"sess_in", OPT_SESS_IN, '<', "File to read SSL session from"}, + + OPT_SECTION("Input/Output"), {"crlf", OPT_CRLF, '-', "Convert LF from terminal into CRLF"}, {"quiet", OPT_QUIET, '-', "No s_client output"}, {"ign_eof", OPT_IGN_EOF, '-', "Ignore input eof (default when -quiet)"}, @@ -656,47 +564,35 @@ const OPTIONS s_client_options[] = { "Use the appropriate STARTTLS command before starting TLS"}, {"xmpphost", OPT_XMPPHOST, 's', "Alias of -name option for \"-starttls xmpp[-server]\""}, - OPT_R_OPTIONS, - {"sess_out", OPT_SESS_OUT, '>', "File to write SSL session to"}, - {"sess_in", OPT_SESS_IN, '<', "File to read SSL session from"}, -#ifndef OPENSSL_NO_SRTP - {"use_srtp", OPT_USE_SRTP, 's', - "Offer SRTP key management with a colon-separated profile list"}, -#endif - {"keymatexport", OPT_KEYMATEXPORT, 's', - "Export keying material using label"}, - {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', - "Export len bytes of keying material (default 20)"}, - {"maxfraglen", OPT_MAXFRAGLEN, 'p', - "Enable Maximum Fragment Length Negotiation (len values: 512, 1024, 2048 and 4096)"}, - {"fallback_scsv", OPT_FALLBACKSCSV, '-', "Send the fallback SCSV"}, - {"name", OPT_PROTOHOST, 's', - "Hostname to use for \"-starttls lmtp\", \"-starttls smtp\" or \"-starttls xmpp[-server]\""}, - {"CRL", OPT_CRL, '<', "CRL file to use"}, - {"crl_download", OPT_CRL_DOWNLOAD, '-', "Download CRL from distribution points"}, - {"CRLform", OPT_CRLFORM, 'F', "CRL format (PEM or DER) PEM is default"}, - {"verify_return_error", OPT_VERIFY_RET_ERROR, '-', - "Close connection on verification error"}, - {"verify_quiet", OPT_VERIFY_QUIET, '-', "Restrict verify output to errors"}, {"brief", OPT_BRIEF, '-', "Restrict output to brief summary of connection parameters"}, {"prexit", OPT_PREXIT, '-', "Print session information when the program exits"}, + + OPT_SECTION("Debug"), + {"showcerts", OPT_SHOWCERTS, '-', + "Show all certificates sent by the server"}, + {"debug", OPT_DEBUG, '-', "Extra output"}, + {"msg", OPT_MSG, '-', "Show protocol messages"}, + {"msgfile", OPT_MSGFILE, '>', + "File to send output of -msg or -trace, instead of stdout"}, + {"nbio_test", OPT_NBIO_TEST, '-', "More ssl protocol testing"}, + {"state", OPT_STATE, '-', "Print the ssl states"}, + {"keymatexport", OPT_KEYMATEXPORT, 's', + "Export keying material using label"}, + {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', + "Export len bytes of keying material; default 20"}, {"security_debug", OPT_SECURITY_DEBUG, '-', "Enable security debug messages"}, {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-', "Output more security debug output"}, - {"cert_chain", OPT_CERT_CHAIN, '<', - "Certificate chain file (in PEM format)"}, - {"chainCApath", OPT_CHAINCAPATH, '/', - "Use dir as certificate store path to build CA certificate chain"}, - {"verifyCApath", OPT_VERIFYCAPATH, '/', - "Use dir as certificate store path to verify CA certificate"}, - {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, - {"chainCAfile", OPT_CHAINCAFILE, '<', - "CA file for certificate chain (PEM format)"}, - {"verifyCAfile", OPT_VERIFYCAFILE, '<', - "CA file for certificate verification (PEM format)"}, +#ifndef OPENSSL_NO_SSL_TRACE + {"trace", OPT_TRACE, '-', "Show trace output of protocol messages"}, +#endif +#ifdef WATT32 + {"wdebug", OPT_WDEBUG, '-', "WATT-32 tcp debugging"}, +#endif + {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, {"nocommands", OPT_NOCMDS, '-', "Do not use interactive command letters"}, {"servername", OPT_SERVERNAME, 's', "Set TLS extension servername (SNI) in ClientHello (default)"}, @@ -704,6 +600,8 @@ const OPTIONS s_client_options[] = { "Do not send the server name (SNI) extension in the ClientHello"}, {"tlsextdebug", OPT_TLSEXTDEBUG, '-', "Hex dump of all TLS extensions received"}, + {"ignore_unexpected_eof", OPT_IGNORE_UNEXPECTED_EOF, '-', + "Do not treat lack of close_notify from a peer as an error"}, #ifndef OPENSSL_NO_OCSP {"status", OPT_STATUS, '-', "Request certificate status from server"}, #endif @@ -712,17 +610,9 @@ const OPTIONS s_client_options[] = { {"alpn", OPT_ALPN, 's', "Enable ALPN extension, considering named protocols supported (comma-separated list)"}, {"async", OPT_ASYNC, '-', "Support asynchronous operation"}, - {"ssl_config", OPT_SSL_CONFIG, 's', "Use specified configuration file"}, - {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, - {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', - "Size used to split data for encrypt pipelines"}, - {"max_pipelines", OPT_MAX_PIPELINES, 'p', - "Maximum number of encrypt/decrypt pipelines to be used"}, - {"read_buf", OPT_READ_BUF, 'p', - "Default read buffer size to be used for connections"}, - OPT_S_OPTIONS, - OPT_V_OPTIONS, - OPT_X_OPTIONS, + {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, + + OPT_SECTION("Protocol and version"), #ifndef OPENSSL_NO_SSL3 {"ssl3", OPT_SSL3, '-', "Just use SSLv3"}, #endif @@ -754,43 +644,54 @@ const OPTIONS s_client_options[] = { {"sctp", OPT_SCTP, '-', "Use SCTP"}, {"sctp_label_bug", OPT_SCTP_LABEL_BUG, '-', "Enable SCTP label length bug"}, #endif -#ifndef OPENSSL_NO_SSL_TRACE - {"trace", OPT_TRACE, '-', "Show trace output of protocol messages"}, -#endif -#ifdef WATT32 - {"wdebug", OPT_WDEBUG, '-', "WATT-32 tcp debugging"}, -#endif - {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, - {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity"}, - {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, - {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"}, -#ifndef OPENSSL_NO_SRP - {"srpuser", OPT_SRPUSER, 's', "SRP authentication for 'user'"}, - {"srppass", OPT_SRPPASS, 's', "Password for 'user'"}, - {"srp_lateuser", OPT_SRP_LATEUSER, '-', - "SRP username into second ClientHello message"}, - {"srp_moregroups", OPT_SRP_MOREGROUPS, '-', - "Tolerate other than the known g N values."}, - {"srp_strength", OPT_SRP_STRENGTH, 'p', "Minimal length in bits for N"}, -#endif #ifndef OPENSSL_NO_NEXTPROTONEG {"nextprotoneg", OPT_NEXTPROTONEG, 's', "Enable NPN extension, considering named protocols supported (comma-separated list)"}, #endif -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, - {"ssl_client_engine", OPT_SSL_CLIENT_ENGINE, 's', - "Specify engine to be used for client certificate operations"}, -#endif -#ifndef OPENSSL_NO_CT - {"ct", OPT_CT, '-', "Request and parse SCTs (also enables OCSP stapling)"}, - {"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"}, - {"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"}, -#endif - {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, {"early_data", OPT_EARLY_DATA, '<', "File to send as early data"}, {"enable_pha", OPT_ENABLE_PHA, '-', "Enable post-handshake-authentication"}, - {NULL, OPT_EOF, 0x00, NULL} +#ifndef OPENSSL_NO_SRTP + {"use_srtp", OPT_USE_SRTP, 's', + "Offer SRTP key management with a colon-separated profile list"}, +#endif +#ifndef OPENSSL_NO_SRP + {"srpuser", OPT_SRPUSER, 's', "(deprecated) SRP authentication for 'user'"}, + {"srppass", OPT_SRPPASS, 's', "(deprecated) Password for 'user'"}, + {"srp_lateuser", OPT_SRP_LATEUSER, '-', + "(deprecated) SRP username into second ClientHello message"}, + {"srp_moregroups", OPT_SRP_MOREGROUPS, '-', + "(deprecated) Tolerate other than the known g N values."}, + {"srp_strength", OPT_SRP_STRENGTH, 'p', + "(deprecated) Minimal length in bits for N"}, +#endif + + OPT_R_OPTIONS, + OPT_S_OPTIONS, + OPT_V_OPTIONS, + {"CRL", OPT_CRL, '<', "CRL file to use"}, + {"crl_download", OPT_CRL_DOWNLOAD, '-', "Download CRL from distribution points"}, + {"CRLform", OPT_CRLFORM, 'F', "CRL format (PEM or DER); default PEM"}, + {"verify_return_error", OPT_VERIFY_RET_ERROR, '-', + "Close connection on verification error"}, + {"verify_quiet", OPT_VERIFY_QUIET, '-', "Restrict verify output to errors"}, + {"chainCAfile", OPT_CHAINCAFILE, '<', + "CA file for certificate chain (PEM format)"}, + {"chainCApath", OPT_CHAINCAPATH, '/', + "Use dir as certificate store path to build CA certificate chain"}, + {"chainCAstore", OPT_CHAINCASTORE, ':', + "CA store URI for certificate chain"}, + {"verifyCAfile", OPT_VERIFYCAFILE, '<', + "CA file for certificate verification (PEM format)"}, + {"verifyCApath", OPT_VERIFYCAPATH, '/', + "Use dir as certificate store path to verify CA certificate"}, + {"verifyCAstore", OPT_VERIFYCASTORE, ':', + "CA store URI for certificate verification"}, + OPT_X_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"host:port", 0, 0, "Where to connect; same as -connect option"}, + {NULL} }; typedef enum PROTOCOL_choice { @@ -802,7 +703,6 @@ typedef enum PROTOCOL_choice { PROTO_TELNET, PROTO_XMPP, PROTO_XMPP_SERVER, - PROTO_CONNECT, PROTO_IRC, PROTO_MYSQL, PROTO_POSTGRES, @@ -896,29 +796,33 @@ int s_client_main(int argc, char **argv) int dane_ee_no_name = 0; STACK_OF(X509_CRL) *crls = NULL; const SSL_METHOD *meth = TLS_client_method(); - const char *CApath = NULL, *CAfile = NULL; - char *cbuf = NULL, *sbuf = NULL; - char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL, *bindstr = NULL; + const char *CApath = NULL, *CAfile = NULL, *CAstore = NULL; + char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; + char *proxystr = NULL, *proxyuser = NULL; + char *proxypassarg = NULL, *proxypass = NULL; + char *connectstr = NULL, *bindstr = NULL; char *cert_file = NULL, *key_file = NULL, *chain_file = NULL; - char *chCApath = NULL, *chCAfile = NULL, *host = NULL; - char *port = OPENSSL_strdup(PORT); + char *chCApath = NULL, *chCAfile = NULL, *chCAstore = NULL, *host = NULL; + char *thost = NULL, *tport = NULL; + char *port = NULL; char *bindhost = NULL, *bindport = NULL; - char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; + char *passarg = NULL, *pass = NULL; + char *vfyCApath = NULL, *vfyCAfile = NULL, *vfyCAstore = NULL; char *ReqCAfile = NULL; char *sess_in = NULL, *crl_file = NULL, *p; const char *protohost = NULL; struct timeval timeout, *timeoutp; fd_set readfds, writefds; - int noCApath = 0, noCAfile = 0; - int build_chain = 0, cbuf_len, cbuf_off, cert_format = FORMAT_PEM; - int key_format = FORMAT_PEM, crlf = 0, full_log = 1, mbuf_len = 0; + int noCApath = 0, noCAfile = 0, noCAstore = 0; + int build_chain = 0, cbuf_len, cbuf_off, cert_format = FORMAT_UNDEF; + int key_format = FORMAT_UNDEF, crlf = 0, full_log = 1, mbuf_len = 0; int prexit = 0; int sdebug = 0; int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0; - int ret = 1, in_init = 1, i, nbio_test = 0, s = -1, k, width, state = 0; + int ret = 1, in_init = 1, i, nbio_test = 0, sock = -1, k, width, state = 0; int sbuf_len, sbuf_off, cmdletters = 1; int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM, protocol = 0; - int starttls_proto = PROTO_OFF, crl_format = FORMAT_PEM, crl_download = 0; + int starttls_proto = PROTO_OFF, crl_format = FORMAT_UNDEF, crl_download = 0; int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) int at_eof = 0; @@ -983,6 +887,7 @@ int s_client_main(int argc, char **argv) #ifndef OPENSSL_NO_SCTP int sctp_label_bug = 0; #endif + int ignore_unexpected_eof = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -994,16 +899,16 @@ int s_client_main(int argc, char **argv) # endif #endif - prog = opt_progname(argv[0]); c_quiet = 0; c_debug = 0; c_showcerts = 0; c_nbio = 0; + port = OPENSSL_strdup(PORT); vpm = X509_VERIFY_PARAM_new(); cctx = SSL_CONF_CTX_new(); - if (vpm == NULL || cctx == NULL) { - BIO_printf(bio_err, "%s: out of memory\n", prog); + if (port == NULL || vpm == NULL || cctx == NULL) { + BIO_printf(bio_err, "%s: out of memory\n", opt_getprog()); goto end; } @@ -1080,7 +985,12 @@ int s_client_main(int argc, char **argv) break; case OPT_PROXY: proxystr = opt_arg(); - starttls_proto = PROTO_CONNECT; + break; + case OPT_PROXY_USER: + proxyuser = opt_arg(); + break; + case OPT_PROXY_PASS: + proxypassarg = opt_arg(); break; #ifdef AF_UNIX case OPT_UNIX: @@ -1120,7 +1030,7 @@ int s_client_main(int argc, char **argv) sess_in = opt_arg(); break; case OPT_CERTFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &cert_format)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &cert_format)) goto opthelp; break; case OPT_CRLFORM: @@ -1156,6 +1066,9 @@ int s_client_main(int argc, char **argv) if (!args_excert(o, &exc)) goto end; break; + case OPT_IGNORE_UNEXPECTED_EOF: + ignore_unexpected_eof = 1; + break; case OPT_PREXIT: prexit = 1; break; @@ -1176,7 +1089,7 @@ int s_client_main(int argc, char **argv) break; case OPT_SSL_CLIENT_ENGINE: #ifndef OPENSSL_NO_ENGINE - ssl_client_engine = ENGINE_by_id(opt_arg()); + ssl_client_engine = setup_engine(opt_arg(), 0); if (ssl_client_engine == NULL) { BIO_printf(bio_err, "Error getting client auth engine\n"); goto opthelp; @@ -1187,6 +1100,10 @@ int s_client_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_IGN_EOF: c_ign_eof = 1; break; @@ -1214,6 +1131,10 @@ int s_client_main(int argc, char **argv) break; case OPT_MSGFILE: bio_c_msg = BIO_new_file(opt_arg(), "w"); + if (bio_c_msg == NULL) { + BIO_printf(bio_err, "Error writing file %s\n", opt_arg()); + goto end; + } break; case OPT_TRACE: #ifndef OPENSSL_NO_SSL_TRACE @@ -1370,7 +1291,7 @@ int s_client_main(int argc, char **argv) fallback_scsv = 1; break; case OPT_KEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PDE, &key_format)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &key_format)) goto opthelp; break; case OPT_PASS: @@ -1426,6 +1347,18 @@ int s_client_main(int argc, char **argv) case OPT_VERIFYCAFILE: vfyCAfile = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; + case OPT_NOCASTORE: + noCAstore = 1; + break; + case OPT_CHAINCASTORE: + chCAstore = opt_arg(); + break; + case OPT_VERIFYCASTORE: + vfyCAstore = opt_arg(); + break; case OPT_DANE_TLSA_DOMAIN: dane_tlsa_domain = opt_arg(); break; @@ -1530,6 +1463,25 @@ int s_client_main(int argc, char **argv) break; } } + + /* Optional argument is connect string if -connect not used. */ + argc = opt_num_rest(); + if (argc == 1) { + /* Don't allow -connect and a separate argument. */ + if (connectstr != NULL) { + BIO_printf(bio_err, + "%s: cannot provide both -connect option and target parameter\n", + prog); + goto opthelp; + } + connect_type = use_inet; + freeandcopy(&connectstr, *opt_rest()); + } else if (argc != 0) { + goto opthelp; + } + if (!app_RAND_load()) + goto end; + if (count4or6 >= 2) { BIO_printf(bio_err, "%s: Can't use both -4 and -6\n", prog); goto opthelp; @@ -1548,23 +1500,6 @@ int s_client_main(int argc, char **argv) goto opthelp; } } - argc = opt_num_rest(); - if (argc == 1) { - /* If there's a positional argument, it's the equivalent of - * OPT_CONNECT. - * Don't allow -connect and a separate argument. - */ - if (connectstr != NULL) { - BIO_printf(bio_err, - "%s: must not provide both -connect option and target parameter\n", - prog); - goto opthelp; - } - connect_type = use_inet; - freeandcopy(&connectstr, *opt_rest()); - } else if (argc != 0) { - goto opthelp; - } #ifndef OPENSSL_NO_NEXTPROTONEG if (min_version == TLS1_3_VERSION && next_proto_neg_in != NULL) { @@ -1572,46 +1507,57 @@ int s_client_main(int argc, char **argv) goto opthelp; } #endif - if (proxystr != NULL) { + + if (connectstr != NULL) { int res; char *tmp_host = host, *tmp_port = port; - if (connectstr == NULL) { - BIO_printf(bio_err, "%s: -proxy requires use of -connect or target parameter\n", prog); - goto opthelp; - } - res = BIO_parse_hostserv(proxystr, &host, &port, BIO_PARSE_PRIO_HOST); + + res = BIO_parse_hostserv(connectstr, &host, &port, BIO_PARSE_PRIO_HOST); if (tmp_host != host) OPENSSL_free(tmp_host); if (tmp_port != port) OPENSSL_free(tmp_port); if (!res) { BIO_printf(bio_err, - "%s: -proxy argument malformed or ambiguous\n", prog); + "%s: -connect argument or target parameter malformed or ambiguous\n", + prog); goto end; } + } + + if (proxystr != NULL) { + int res; + char *tmp_host = host, *tmp_port = port; + + if (host == NULL || port == NULL) { + BIO_printf(bio_err, "%s: -proxy requires use of -connect or target parameter\n", prog); + goto opthelp; + } + if (servername == NULL && !noservername) { - res = BIO_parse_hostserv(connectstr, &sname_alloc, NULL, BIO_PARSE_PRIO_HOST); - if (!res) { - BIO_printf(bio_err, - "%s: -connect argument malformed or ambiguous\n", prog); + servername = sname_alloc = OPENSSL_strdup(host); + if (sname_alloc == NULL) { + BIO_printf(bio_err, "%s: out of memory\n", prog); goto end; } - servername = sname_alloc; } - } else { - int res = 1; - char *tmp_host = host, *tmp_port = port; - if (connectstr != NULL) - res = BIO_parse_hostserv(connectstr, &host, &port, - BIO_PARSE_PRIO_HOST); + + /* Retain the original target host:port for use in the HTTP proxy connect string */ + thost = OPENSSL_strdup(host); + tport = OPENSSL_strdup(port); + if (thost == NULL || tport == NULL) { + BIO_printf(bio_err, "%s: out of memory\n", prog); + goto end; + } + + res = BIO_parse_hostserv(proxystr, &host, &port, BIO_PARSE_PRIO_HOST); if (tmp_host != host) OPENSSL_free(tmp_host); if (tmp_port != port) OPENSSL_free(tmp_port); if (!res) { BIO_printf(bio_err, - "%s: -connect argument or target parameter malformed or ambiguous\n", - prog); + "%s: -proxy argument malformed or ambiguous\n", prog); goto end; } } @@ -1661,7 +1607,17 @@ int s_client_main(int argc, char **argv) #endif if (!app_passwd(passarg, NULL, &pass, NULL)) { - BIO_printf(bio_err, "Error getting password\n"); + BIO_printf(bio_err, "Error getting private key password\n"); + goto end; + } + + if (!app_passwd(proxypassarg, NULL, &proxypass, NULL)) { + BIO_printf(bio_err, "Error getting proxy password\n"); + goto end; + } + + if (proxypass != NULL && proxyuser == NULL) { + BIO_printf(bio_err, "Error: Must specify proxy_user with proxy_pass\n"); goto end; } @@ -1670,35 +1626,28 @@ int s_client_main(int argc, char **argv) if (key_file != NULL) { key = load_key(key_file, key_format, 0, pass, e, - "client certificate private key file"); - if (key == NULL) { - ERR_print_errors(bio_err); + "client certificate private key"); + if (key == NULL) goto end; - } } if (cert_file != NULL) { - cert = load_cert(cert_file, cert_format, "client certificate file"); - if (cert == NULL) { - ERR_print_errors(bio_err); + cert = load_cert_pass(cert_file, cert_format, 1, pass, + "client certificate"); + if (cert == NULL) goto end; - } } if (chain_file != NULL) { - if (!load_certs(chain_file, &chain, FORMAT_PEM, NULL, - "client certificate chain")) + if (!load_certs(chain_file, 0, &chain, pass, "client certificate chain")) goto end; } if (crl_file != NULL) { X509_CRL *crl; - crl = load_crl(crl_file, crl_format); - if (crl == NULL) { - BIO_puts(bio_err, "Error loading CRL\n"); - ERR_print_errors(bio_err); + crl = load_crl(crl_file, crl_format, 0, "CRL"); + if (crl == NULL) goto end; - } crls = sk_X509_CRL_new_null(); if (crls == NULL || !sk_X509_CRL_push(crls, crl)) { BIO_puts(bio_err, "Error adding CRL\n"); @@ -1714,10 +1663,21 @@ int s_client_main(int argc, char **argv) if (bio_c_out == NULL) { if (c_quiet && !c_debug) { bio_c_out = BIO_new(BIO_s_null()); - if (c_msg && bio_c_msg == NULL) + if (c_msg && bio_c_msg == NULL) { bio_c_msg = dup_bio_out(FORMAT_TEXT); - } else if (bio_c_out == NULL) + if (bio_c_msg == NULL) { + BIO_printf(bio_err, "Out of memory\n"); + goto end; + } + } + } else { bio_c_out = dup_bio_out(FORMAT_TEXT); + } + + if (bio_c_out == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto end; + } } #ifndef OPENSSL_NO_SRP if (!app_passwd(srppass, NULL, &srp_arg.srppassin, NULL)) { @@ -1726,7 +1686,7 @@ int s_client_main(int argc, char **argv) } #endif - ctx = SSL_CTX_new(meth); + ctx = SSL_CTX_new_ex(app_get0_libctx(), app_get0_propq(), meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; @@ -1761,6 +1721,9 @@ int s_client_main(int argc, char **argv) && SSL_CTX_set_max_proto_version(ctx, max_version) == 0) goto end; + if (ignore_unexpected_eof) + SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); + if (vpmtouched && !SSL_CTX_set1_param(ctx, vpm)) { BIO_printf(bio_err, "Error setting verify params\n"); ERR_print_errors(bio_err); @@ -1804,7 +1767,9 @@ int s_client_main(int argc, char **argv) goto end; } - if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, + if (!ssl_load_stores(ctx, + vfyCApath, vfyCAfile, vfyCAstore, + chCApath, chCAfile, chCAstore, crls, crl_download)) { BIO_printf(bio_err, "Error loading store locations\n"); ERR_print_errors(bio_err); @@ -1826,10 +1791,10 @@ int s_client_main(int argc, char **argv) if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { BIO_puts(bio_err, "Error setting client auth engine\n"); ERR_print_errors(bio_err); - ENGINE_free(ssl_client_engine); + release_engine(ssl_client_engine); goto end; } - ENGINE_free(ssl_client_engine); + release_engine(ssl_client_engine); } #endif @@ -1933,7 +1898,8 @@ int s_client_main(int argc, char **argv) SSL_CTX_set_verify(ctx, verify, verify_callback); - if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { + if (!ctx_set_verify_locations(ctx, CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) { ERR_print_errors(bio_err); goto end; } @@ -1948,21 +1914,10 @@ int s_client_main(int argc, char **argv) SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); } -# ifndef OPENSSL_NO_SRP - if (srp_arg.srplogin) { - if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg.srplogin)) { - BIO_printf(bio_err, "Unable to set SRP username\n"); - goto end; - } - srp_arg.msg = c_msg; - srp_arg.debug = c_debug; - SSL_CTX_set_srp_cb_arg(ctx, &srp_arg); - SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb); - SSL_CTX_set_srp_strength(ctx, srp_arg.strength); - if (c_msg || c_debug || srp_arg.amp == 0) - SSL_CTX_set_srp_verify_param_callback(ctx, - ssl_srp_verify_param_cb); - } +#ifndef OPENSSL_NO_SRP + if (srp_arg.srplogin != NULL + && !set_up_srp_arg(ctx, &srp_arg, srp_lateuser, c_msg, c_debug)) + goto end; # endif if (dane_tlsa_domain != NULL) { @@ -2023,7 +1978,7 @@ int s_client_main(int argc, char **argv) if (!noservername && (servername != NULL || dane_tlsa_domain == NULL)) { if (servername == NULL) { - if(host == NULL || is_dNS_name(host)) + if(host == NULL || is_dNS_name(host)) servername = (host == NULL) ? "localhost" : host; } if (servername != NULL && !SSL_set_tlsext_host_name(con, servername)) { @@ -2059,16 +2014,16 @@ int s_client_main(int argc, char **argv) } re_start: - if (init_client(&s, host, port, bindhost, bindport, socket_family, + if (init_client(&sock, host, port, bindhost, bindport, socket_family, socket_type, protocol) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); - BIO_closesocket(s); + BIO_closesocket(sock); goto end; } - BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); + BIO_printf(bio_c_out, "CONNECTED(%08X)\n", sock); if (c_nbio) { - if (!BIO_socket_nbio(s, 1)) { + if (!BIO_socket_nbio(sock, 1)) { ERR_print_errors(bio_err); goto end; } @@ -2080,21 +2035,23 @@ int s_client_main(int argc, char **argv) #ifndef OPENSSL_NO_SCTP if (protocol == IPPROTO_SCTP) - sbio = BIO_new_dgram_sctp(s, BIO_NOCLOSE); + sbio = BIO_new_dgram_sctp(sock, BIO_NOCLOSE); else #endif - sbio = BIO_new_dgram(s, BIO_NOCLOSE); + sbio = BIO_new_dgram(sock, BIO_NOCLOSE); - if ((peer_info.addr = BIO_ADDR_new()) == NULL) { + if (sbio == NULL || (peer_info.addr = BIO_ADDR_new()) == NULL) { BIO_printf(bio_err, "memory allocation failure\n"); - BIO_closesocket(s); + BIO_free(sbio); + BIO_closesocket(sock); goto end; } - if (!BIO_sock_info(s, BIO_SOCK_INFO_ADDRESS, &peer_info)) { + if (!BIO_sock_info(sock, BIO_SOCK_INFO_ADDRESS, &peer_info)) { BIO_printf(bio_err, "getsockname:errno=%d\n", get_last_socket_error()); + BIO_free(sbio); BIO_ADDR_free(peer_info.addr); - BIO_closesocket(s); + BIO_closesocket(sock); goto end; } @@ -2131,17 +2088,29 @@ int s_client_main(int argc, char **argv) } } else #endif /* OPENSSL_NO_DTLS */ - sbio = BIO_new_socket(s, BIO_NOCLOSE); + sbio = BIO_new_socket(sock, BIO_NOCLOSE); + + if (sbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + ERR_print_errors(bio_err); + BIO_closesocket(sock); + goto end; + } if (nbio_test) { BIO *test; test = BIO_new(BIO_f_nbio_test()); + if (test == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + BIO_free(sbio); + goto shut; + } sbio = BIO_push(test, sbio); } if (c_debug) { - BIO_set_callback(sbio, bio_dump_callback); + BIO_set_callback_ex(sbio, bio_dump_callback); BIO_set_callback_arg(sbio, (char *)bio_c_out); } if (c_msg) { @@ -2186,6 +2155,13 @@ int s_client_main(int argc, char **argv) sbuf_len = 0; sbuf_off = 0; + if (proxystr != NULL) { + /* Here we must use the connect string target host & port */ + if (!OSSL_HTTP_proxy_connect(sbio, thost, tport, proxyuser, proxypass, + 0 /* no timeout */, bio_err, prog)) + goto shut; + } + switch ((PROTOCOL_CHOICE) starttls_proto) { case PROTO_OFF: break; @@ -2203,6 +2179,10 @@ int s_client_main(int argc, char **argv) int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); + if (fbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto shut; + } BIO_push(fbio, sbio); /* Wait for multi-line response to end from LMTP or SMTP */ do { @@ -2251,6 +2231,10 @@ int s_client_main(int argc, char **argv) int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); + if (fbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto shut; + } BIO_push(fbio, sbio); BIO_gets(fbio, mbuf, BUFSIZZ); /* STARTTLS command requires CAPABILITY... */ @@ -2278,6 +2262,10 @@ int s_client_main(int argc, char **argv) { BIO *fbio = BIO_new(BIO_f_buffer()); + if (fbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto shut; + } BIO_push(fbio, sbio); /* wait for multi-line response to end from FTP */ do { @@ -2361,64 +2349,15 @@ int s_client_main(int argc, char **argv) goto shut; } break; - case PROTO_CONNECT: - { - enum { - error_proto, /* Wrong protocol, not even HTTP */ - error_connect, /* CONNECT failed */ - success - } foundit = error_connect; - BIO *fbio = BIO_new(BIO_f_buffer()); - - BIO_push(fbio, sbio); - BIO_printf(fbio, "CONNECT %s HTTP/1.0\r\n\r\n", connectstr); - (void)BIO_flush(fbio); - /* - * The first line is the HTTP response. According to RFC 7230, - * it's formatted exactly like this: - * - * HTTP/d.d ddd Reason text\r\n - */ - mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); - if (mbuf_len < (int)strlen("HTTP/1.0 200")) { - BIO_printf(bio_err, - "%s: HTTP CONNECT failed, insufficient response " - "from proxy (got %d octets)\n", prog, mbuf_len); - (void)BIO_flush(fbio); - BIO_pop(fbio); - BIO_free(fbio); - goto shut; - } - if (mbuf[8] != ' ') { - BIO_printf(bio_err, - "%s: HTTP CONNECT failed, incorrect response " - "from proxy\n", prog); - foundit = error_proto; - } else if (mbuf[9] != '2') { - BIO_printf(bio_err, "%s: HTTP CONNECT failed: %s ", prog, - &mbuf[9]); - } else { - foundit = success; - } - if (foundit != error_proto) { - /* Read past all following headers */ - do { - mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); - } while (mbuf_len > 2); - } - (void)BIO_flush(fbio); - BIO_pop(fbio); - BIO_free(fbio); - if (foundit != success) { - goto shut; - } - } - break; case PROTO_IRC: { int numeric; BIO *fbio = BIO_new(BIO_f_buffer()); + if (fbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto end; + } BIO_push(fbio, sbio); BIO_printf(fbio, "STARTTLS\r\n"); (void)BIO_flush(fbio); @@ -2579,17 +2518,25 @@ int s_client_main(int argc, char **argv) int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); + if (fbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto end; + } BIO_push(fbio, sbio); BIO_gets(fbio, mbuf, BUFSIZZ); /* STARTTLS command requires CAPABILITIES... */ BIO_printf(fbio, "CAPABILITIES\r\n"); (void)BIO_flush(fbio); - /* wait for multi-line CAPABILITIES response */ - do { - mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); - if (strstr(mbuf, "STARTTLS")) - foundit = 1; - } while (mbuf_len > 1 && mbuf[0] != '.'); + BIO_gets(fbio, mbuf, BUFSIZZ); + /* no point in trying to parse the CAPABILITIES response if there is none */ + if (strstr(mbuf, "101") != NULL) { + /* wait for multi-line CAPABILITIES response */ + do { + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + if (strstr(mbuf, "STARTTLS")) + foundit = 1; + } while (mbuf_len > 1 && mbuf[0] != '.'); + } (void)BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); @@ -2615,6 +2562,10 @@ int s_client_main(int argc, char **argv) int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); + if (fbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + goto end; + } BIO_push(fbio, sbio); /* wait for multi-line response to end from Sieve */ do { @@ -2674,8 +2625,9 @@ int s_client_main(int argc, char **argv) BIO *ldapbio = BIO_new(BIO_s_mem()); CONF *cnf = NCONF_new(NULL); - if (cnf == NULL) { + if (ldapbio == NULL || cnf == NULL) { BIO_free(ldapbio); + NCONF_free(cnf); goto end; } BIO_puts(ldapbio, ldap_tls_genconf); @@ -2784,7 +2736,6 @@ int s_client_main(int argc, char **argv) tty_on = 1; if (in_init) { in_init = 0; - if (c_brief) { BIO_puts(bio_err, "CONNECTION ESTABLISHED\n"); print_ssl_summary(con); @@ -3080,22 +3031,14 @@ int s_client_main(int argc, char **argv) BIO_printf(bio_err, "RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len = 0; - } else if (!c_ign_eof && (cbuf[0] == 'K' || cbuf[0] == 'k' ) + } else if (!c_ign_eof && (cbuf[0] == 'K' || cbuf[0] == 'k' ) && cmdletters) { BIO_printf(bio_err, "KEYUPDATE\n"); SSL_key_update(con, cbuf[0] == 'K' ? SSL_KEY_UPDATE_REQUESTED : SSL_KEY_UPDATE_NOT_REQUESTED); cbuf_len = 0; - } -#ifndef OPENSSL_NO_HEARTBEATS - else if ((!c_ign_eof) && (cbuf[0] == 'B' && cmdletters)) { - BIO_printf(bio_err, "HEARTBEATING\n"); - SSL_heartbeat(con); - cbuf_len = 0; - } -#endif - else { + } else { cbuf_len = i; cbuf_off = 0; #ifdef CHARSET_EBCDIC @@ -3108,7 +3051,6 @@ int s_client_main(int argc, char **argv) } } - ret = 0; shut: if (in_init) print_stuff(bio_c_out, con, full_log); @@ -3134,8 +3076,8 @@ int s_client_main(int argc, char **argv) timeout.tv_usec = 500000; /* some extreme round-trip */ do { FD_ZERO(&readfds); - openssl_fdset(s, &readfds); - } while (select(s + 1, &readfds, NULL, NULL, &timeout) > 0 + openssl_fdset(sock, &readfds); + } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0 && BIO_read(sbio, sbuf, BUFSIZZ) > 0); BIO_closesocket(SSL_get_fd(con)); @@ -3166,6 +3108,8 @@ int s_client_main(int argc, char **argv) OPENSSL_free(bindport); OPENSSL_free(host); OPENSSL_free(port); + OPENSSL_free(thost); + OPENSSL_free(tport); X509_VERIFY_PARAM_free(vpm); ssl_excert_free(exc); sk_OPENSSL_STRING_free(ssl_args); @@ -3174,6 +3118,7 @@ int s_client_main(int argc, char **argv) OPENSSL_clear_free(cbuf, BUFSIZZ); OPENSSL_clear_free(sbuf, BUFSIZZ); OPENSSL_clear_free(mbuf, BUFSIZZ); + clear_free(proxypass); release_engine(e); BIO_free(bio_c_out); bio_c_out = NULL; @@ -3187,6 +3132,7 @@ static void print_stuff(BIO *bio, SSL *s, int full) X509 *peer = NULL; STACK_OF(X509) *sk; const SSL_CIPHER *c; + EVP_PKEY *public_key; int i, istls13 = (SSL_version(s) == TLS1_3_VERSION); long verify_result; #ifndef OPENSSL_NO_COMP @@ -3212,13 +3158,26 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_printf(bio, " i:"); X509_NAME_print_ex(bio, X509_get_issuer_name(sk_X509_value(sk, i)), 0, get_nameopt()); BIO_puts(bio, "\n"); + public_key = X509_get_pubkey(sk_X509_value(sk, i)); + if (public_key != NULL) { + BIO_printf(bio, " a:PKEY: %s, %d (bit); sigalg: %s\n", + OBJ_nid2sn(EVP_PKEY_get_base_id(public_key)), + EVP_PKEY_get_bits(public_key), + OBJ_nid2sn(X509_get_signature_nid(sk_X509_value(sk, i)))); + EVP_PKEY_free(public_key); + } + BIO_printf(bio, " v:NotBefore: "); + ASN1_TIME_print(bio, X509_get0_notBefore(sk_X509_value(sk, i))); + BIO_printf(bio, "; NotAfter: "); + ASN1_TIME_print(bio, X509_get0_notAfter(sk_X509_value(sk, i))); + BIO_puts(bio, "\n"); if (c_showcerts) PEM_write_bio_X509(bio, sk_X509_value(sk, i)); } } BIO_printf(bio, "---\n"); - peer = SSL_get_peer_certificate(s); + peer = SSL_get0_peer_certificate(s); if (peer != NULL) { BIO_printf(bio, "Server certificate\n"); @@ -3283,7 +3242,7 @@ static void print_stuff(BIO *bio, SSL *s, int full) pktmp = X509_get0_pubkey(peer); BIO_printf(bio, "Server public key is %d bit\n", - EVP_PKEY_bits(pktmp)); + EVP_PKEY_get_bits(pktmp)); } BIO_printf(bio, "Secure Renegotiation IS%s supported\n", SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); @@ -3295,9 +3254,14 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_printf(bio, "Expansion: %s\n", expansion ? SSL_COMP_get_name(expansion) : "NONE"); #endif +#ifndef OPENSSL_NO_KTLS + if (BIO_get_ktls_send(SSL_get_wbio(s))) + BIO_printf(bio_err, "Using Kernel TLS for sending\n"); + if (BIO_get_ktls_recv(SSL_get_rbio(s))) + BIO_printf(bio_err, "Using Kernel TLS for receiving\n"); +#endif -#ifdef SSL_DEBUG - { + if (OSSL_TRACE_ENABLED(TLS)) { /* Print out local port of connection: useful for debugging */ int sock; union BIO_sock_info_u info; @@ -3310,7 +3274,6 @@ static void print_stuff(BIO *bio, SSL *s, int full) } BIO_ADDR_free(info.addr); } -#endif #if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.status != -1) { @@ -3379,11 +3342,11 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); BIO_printf(bio, " Length: %i bytes\n", keymatexportlen); exportedkeymat = app_malloc(keymatexportlen, "export key"); - if (!SSL_export_keying_material(s, exportedkeymat, + if (SSL_export_keying_material(s, exportedkeymat, keymatexportlen, keymatexportlabel, strlen(keymatexportlabel), - NULL, 0, 0)) { + NULL, 0, 0) <= 0) { BIO_printf(bio, " Error\n"); } else { BIO_printf(bio, " Keying material: "); @@ -3394,7 +3357,6 @@ static void print_stuff(BIO *bio, SSL *s, int full) OPENSSL_free(exportedkeymat); } BIO_printf(bio, "---\n"); - X509_free(peer); /* flush, or debugging output gets mixed with http response */ (void)BIO_flush(bio); } @@ -3510,7 +3472,7 @@ static int ldap_ExtendedResponse_parse(const char *buf, long rem) } /* - * Host dNS Name verifier: used for checking that the hostname is in dNS format + * Host dNS Name verifier: used for checking that the hostname is in dNS format * before setting it as SNI */ static int is_dNS_name(const char *host) diff --git a/apps/s_server.c b/apps/s_server.c index 1a42bf89c7a0..2b0b6ba381fb 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -3,7 +3,7 @@ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * Copyright 2005 Nokia. All rights reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -21,6 +21,7 @@ #include <openssl/e_os2.h> #include <openssl/async.h> #include <openssl/ssl.h> +#include <openssl/decoder.h> #ifndef OPENSSL_NO_SOCK @@ -47,12 +48,7 @@ typedef unsigned int u_int; #ifndef OPENSSL_NO_DH # include <openssl/dh.h> #endif -#ifndef OPENSSL_NO_RSA -# include <openssl/rsa.h> -#endif -#ifndef OPENSSL_NO_SRP -# include <openssl/srp.h> -#endif +#include <openssl/rsa.h> #include "s_apps.h" #include "timeouts.h" #ifdef CHARSET_EBCDIC @@ -71,9 +67,6 @@ static int generate_session_id(SSL *ssl, unsigned char *id, unsigned int *id_len); static void init_session_cache_ctx(SSL_CTX *sctx); static void free_sessions(void); -#ifndef OPENSSL_NO_DH -static DH *load_dh_param(const char *dhfile); -#endif static void print_connection_info(SSL *con); static const int bufsize = 16 * 1024; @@ -103,6 +96,8 @@ static int keymatexportlen = 20; static int async = 0; +static int use_sendfile = 0; + static const char *session_id_prefix = NULL; #ifndef OPENSSL_NO_DTLS @@ -123,6 +118,8 @@ static SSL_SESSION *psksess = NULL; static char *psk_identity = "Client_identity"; char *psk_key = NULL; /* by default PSK is not used */ +static char http_server_binmode = 0; /* for now: 0/1 = default/binary */ + #ifndef OPENSSL_NO_PSK static unsigned int psk_server_cb(SSL *ssl, const char *identity, unsigned char *psk, @@ -241,56 +238,7 @@ static int psk_find_session_cb(SSL *ssl, const unsigned char *identity, } #ifndef OPENSSL_NO_SRP -/* This is a context that we pass to callbacks */ -typedef struct srpsrvparm_st { - char *login; - SRP_VBASE *vb; - SRP_user_pwd *user; -} srpsrvparm; static srpsrvparm srp_callback_parm; - -/* - * This callback pretends to require some asynchronous logic in order to - * obtain a verifier. When the callback is called for a new connection we - * return with a negative value. This will provoke the accept etc to return - * with an LOOKUP_X509. The main logic of the reinvokes the suspended call - * (which would normally occur after a worker has finished) and we set the - * user parameters. - */ -static int ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) -{ - srpsrvparm *p = (srpsrvparm *) arg; - int ret = SSL3_AL_FATAL; - - if (p->login == NULL && p->user == NULL) { - p->login = SSL_get_srp_username(s); - BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); - return -1; - } - - if (p->user == NULL) { - BIO_printf(bio_err, "User %s doesn't exist\n", p->login); - goto err; - } - - if (SSL_set_srp_server_param - (s, p->user->N, p->user->g, p->user->s, p->user->v, - p->user->info) < 0) { - *ad = SSL_AD_INTERNAL_ERROR; - goto err; - } - BIO_printf(bio_err, - "SRP parameters set: username = \"%s\" info=\"%s\" \n", - p->login, p->user->info); - ret = SSL_ERROR_NONE; - - err: - SRP_user_pwd_free(p->user); - p->user = NULL; - p->login = NULL; - return ret; -} - #endif static int local_argc = 0; @@ -476,7 +424,7 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) BIO_printf(p->biodebug, "Hostname in TLS extension: \""); while ((uc = *cp++) != 0) BIO_printf(p->biodebug, - isascii(uc) && isprint(uc) ? "%c" : "\\x%02x", uc); + (((uc) & ~127) == 0) && isprint(uc) ? "%c" : "\\x%02x", uc); BIO_printf(p->biodebug, "\"\n"); } @@ -484,7 +432,7 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) return SSL_TLSEXT_ERR_NOACK; if (servername != NULL) { - if (strcasecmp(servername, p->servername)) + if (OPENSSL_strcasecmp(servername, p->servername)) return p->extension_error; if (ctx2 != NULL) { BIO_printf(p->biodebug, "Switching server context.\n"); @@ -501,6 +449,7 @@ typedef struct tlsextstatusctx_st { char *respin; /* Default responder to use */ char *host, *path, *port; + char *proxy, *no_proxy; int use_ssl; int verbose; } tlsextstatusctx; @@ -520,6 +469,7 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, OCSP_RESPONSE **resp) { char *host = NULL, *port = NULL, *path = NULL; + char *proxy = NULL, *no_proxy = NULL; int use_ssl; STACK_OF(OPENSSL_STRING) *aia = NULL; X509 *x = NULL; @@ -535,8 +485,8 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, x = SSL_get_certificate(s); aia = X509_get1_ocsp(x); if (aia != NULL) { - if (!OCSP_parse_url(sk_OPENSSL_STRING_value(aia, 0), - &host, &port, &path, &use_ssl)) { + if (!OSSL_HTTP_parse_url(sk_OPENSSL_STRING_value(aia, 0), &use_ssl, + NULL, &host, &port, NULL, &path, NULL, NULL)) { BIO_puts(bio_err, "cert_status: can't parse AIA URL\n"); goto err; } @@ -554,6 +504,8 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, port = srctx->port; use_ssl = srctx->use_ssl; } + proxy = srctx->proxy; + no_proxy = srctx->no_proxy; inctx = X509_STORE_CTX_new(); if (inctx == NULL) @@ -585,8 +537,8 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, if (!OCSP_REQUEST_add_ext(req, ext, -1)) goto err; } - *resp = process_responder(req, host, path, port, use_ssl, NULL, - srctx->timeout); + *resp = process_responder(req, host, port, path, proxy, no_proxy, + use_ssl, NULL /* headers */, srctx->timeout); if (*resp == NULL) { BIO_puts(bio_err, "cert_status: error querying responder\n"); goto done; @@ -716,7 +668,7 @@ static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, if (SSL_select_next_proto ((unsigned char **)out, outlen, alpn_ctx->data, alpn_ctx->len, in, inlen) != OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_ALERT_FATAL; } if (!s_quiet) { @@ -735,7 +687,8 @@ static int not_resumable_sess_cb(SSL *s, int is_forward_secure) } typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE, + OPT_COMMON, + OPT_ENGINE, OPT_4, OPT_6, OPT_ACCEPT, OPT_PORT, OPT_UNIX, OPT_UNLINK, OPT_NACCEPT, OPT_VERIFY, OPT_NAMEOPT, OPT_UPPER_V_VERIFY, OPT_CONTEXT, OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SERVERINFO, OPT_CERTFORM, OPT_KEY, OPT_KEYFORM, @@ -744,9 +697,12 @@ typedef enum OPTION_choice { OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, OPT_VERIFYCAPATH, OPT_NO_CACHE, OPT_EXT_CACHE, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE, OPT_CHAINCAFILE, - OPT_VERIFYCAFILE, OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, + OPT_VERIFYCAFILE, + OPT_CASTORE, OPT_NOCASTORE, OPT_CHAINCASTORE, OPT_VERIFYCASTORE, + OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_VERBOSE, - OPT_STATUS_TIMEOUT, OPT_STATUS_URL, OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, + OPT_STATUS_TIMEOUT, OPT_PROXY, OPT_NO_PROXY, OPT_STATUS_URL, + OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, OPT_TRACE, OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE, OPT_CRLF, OPT_QUIET, OPT_BRIEF, OPT_NO_DHE, OPT_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK, @@ -756,132 +712,154 @@ typedef enum OPTION_choice { OPT_SSL3, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, OPT_STATELESS, OPT_ID_PREFIX, OPT_SERVERNAME, OPT_SERVERNAME_FATAL, - OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, + OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, OPT_SENDFILE, OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA, OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY, OPT_SCTP_LABEL_BUG, + OPT_HTTP_SERVER_BINMODE, OPT_NOCANAMES, OPT_IGNORE_UNEXPECTED_EOF, OPT_R_ENUM, OPT_S_ENUM, OPT_V_ENUM, - OPT_X_ENUM + OPT_X_ENUM, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS s_server_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"ssl_config", OPT_SSL_CONFIG, 's', + "Configure SSL_CTX using the given configuration value"}, +#ifndef OPENSSL_NO_SSL_TRACE + {"trace", OPT_TRACE, '-', "trace protocol messages"}, +#endif +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Network"), {"port", OPT_PORT, 'p', "TCP/IP port to listen on for connections (default is " PORT ")"}, {"accept", OPT_ACCEPT, 's', "TCP/IP optional host and port to listen on for connections (default is *:" PORT ")"}, #ifdef AF_UNIX {"unix", OPT_UNIX, 's', "Unix domain socket to accept on"}, + {"unlink", OPT_UNLINK, '-', "For -unix, unlink existing socket first"}, #endif {"4", OPT_4, '-', "Use IPv4 only"}, {"6", OPT_6, '-', "Use IPv6 only"}, -#ifdef AF_UNIX - {"unlink", OPT_UNLINK, '-', "For -unix, unlink existing socket first"}, -#endif + + OPT_SECTION("Identity"), {"context", OPT_CONTEXT, 's', "Set session ID context"}, + {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, + {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, + {"CAstore", OPT_CASTORE, ':', "URI to store of CA's"}, + {"no-CAfile", OPT_NOCAFILE, '-', + "Do not load the default certificates file"}, + {"no-CApath", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates directory"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store URI"}, + {"nocert", OPT_NOCERT, '-', "Don't use any certificates (Anon-DH)"}, {"verify", OPT_VERIFY, 'n', "Turn on peer certificate verification"}, {"Verify", OPT_UPPER_V_VERIFY, 'n', "Turn on peer certificate verification, must have a cert"}, - {"cert", OPT_CERT, '<', "Certificate file to use; default is " TEST_CERT}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, - {"naccept", OPT_NACCEPT, 'p', "Terminate after #num connections"}, + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, + {"cert", OPT_CERT, '<', "Server certificate file to use; default " TEST_CERT}, + {"cert2", OPT_CERT2, '<', + "Certificate file to use for servername; default " TEST_CERT2}, + {"certform", OPT_CERTFORM, 'F', + "Server certificate file format (PEM/DER/P12); has no effect"}, + {"cert_chain", OPT_CERT_CHAIN, '<', + "Server certificate chain file in PEM format"}, + {"build_chain", OPT_BUILD_CHAIN, '-', "Build server certificate chain"}, {"serverinfo", OPT_SERVERINFO, 's', "PEM serverinfo file for certificate"}, - {"certform", OPT_CERTFORM, 'F', - "Certificate format (PEM or DER) PEM default"}, {"key", OPT_KEY, 's', - "Private Key if not in -cert; default is " TEST_CERT}, - {"keyform", OPT_KEYFORM, 'f', - "Key format (PEM, DER or ENGINE) PEM default"}, - {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, + "Private key file to use; default is -cert file or else" TEST_CERT}, + {"key2", OPT_KEY2, '<', + "-Private Key file to use for servername if not in -cert2"}, + {"keyform", OPT_KEYFORM, 'f', "Key format (ENGINE, other values ignored)"}, + {"pass", OPT_PASS, 's', "Private key and cert file pass phrase source"}, {"dcert", OPT_DCERT, '<', - "Second certificate file to use (usually for DSA)"}, - {"dhparam", OPT_DHPARAM, '<', "DH parameters file to use"}, + "Second server certificate file to use (usually for DSA)"}, {"dcertform", OPT_DCERTFORM, 'F', - "Second certificate format (PEM or DER) PEM default"}, + "Second server certificate file format (PEM/DER/P12); has no effect"}, + {"dcert_chain", OPT_DCERT_CHAIN, '<', + "second server certificate chain file in PEM format"}, {"dkey", OPT_DKEY, '<', "Second private key file to use (usually for DSA)"}, {"dkeyform", OPT_DKEYFORM, 'F', - "Second key format (PEM, DER or ENGINE) PEM default"}, - {"dpass", OPT_DPASS, 's', "Second private key file pass phrase source"}, + "Second key file format (ENGINE, other values ignored)"}, + {"dpass", OPT_DPASS, 's', + "Second private key and cert file pass phrase source"}, + {"dhparam", OPT_DHPARAM, '<', "DH parameters file to use"}, + {"servername", OPT_SERVERNAME, 's', + "Servername for HostName TLS extension"}, + {"servername_fatal", OPT_SERVERNAME_FATAL, '-', + "On servername mismatch send fatal alert (default warning alert)"}, {"nbio_test", OPT_NBIO_TEST, '-', "Test with the non-blocking test bio"}, {"crlf", OPT_CRLF, '-', "Convert LF from terminal into CRLF"}, - {"debug", OPT_DEBUG, '-', "Print more output"}, - {"msg", OPT_MSG, '-', "Show protocol messages"}, - {"msgfile", OPT_MSGFILE, '>', - "File to send output of -msg or -trace, instead of stdout"}, - {"state", OPT_STATE, '-', "Print the SSL states"}, - {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, - {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, - {"no-CAfile", OPT_NOCAFILE, '-', - "Do not load the default certificates file"}, - {"no-CApath", OPT_NOCAPATH, '-', - "Do not load certificates from the default certificates directory"}, - {"nocert", OPT_NOCERT, '-', "Don't use any certificates (Anon-DH)"}, {"quiet", OPT_QUIET, '-', "No server output"}, {"no_resume_ephemeral", OPT_NO_RESUME_EPHEMERAL, '-', "Disable caching and tickets if ephemeral (EC)DH is used"}, {"www", OPT_WWW, '-', "Respond to a 'GET /' with a status page"}, {"WWW", OPT_UPPER_WWW, '-', "Respond to a 'GET with the file ./path"}, - {"servername", OPT_SERVERNAME, 's', - "Servername for HostName TLS extension"}, - {"servername_fatal", OPT_SERVERNAME_FATAL, '-', - "mismatch send fatal alert (default warning alert)"}, - {"cert2", OPT_CERT2, '<', - "Certificate file to use for servername; default is" TEST_CERT2}, - {"key2", OPT_KEY2, '<', - "-Private Key file to use for servername if not in -cert2"}, + {"ignore_unexpected_eof", OPT_IGNORE_UNEXPECTED_EOF, '-', + "Do not treat lack of close_notify from a peer as an error"}, {"tlsextdebug", OPT_TLSEXTDEBUG, '-', "Hex dump of all TLS extensions received"}, {"HTTP", OPT_HTTP, '-', "Like -WWW but ./path includes HTTP headers"}, {"id_prefix", OPT_ID_PREFIX, 's', "Generate SSL/TLS session IDs prefixed by arg"}, - OPT_R_OPTIONS, {"keymatexport", OPT_KEYMATEXPORT, 's', "Export keying material using label"}, {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', - "Export len bytes of keying material (default 20)"}, + "Export len bytes of keying material; default 20"}, {"CRL", OPT_CRL, '<', "CRL file to use"}, + {"CRLform", OPT_CRLFORM, 'F', "CRL file format (PEM or DER); default PEM"}, {"crl_download", OPT_CRL_DOWNLOAD, '-', - "Download CRL from distribution points"}, - {"cert_chain", OPT_CERT_CHAIN, '<', - "certificate chain file in PEM format"}, - {"dcert_chain", OPT_DCERT_CHAIN, '<', - "second certificate chain file in PEM format"}, + "Download CRLs from distribution points in certificate CDP entries"}, + {"chainCAfile", OPT_CHAINCAFILE, '<', + "CA file for certificate chain (PEM format)"}, {"chainCApath", OPT_CHAINCAPATH, '/', "use dir as certificate store path to build CA certificate chain"}, + {"chainCAstore", OPT_CHAINCASTORE, ':', + "use URI as certificate store to build CA certificate chain"}, + {"verifyCAfile", OPT_VERIFYCAFILE, '<', + "CA file for certificate verification (PEM format)"}, {"verifyCApath", OPT_VERIFYCAPATH, '/', "use dir as certificate store path to verify CA certificate"}, + {"verifyCAstore", OPT_VERIFYCASTORE, ':', + "use URI as certificate store to verify CA certificate"}, {"no_cache", OPT_NO_CACHE, '-', "Disable session cache"}, {"ext_cache", OPT_EXT_CACHE, '-', - "Disable internal cache, setup and use external cache"}, - {"CRLform", OPT_CRLFORM, 'F', "CRL format (PEM or DER) PEM is default"}, + "Disable internal cache, set up and use external cache"}, {"verify_return_error", OPT_VERIFY_RET_ERROR, '-', "Close connection on verification error"}, {"verify_quiet", OPT_VERIFY_QUIET, '-', "No verify output except verify errors"}, - {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, - {"chainCAfile", OPT_CHAINCAFILE, '<', - "CA file for certificate chain (PEM format)"}, - {"verifyCAfile", OPT_VERIFYCAFILE, '<', - "CA file for certificate verification (PEM format)"}, - {"ign_eof", OPT_IGN_EOF, '-', "ignore input eof (default when -quiet)"}, - {"no_ign_eof", OPT_NO_IGN_EOF, '-', "Do not ignore input eof"}, + {"ign_eof", OPT_IGN_EOF, '-', "Ignore input EOF (default when -quiet)"}, + {"no_ign_eof", OPT_NO_IGN_EOF, '-', "Do not ignore input EOF"}, + #ifndef OPENSSL_NO_OCSP + OPT_SECTION("OCSP"), {"status", OPT_STATUS, '-', "Request certificate status from server"}, {"status_verbose", OPT_STATUS_VERBOSE, '-', "Print more output in certificate status callback"}, {"status_timeout", OPT_STATUS_TIMEOUT, 'n', "Status request responder timeout"}, {"status_url", OPT_STATUS_URL, 's', "Status request fallback URL"}, + {"proxy", OPT_PROXY, 's', + "[http[s]://]host[:port][/path] of HTTP(S) proxy to use; path is ignored"}, + {"no_proxy", OPT_NO_PROXY, 's', + "List of addresses of servers not to use HTTP(S) proxy for"}, + {OPT_MORE_STR, 0, 0, + "Default from environment variable 'no_proxy', else 'NO_PROXY', else none"}, {"status_file", OPT_STATUS_FILE, '<', "File containing DER encoded OCSP Response"}, #endif -#ifndef OPENSSL_NO_SSL_TRACE - {"trace", OPT_TRACE, '-', "trace protocol messages"}, -#endif + + OPT_SECTION("Debug"), {"security_debug", OPT_SECURITY_DEBUG, '-', "Print output from SSL/TLS security framework"}, {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-', @@ -889,21 +867,29 @@ const OPTIONS s_server_options[] = { {"brief", OPT_BRIEF, '-', "Restrict output to brief summary of connection parameters"}, {"rev", OPT_REV, '-', - "act as a simple test server which just sends back with the received text reversed"}, + "act as an echo server that sends back received text reversed"}, + {"debug", OPT_DEBUG, '-', "Print more output"}, + {"msg", OPT_MSG, '-', "Show protocol messages"}, + {"msgfile", OPT_MSGFILE, '>', + "File to send output of -msg or -trace, instead of stdout"}, + {"state", OPT_STATE, '-', "Print the SSL states"}, {"async", OPT_ASYNC, '-', "Operate in asynchronous mode"}, - {"ssl_config", OPT_SSL_CONFIG, 's', - "Configure SSL_CTX using the configuration 'val'"}, - {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, - {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', - "Size used to split data for encrypt pipelines"}, {"max_pipelines", OPT_MAX_PIPELINES, 'p', "Maximum number of encrypt/decrypt pipelines to be used"}, + {"naccept", OPT_NACCEPT, 'p', "Terminate after #num connections"}, + {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, + + OPT_SECTION("Network"), + {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, + {"timeout", OPT_TIMEOUT, '-', "Enable timeouts"}, + {"mtu", OPT_MTU, 'p', "Set link-layer MTU"}, {"read_buf", OPT_READ_BUF, 'p', "Default read buffer size to be used for connections"}, - OPT_S_OPTIONS, - OPT_V_OPTIONS, - OPT_X_OPTIONS, - {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, + {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', + "Size used to split data for encrypt pipelines"}, + {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, + + OPT_SECTION("Server identity"), {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity to expect"}, #ifndef OPENSSL_NO_PSK {"psk_hint", OPT_PSK_HINT, 's', "PSK identity hint to use"}, @@ -911,10 +897,25 @@ const OPTIONS s_server_options[] = { {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"}, #ifndef OPENSSL_NO_SRP - {"srpvfile", OPT_SRPVFILE, '<', "The verifier file for SRP"}, + {"srpvfile", OPT_SRPVFILE, '<', "(deprecated) The verifier file for SRP"}, {"srpuserseed", OPT_SRPUSERSEED, 's', - "A seed string for a default user salt"}, + "(deprecated) A seed string for a default user salt"}, #endif + + OPT_SECTION("Protocol and version"), + {"max_early_data", OPT_MAX_EARLY, 'n', + "The maximum number of bytes of early data as advertised in tickets"}, + {"recv_max_early_data", OPT_RECV_MAX_EARLY, 'n', + "The maximum number of bytes of early data (hard limit)"}, + {"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"}, + {"num_tickets", OPT_S_NUM_TICKETS, 'n', + "The number of TLSv1.3 session tickets that a server will automatically issue" }, + {"anti_replay", OPT_ANTI_REPLAY, '-', "Switch on anti-replay protection (default)"}, + {"no_anti_replay", OPT_NO_ANTI_REPLAY, '-', "Switch off anti-replay protection"}, + {"http_server_binmode", OPT_HTTP_SERVER_BINMODE, '-', "opening files in binary mode when acting as http server (-WWW and -HTTP)"}, + {"no_ca_names", OPT_NOCANAMES, '-', + "Disable TLS Extension CA Names"}, + {"stateless", OPT_STATELESS, '-', "Require TLSv1.3 cookies"}, #ifndef OPENSSL_NO_SSL3 {"ssl3", OPT_SSL3, '-', "Just talk SSLv3"}, #endif @@ -932,12 +933,9 @@ const OPTIONS s_server_options[] = { #endif #ifndef OPENSSL_NO_DTLS {"dtls", OPT_DTLS, '-', "Use any DTLS version"}, - {"timeout", OPT_TIMEOUT, '-', "Enable timeouts"}, - {"mtu", OPT_MTU, 'p', "Set link layer MTU"}, {"listen", OPT_LISTEN, '-', "Listen for a DTLS ClientHello with a cookie and then connect"}, #endif - {"stateless", OPT_STATELESS, '-', "Require TLSv1.3 cookies"}, #ifndef OPENSSL_NO_DTLS1 {"dtls1", OPT_DTLS1, '-', "Just talk DTLSv1"}, #endif @@ -948,33 +946,27 @@ const OPTIONS s_server_options[] = { {"sctp", OPT_SCTP, '-', "Use SCTP"}, {"sctp_label_bug", OPT_SCTP_LABEL_BUG, '-', "Enable SCTP label length bug"}, #endif -#ifndef OPENSSL_NO_DH - {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, +#ifndef OPENSSL_NO_SRTP + {"use_srtp", OPT_SRTP_PROFILES, 's', + "Offer SRTP key management with a colon-separated profile list"}, #endif + {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, #ifndef OPENSSL_NO_NEXTPROTONEG {"nextprotoneg", OPT_NEXTPROTONEG, 's', "Set the advertised protocols for the NPN extension (comma-separated list)"}, #endif -#ifndef OPENSSL_NO_SRTP - {"use_srtp", OPT_SRTP_PROFILES, 's', - "Offer SRTP key management with a colon-separated profile list"}, -#endif {"alpn", OPT_ALPN, 's', "Set the advertised protocols for the ALPN extension (comma-separated list)"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#ifndef OPENSSL_NO_KTLS + {"sendfile", OPT_SENDFILE, '-', "Use sendfile to response file with -WWW"}, #endif - {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, - {"max_early_data", OPT_MAX_EARLY, 'n', - "The maximum number of bytes of early data as advertised in tickets"}, - {"recv_max_early_data", OPT_RECV_MAX_EARLY, 'n', - "The maximum number of bytes of early data (hard limit)"}, - {"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"}, - {"num_tickets", OPT_S_NUM_TICKETS, 'n', - "The number of TLSv1.3 session tickets that a server will automatically issue" }, - {"anti_replay", OPT_ANTI_REPLAY, '-', "Switch on anti-replay protection (default)"}, - {"no_anti_replay", OPT_NO_ANTI_REPLAY, '-', "Switch off anti-replay protection"}, - {NULL, OPT_EOF, 0, NULL} + + OPT_R_OPTIONS, + OPT_S_OPTIONS, + OPT_V_OPTIONS, + OPT_X_OPTIONS, + OPT_PROV_OPTIONS, + {NULL} }; #define IS_PROT_FLAG(o) \ @@ -993,28 +985,28 @@ int s_server_main(int argc, char *argv[]) STACK_OF(X509_CRL) *crls = NULL; X509 *s_cert = NULL, *s_dcert = NULL; X509_VERIFY_PARAM *vpm = NULL; - const char *CApath = NULL, *CAfile = NULL, *chCApath = NULL, *chCAfile = NULL; + const char *CApath = NULL, *CAfile = NULL, *CAstore = NULL; + const char *chCApath = NULL, *chCAfile = NULL, *chCAstore = NULL; char *dpassarg = NULL, *dpass = NULL; - char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; + char *passarg = NULL, *pass = NULL; + char *vfyCApath = NULL, *vfyCAfile = NULL, *vfyCAstore = NULL; char *crl_file = NULL, *prog; #ifdef AF_UNIX int unlink_unix_path = 0; #endif do_server_cb server_cb; int vpmtouched = 0, build_chain = 0, no_cache = 0, ext_cache = 0; -#ifndef OPENSSL_NO_DH char *dhfile = NULL; int no_dhe = 0; -#endif int nocert = 0, ret = 1; - int noCApath = 0, noCAfile = 0; - int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; - int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; + int noCApath = 0, noCAfile = 0, noCAstore = 0; + int s_cert_format = FORMAT_UNDEF, s_key_format = FORMAT_UNDEF; + int s_dcert_format = FORMAT_UNDEF, s_dkey_format = FORMAT_UNDEF; int rev = 0, naccept = -1, sdebug = 0; int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM, protocol = 0; - int state = 0, crl_format = FORMAT_PEM, crl_download = 0; + int state = 0, crl_format = FORMAT_UNDEF, crl_download = 0; char *host = NULL; - char *port = BUF_strdup(PORT); + char *port = NULL; unsigned char *context = NULL; OPTION_CHOICE o; EVP_PKEY *s_key2 = NULL; @@ -1056,9 +1048,11 @@ int s_server_main(int argc, char *argv[]) const char *keylog_file = NULL; int max_early_data = -1, recv_max_early_data = -1; char *psksessf = NULL; + int no_ca_names = 0; #ifndef OPENSSL_NO_SCTP int sctp_label_bug = 0; #endif + int ignore_unexpected_eof = 0; /* Init of few remaining global variables */ local_argc = argc; @@ -1073,10 +1067,12 @@ int s_server_main(int argc, char *argv[]) s_quiet = 0; s_brief = 0; async = 0; + use_sendfile = 0; + port = OPENSSL_strdup(PORT); cctx = SSL_CONF_CTX_new(); vpm = X509_VERIFY_PARAM_new(); - if (cctx == NULL || vpm == NULL) + if (port == NULL || cctx == NULL || vpm == NULL) goto end; SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CMDLINE); @@ -1163,7 +1159,9 @@ int s_server_main(int argc, char *argv[]) #ifdef AF_UNIX case OPT_UNIX: socket_family = AF_UNIX; - OPENSSL_free(host); host = BUF_strdup(opt_arg()); + OPENSSL_free(host); host = OPENSSL_strdup(opt_arg()); + if (host == NULL) + goto end; OPENSSL_free(port); port = NULL; break; case OPT_UNLINK: @@ -1209,7 +1207,7 @@ int s_server_main(int argc, char *argv[]) s_serverinfo_file = opt_arg(); break; case OPT_CERTFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &s_cert_format)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &s_cert_format)) goto opthelp; break; case OPT_KEY: @@ -1226,19 +1224,17 @@ int s_server_main(int argc, char *argv[]) s_chain_file = opt_arg(); break; case OPT_DHPARAM: -#ifndef OPENSSL_NO_DH dhfile = opt_arg(); -#endif break; case OPT_DCERTFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &s_dcert_format)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &s_dcert_format)) goto opthelp; break; case OPT_DCERT: s_dcert_file = opt_arg(); break; case OPT_DKEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &s_dkey_format)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &s_dkey_format)) goto opthelp; break; case OPT_DPASS: @@ -1265,6 +1261,18 @@ int s_server_main(int argc, char *argv[]) case OPT_VERIFYCAPATH: vfyCApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; + case OPT_NOCASTORE: + noCAstore = 1; + break; + case OPT_CHAINCASTORE: + chCAstore = opt_arg(); + break; + case OPT_VERIFYCASTORE: + vfyCAstore = opt_arg(); + break; case OPT_NO_CACHE: no_cache = 1; break; @@ -1352,14 +1360,23 @@ int s_server_main(int argc, char *argv[]) tlscstatp.timeout = atoi(opt_arg()); #endif break; + case OPT_PROXY: +#ifndef OPENSSL_NO_OCSP + tlscstatp.proxy = opt_arg(); +#endif + break; + case OPT_NO_PROXY: +#ifndef OPENSSL_NO_OCSP + tlscstatp.no_proxy = opt_arg(); +#endif + break; case OPT_STATUS_URL: #ifndef OPENSSL_NO_OCSP s_tlsextstatus = 1; - if (!OCSP_parse_url(opt_arg(), - &tlscstatp.host, - &tlscstatp.port, - &tlscstatp.path, &tlscstatp.use_ssl)) { - BIO_printf(bio_err, "Error parsing URL\n"); + if (!OSSL_HTTP_parse_url(opt_arg(), &tlscstatp.use_ssl, NULL, + &tlscstatp.host, &tlscstatp.port, NULL, + &tlscstatp.path, NULL, NULL)) { + BIO_printf(bio_err, "Error parsing -status_url argument\n"); goto end; } #endif @@ -1375,6 +1392,10 @@ int s_server_main(int argc, char *argv[]) break; case OPT_MSGFILE: bio_s_msg = BIO_new_file(opt_arg(), "w"); + if (bio_s_msg == NULL) { + BIO_printf(bio_err, "Error writing file %s\n", opt_arg()); + goto end; + } break; case OPT_TRACE: #ifndef OPENSSL_NO_SSL_TRACE @@ -1400,9 +1421,7 @@ int s_server_main(int argc, char *argv[]) s_quiet = s_brief = verify_args.quiet = 1; break; case OPT_NO_DHE: -#ifndef OPENSSL_NO_DH no_dhe = 1; -#endif break; case OPT_NO_RESUME_EPHEMERAL: no_resume_ephemeral = 1; @@ -1529,12 +1548,18 @@ int s_server_main(int argc, char *argv[]) session_id_prefix = opt_arg(); break; case OPT_ENGINE: - engine = setup_engine(opt_arg(), 1); +#ifndef OPENSSL_NO_ENGINE + engine = setup_engine(opt_arg(), s_debug); +#endif break; case OPT_R_CASES: if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_SERVERNAME: tlsextcbp.servername = opt_arg(); break; @@ -1603,10 +1628,30 @@ int s_server_main(int argc, char *argv[]) if (max_early_data == -1) max_early_data = SSL3_RT_MAX_PLAIN_LENGTH; break; + case OPT_HTTP_SERVER_BINMODE: + http_server_binmode = 1; + break; + case OPT_NOCANAMES: + no_ca_names = 1; + break; + case OPT_SENDFILE: +#ifndef OPENSSL_NO_KTLS + use_sendfile = 1; +#endif + break; + case OPT_IGNORE_UNEXPECTED_EOF: + ignore_unexpected_eof = 1; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); - argv = opt_rest(); + if (argc != 0) + goto opthelp; + + if (!app_RAND_load()) + goto end; #ifndef OPENSSL_NO_NEXTPROTONEG if (min_version == TLS1_3_VERSION && next_proto_neg_in != NULL) { @@ -1655,6 +1700,13 @@ int s_server_main(int argc, char *argv[]) } #endif +#ifndef OPENSSL_NO_KTLS + if (use_sendfile && www <= 1) { + BIO_printf(bio_err, "Can't use -sendfile without -WWW or -HTTP\n"); + goto end; + } +#endif + if (!app_passwd(passarg, dpassarg, &pass, &dpass)) { BIO_printf(bio_err, "Error getting password\n"); goto end; @@ -1671,40 +1723,32 @@ int s_server_main(int argc, char *argv[]) if (nocert == 0) { s_key = load_key(s_key_file, s_key_format, 0, pass, engine, - "server certificate private key file"); - if (s_key == NULL) { - ERR_print_errors(bio_err); + "server certificate private key"); + if (s_key == NULL) goto end; - } - s_cert = load_cert(s_cert_file, s_cert_format, - "server certificate file"); + s_cert = load_cert_pass(s_cert_file, s_cert_format, 1, pass, + "server certificate"); - if (s_cert == NULL) { - ERR_print_errors(bio_err); + if (s_cert == NULL) goto end; - } if (s_chain_file != NULL) { - if (!load_certs(s_chain_file, &s_chain, FORMAT_PEM, NULL, + if (!load_certs(s_chain_file, 0, &s_chain, NULL, "server certificate chain")) goto end; } if (tlsextcbp.servername != NULL) { s_key2 = load_key(s_key_file2, s_key_format, 0, pass, engine, - "second server certificate private key file"); - if (s_key2 == NULL) { - ERR_print_errors(bio_err); + "second server certificate private key"); + if (s_key2 == NULL) goto end; - } - s_cert2 = load_cert(s_cert_file2, s_cert_format, - "second server certificate file"); + s_cert2 = load_cert_pass(s_cert_file2, s_cert_format, 1, pass, + "second server certificate"); - if (s_cert2 == NULL) { - ERR_print_errors(bio_err); + if (s_cert2 == NULL) goto end; - } } } #if !defined(OPENSSL_NO_NEXTPROTONEG) @@ -1723,12 +1767,9 @@ int s_server_main(int argc, char *argv[]) if (crl_file != NULL) { X509_CRL *crl; - crl = load_crl(crl_file, crl_format); - if (crl == NULL) { - BIO_puts(bio_err, "Error loading CRL\n"); - ERR_print_errors(bio_err); + crl = load_crl(crl_file, crl_format, 0, "CRL"); + if (crl == NULL) goto end; - } crls = sk_X509_CRL_new_null(); if (crls == NULL || !sk_X509_CRL_push(crls, crl)) { BIO_puts(bio_err, "Error adding CRL\n"); @@ -1744,21 +1785,19 @@ int s_server_main(int argc, char *argv[]) s_dkey_file = s_dcert_file; s_dkey = load_key(s_dkey_file, s_dkey_format, - 0, dpass, engine, "second certificate private key file"); - if (s_dkey == NULL) { - ERR_print_errors(bio_err); + 0, dpass, engine, "second certificate private key"); + if (s_dkey == NULL) goto end; - } - s_dcert = load_cert(s_dcert_file, s_dcert_format, - "second server certificate file"); + s_dcert = load_cert_pass(s_dcert_file, s_dcert_format, 1, dpass, + "second server certificate"); if (s_dcert == NULL) { ERR_print_errors(bio_err); goto end; } if (s_dchain_file != NULL) { - if (!load_certs(s_dchain_file, &s_dchain, FORMAT_PEM, NULL, + if (!load_certs(s_dchain_file, 0, &s_dchain, NULL, "second server certificate chain")) goto end; } @@ -1768,17 +1807,22 @@ int s_server_main(int argc, char *argv[]) if (bio_s_out == NULL) { if (s_quiet && !s_debug) { bio_s_out = BIO_new(BIO_s_null()); - if (s_msg && bio_s_msg == NULL) + if (s_msg && bio_s_msg == NULL) { bio_s_msg = dup_bio_out(FORMAT_TEXT); + if (bio_s_msg == NULL) { + BIO_printf(bio_err, "Out of memory\n"); + goto end; + } + } } else { - if (bio_s_out == NULL) - bio_s_out = dup_bio_out(FORMAT_TEXT); + bio_s_out = dup_bio_out(FORMAT_TEXT); } } -#if !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC) - if (nocert) -#endif - { + + if (bio_s_out == NULL) + goto end; + + if (nocert) { s_cert_file = NULL; s_key_file = NULL; s_dcert_file = NULL; @@ -1787,7 +1831,7 @@ int s_server_main(int argc, char *argv[]) s_key_file2 = NULL; } - ctx = SSL_CTX_new(meth); + ctx = SSL_CTX_new_ex(app_get0_libctx(), app_get0_propq(), meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; @@ -1809,7 +1853,6 @@ int s_server_main(int argc, char *argv[]) goto end; } } - #ifndef OPENSSL_NO_SCTP if (protocol == IPPROTO_SCTP && sctp_label_bug == 1) SSL_CTX_set_mode(ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG); @@ -1833,7 +1876,6 @@ int s_server_main(int argc, char *argv[]) } BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); } - SSL_CTX_set_quiet_shutdown(ctx, 1); if (exc != NULL) ssl_ctx_set_excert(ctx, exc); @@ -1850,6 +1892,13 @@ int s_server_main(int argc, char *argv[]) SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC); } + if (no_ca_names) { + SSL_CTX_set_options(ctx, SSL_OP_DISABLE_TLSEXT_CA_NAMES); + } + + if (ignore_unexpected_eof) + SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); + if (max_send_fragment > 0 && !SSL_CTX_set_max_send_fragment(ctx, max_send_fragment)) { BIO_printf(bio_err, "%s: Max send fragment size %u is out of permitted range\n", @@ -1884,7 +1933,8 @@ int s_server_main(int argc, char *argv[]) } #endif - if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { + if (!ctx_set_verify_locations(ctx, CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) { ERR_print_errors(bio_err); goto end; } @@ -1896,7 +1946,9 @@ int s_server_main(int argc, char *argv[]) ssl_ctx_add_crls(ctx, crls, 0); - if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, + if (!ssl_load_stores(ctx, + vfyCApath, vfyCAfile, vfyCAstore, + chCApath, chCAfile, chCAstore, crls, crl_download)) { BIO_printf(bio_err, "Error loading store locations\n"); ERR_print_errors(bio_err); @@ -1904,7 +1956,7 @@ int s_server_main(int argc, char *argv[]) } if (s_cert2) { - ctx2 = SSL_CTX_new(meth); + ctx2 = SSL_CTX_new_ex(app_get0_libctx(), app_get0_propq(), meth); if (ctx2 == NULL) { ERR_print_errors(bio_err); goto end; @@ -1928,7 +1980,6 @@ int s_server_main(int argc, char *argv[]) } BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); } - SSL_CTX_set_quiet_shutdown(ctx2, 1); if (exc != NULL) ssl_ctx_set_excert(ctx2, exc); @@ -1945,8 +1996,8 @@ int s_server_main(int argc, char *argv[]) if (async) SSL_CTX_set_mode(ctx2, SSL_MODE_ASYNC); - if (!ctx_set_verify_locations(ctx2, CAfile, CApath, noCAfile, - noCApath)) { + if (!ctx_set_verify_locations(ctx2, CAfile, noCAfile, CApath, + noCApath, CAstore, noCAstore)) { ERR_print_errors(bio_err); goto end; } @@ -1968,54 +2019,70 @@ int s_server_main(int argc, char *argv[]) if (alpn_ctx.data) SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx); -#ifndef OPENSSL_NO_DH if (!no_dhe) { - DH *dh = NULL; + EVP_PKEY *dhpkey = NULL; if (dhfile != NULL) - dh = load_dh_param(dhfile); + dhpkey = load_keyparams(dhfile, FORMAT_UNDEF, 0, "DH", "DH parameters"); else if (s_cert_file != NULL) - dh = load_dh_param(s_cert_file); + dhpkey = load_keyparams_suppress(s_cert_file, FORMAT_UNDEF, 0, "DH", + "DH parameters", 1); - if (dh != NULL) { + if (dhpkey != NULL) { BIO_printf(bio_s_out, "Setting temp DH parameters\n"); } else { BIO_printf(bio_s_out, "Using default temp DH parameters\n"); } (void)BIO_flush(bio_s_out); - if (dh == NULL) { + if (dhpkey == NULL) { SSL_CTX_set_dh_auto(ctx, 1); - } else if (!SSL_CTX_set_tmp_dh(ctx, dh)) { - BIO_puts(bio_err, "Error setting temp DH parameters\n"); - ERR_print_errors(bio_err); - DH_free(dh); - goto end; + } else { + /* + * We need 2 references: one for use by ctx and one for use by + * ctx2 + */ + if (!EVP_PKEY_up_ref(dhpkey)) { + EVP_PKEY_free(dhpkey); + goto end; + } + if (!SSL_CTX_set0_tmp_dh_pkey(ctx, dhpkey)) { + BIO_puts(bio_err, "Error setting temp DH parameters\n"); + ERR_print_errors(bio_err); + /* Free 2 references */ + EVP_PKEY_free(dhpkey); + EVP_PKEY_free(dhpkey); + goto end; + } } if (ctx2 != NULL) { - if (!dhfile) { - DH *dh2 = load_dh_param(s_cert_file2); - if (dh2 != NULL) { + if (dhfile != NULL) { + EVP_PKEY *dhpkey2 = load_keyparams_suppress(s_cert_file2, + FORMAT_UNDEF, + 0, "DH", + "DH parameters", 1); + + if (dhpkey2 != NULL) { BIO_printf(bio_s_out, "Setting temp DH parameters\n"); (void)BIO_flush(bio_s_out); - DH_free(dh); - dh = dh2; + EVP_PKEY_free(dhpkey); + dhpkey = dhpkey2; } } - if (dh == NULL) { + if (dhpkey == NULL) { SSL_CTX_set_dh_auto(ctx2, 1); - } else if (!SSL_CTX_set_tmp_dh(ctx2, dh)) { + } else if (!SSL_CTX_set0_tmp_dh_pkey(ctx2, dhpkey)) { BIO_puts(bio_err, "Error setting temp DH parameters\n"); ERR_print_errors(bio_err); - DH_free(dh); + EVP_PKEY_free(dhpkey); goto end; } + dhpkey = NULL; } - DH_free(dh); + EVP_PKEY_free(dhpkey); } -#endif if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain, build_chain)) goto end; @@ -2050,10 +2117,16 @@ int s_server_main(int argc, char *argv[]) SSL_CTX_set_psk_server_callback(ctx, psk_server_cb); } - if (!SSL_CTX_use_psk_identity_hint(ctx, psk_identity_hint)) { - BIO_printf(bio_err, "error setting PSK identity hint to context\n"); - ERR_print_errors(bio_err); - goto end; + if (psk_identity_hint != NULL) { + if (min_version == TLS1_3_VERSION) { + BIO_printf(bio_s_out, "PSK warning: there is NO identity hint in TLSv1.3\n"); + } else { + if (!SSL_CTX_use_psk_identity_hint(ctx, psk_identity_hint)) { + BIO_printf(bio_err, "error setting PSK identity hint to context\n"); + ERR_print_errors(bio_err); + goto end; + } + } } #endif if (psksessf != NULL) { @@ -2112,20 +2185,9 @@ int s_server_main(int argc, char *argv[]) #ifndef OPENSSL_NO_SRP if (srp_verifier_file != NULL) { - srp_callback_parm.vb = SRP_VBASE_new(srpuserseed); - srp_callback_parm.user = NULL; - srp_callback_parm.login = NULL; - if ((ret = - SRP_VBASE_init(srp_callback_parm.vb, - srp_verifier_file)) != SRP_NO_ERROR) { - BIO_printf(bio_err, - "Cannot initialize SRP verifier file \"%s\":ret=%d\n", - srp_verifier_file, ret); + if (!set_up_srp_verifier_file(ctx, &srp_callback_parm, srpuserseed, + srp_verifier_file)) goto end; - } - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_callback); - SSL_CTX_set_srp_cb_arg(ctx, &srp_callback_parm); - SSL_CTX_set_srp_username_callback(ctx, ssl_srp_server_param_cb); } else #endif if (CAfile != NULL) { @@ -2236,8 +2298,8 @@ static void print_stats(BIO *bio, SSL_CTX *ssl_ctx) SSL_CTX_sess_get_cache_size(ssl_ctx)); } -static long int count_reads_callback(BIO *bio, int cmd, const char *argp, - int argi, long int argl, long int ret) +static long int count_reads_callback(BIO *bio, int cmd, const char *argp, size_t len, + int argi, long argl, int ret, size_t *processed) { unsigned int *p_counter = (unsigned int *)BIO_get_callback_arg(bio); @@ -2253,7 +2315,7 @@ static long int count_reads_callback(BIO *bio, int cmd, const char *argp, if (s_debug) { BIO_set_callback_arg(bio, (char *)bio_s_out); - ret = bio_dump_callback(bio, cmd, argp, argi, argl, ret); + ret = (int)bio_dump_callback(bio, cmd, argp, len, argi, argl, ret, processed); BIO_set_callback_arg(bio, (char *)p_counter); } @@ -2321,6 +2383,11 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) else # endif sbio = BIO_new_dgram(s, BIO_NOCLOSE); + if (sbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + ERR_print_errors(bio_err); + goto err; + } if (enable_timeouts) { timeout.tv_sec = 0; @@ -2370,6 +2437,13 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) BIO *test; test = BIO_new(BIO_f_nbio_test()); + if (test == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + ret = -1; + BIO_free(sbio); + goto err; + } + sbio = BIO_push(test, sbio); } @@ -2377,7 +2451,7 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) SSL_set_accept_state(con); /* SSL_set_fd(con,s); */ - BIO_set_callback(SSL_get_rbio(con), count_reads_callback); + BIO_set_callback_ex(SSL_get_rbio(con), count_reads_callback); if (s_msg) { #ifndef OPENSSL_NO_SSL_TRACE if (s_msg == 2) @@ -2536,14 +2610,6 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) */ goto err; } -#ifndef OPENSSL_NO_HEARTBEATS - if ((buf[0] == 'B') && ((buf[1] == '\n') || (buf[1] == '\r'))) { - BIO_printf(bio_err, "HEARTBEATING\n"); - SSL_heartbeat(con); - i = 0; - continue; - } -#endif if ((buf[0] == 'r') && ((buf[1] == '\n') || (buf[1] == '\r'))) { SSL_renegotiate(con); i = SSL_do_handshake(con); @@ -2585,8 +2651,8 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) continue; } if (buf[0] == 'P') { - static const char *str = "Lets print some clear text\n"; - BIO_write(SSL_get_wbio(con), str, strlen(str)); + static const char str[] = "Lets print some clear text\n"; + BIO_write(SSL_get_wbio(con), str, sizeof(str) -1); } if (buf[0] == 'S') { print_stats(bio_s_out, SSL_get_SSL_CTX(con)); @@ -2609,15 +2675,9 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) #ifndef OPENSSL_NO_SRP while (SSL_get_error(con, k) == SSL_ERROR_WANT_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP renego during write\n"); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); + + lookup_srp_user(&srp_callback_parm, bio_s_out); + k = SSL_write(con, &(buf[l]), (unsigned int)i); } #endif @@ -2688,7 +2748,6 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) ret = -1; goto err; } - if (i < 0) { ret = 0; goto err; @@ -2702,15 +2761,9 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) #ifndef OPENSSL_NO_SRP while (SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP renego during read\n"); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); + + lookup_srp_user(&srp_callback_parm, bio_s_out); + i = SSL_read(con, (char *)buf, bufsize); } #endif @@ -2757,7 +2810,7 @@ static int sv_body(int s, int stype, int prot, unsigned char *context) err: if (con != NULL) { BIO_printf(bio_s_out, "shutting down SSL\n"); - SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + do_ssl_shutdown(con); SSL_free(con); } BIO_printf(bio_s_out, "CONNECTION CLOSED\n"); @@ -2852,15 +2905,9 @@ static int init_ssl_connection(SSL *con) && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP during accept %s\n", srp_callback_parm.login); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); + + lookup_srp_user(&srp_callback_parm, bio_s_out); + i = SSL_accept(con); if (i <= 0) retry = is_retryable(con, i); @@ -2909,12 +2956,11 @@ static void print_connection_info(SSL *con) PEM_write_bio_SSL_SESSION(bio_s_out, SSL_get_session(con)); - peer = SSL_get_peer_certificate(con); + peer = SSL_get0_peer_certificate(con); if (peer != NULL) { BIO_printf(bio_s_out, "Client certificate\n"); PEM_write_bio_X509(bio_s_out, peer); dump_cert_text(bio_s_out, peer); - X509_free(peer); peer = NULL; } @@ -2959,11 +3005,11 @@ static void print_connection_info(SSL *con) BIO_printf(bio_s_out, " Label: '%s'\n", keymatexportlabel); BIO_printf(bio_s_out, " Length: %i bytes\n", keymatexportlen); exportedkeymat = app_malloc(keymatexportlen, "export key"); - if (!SSL_export_keying_material(con, exportedkeymat, + if (SSL_export_keying_material(con, exportedkeymat, keymatexportlen, keymatexportlabel, strlen(keymatexportlabel), - NULL, 0, 0)) { + NULL, 0, 0) <= 0) { BIO_printf(bio_s_out, " Error\n"); } else { BIO_printf(bio_s_out, " Keying material: "); @@ -2973,25 +3019,16 @@ static void print_connection_info(SSL *con) } OPENSSL_free(exportedkeymat); } +#ifndef OPENSSL_NO_KTLS + if (BIO_get_ktls_send(SSL_get_wbio(con))) + BIO_printf(bio_err, "Using Kernel TLS for sending\n"); + if (BIO_get_ktls_recv(SSL_get_rbio(con))) + BIO_printf(bio_err, "Using Kernel TLS for receiving\n"); +#endif (void)BIO_flush(bio_s_out); } -#ifndef OPENSSL_NO_DH -static DH *load_dh_param(const char *dhfile) -{ - DH *ret = NULL; - BIO *bio; - - if ((bio = BIO_new_file(dhfile, "r")) == NULL) - goto err; - ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - err: - BIO_free(bio); - return ret; -} -#endif - static int www_body(int s, int stype, int prot, unsigned char *context) { char *buf = NULL; @@ -3004,12 +3041,21 @@ static int www_body(int s, int stype, int prot, unsigned char *context) int total_bytes = 0; #endif int width; +#ifndef OPENSSL_NO_KTLS + int use_sendfile_for_req = use_sendfile; +#endif fd_set readfds; + const char *opmode; +#ifdef CHARSET_EBCDIC + BIO *filter; +#endif /* Set width for a select call if needed */ width = s + 1; - buf = app_malloc(bufsize, "server www buffer"); + /* as we use BIO_gets(), and it always null terminates data, we need + * to allocate 1 byte longer buffer to fit the full 2^14 byte record */ + buf = app_malloc(bufsize + 1, "server www buffer"); io = BIO_new(BIO_f_buffer()); ssl_bio = BIO_new(BIO_f_ssl()); if ((io == NULL) || (ssl_bio == NULL)) @@ -3023,7 +3069,7 @@ static int www_body(int s, int stype, int prot, unsigned char *context) } /* lets make the output buffer a reasonable size */ - if (!BIO_set_write_buffer_size(io, bufsize)) + if (BIO_set_write_buffer_size(io, bufsize) <= 0) goto err; if ((con = SSL_new(ctx)) == NULL) @@ -3042,10 +3088,21 @@ static int www_body(int s, int stype, int prot, unsigned char *context) } sbio = BIO_new_socket(s, BIO_NOCLOSE); + if (sbio == NULL) { + SSL_free(con); + goto err; + } + if (s_nbio_test) { BIO *test; test = BIO_new(BIO_f_nbio_test()); + if (test == NULL) { + SSL_free(con); + BIO_free(sbio); + goto err; + } + sbio = BIO_push(test, sbio); } SSL_set_bio(con, sbio, sbio); @@ -3054,12 +3111,17 @@ static int www_body(int s, int stype, int prot, unsigned char *context) /* No need to free |con| after this. Done by BIO_free(ssl_bio) */ BIO_set_ssl(ssl_bio, con, BIO_CLOSE); BIO_push(io, ssl_bio); + ssl_bio = NULL; #ifdef CHARSET_EBCDIC - io = BIO_push(BIO_new(BIO_f_ebcdic_filter()), io); + filter = BIO_new(BIO_f_ebcdic_filter()); + if (filter == NULL) + goto err; + + io = BIO_push(filter, io); #endif if (s_debug) { - BIO_set_callback(SSL_get_rbio(con), bio_dump_callback); + BIO_set_callback_ex(SSL_get_rbio(con), bio_dump_callback); BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out); } if (s_msg) { @@ -3073,7 +3135,7 @@ static int www_body(int s, int stype, int prot, unsigned char *context) } for (;;) { - i = BIO_gets(io, buf, bufsize - 1); + i = BIO_gets(io, buf, bufsize + 1); if (i < 0) { /* error */ if (!BIO_should_retry(io) && !SSL_waiting_for_async(con)) { if (!s_quiet) @@ -3085,21 +3147,13 @@ static int www_body(int s, int stype, int prot, unsigned char *context) if (BIO_should_io_special(io) && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP renego during read\n"); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); + + lookup_srp_user(&srp_callback_parm, bio_s_out); + continue; } #endif -#if !defined(OPENSSL_SYS_MSDOS) - sleep(1); -#endif + ossl_sleep(1000); continue; } } else if (i == 0) { /* end of input */ @@ -3146,7 +3200,7 @@ static int www_body(int s, int stype, int prot, unsigned char *context) * we're expecting to come from the client. If they haven't * sent one there's not much we can do. */ - BIO_gets(io, buf, bufsize - 1); + BIO_gets(io, buf, bufsize + 1); } BIO_puts(io, @@ -3228,12 +3282,11 @@ static int www_body(int s, int stype, int prot, unsigned char *context) BIO_printf(io, "---\n"); print_stats(io, SSL_get_SSL_CTX(con)); BIO_printf(io, "---\n"); - peer = SSL_get_peer_certificate(con); + peer = SSL_get0_peer_certificate(con); if (peer != NULL) { BIO_printf(io, "Client certificate\n"); X509_print(io, peer); PEM_write_bio_X509(io, peer); - X509_free(peer); peer = NULL; } else { BIO_puts(io, "no client certificate available\n"); @@ -3304,9 +3357,10 @@ static int www_body(int s, int stype, int prot, unsigned char *context) break; } - if ((file = BIO_new_file(p, "r")) == NULL) { + opmode = (http_server_binmode == 1) ? "rb" : "r"; + if ((file = BIO_new_file(p, opmode)) == NULL) { BIO_puts(io, text); - BIO_printf(io, "Error opening '%s'\r\n", p); + BIO_printf(io, "Error opening '%s' mode='%s'\r\n", p, opmode); ERR_print_errors(io); break; } @@ -3326,38 +3380,83 @@ static int www_body(int s, int stype, int prot, unsigned char *context) "HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n"); } /* send the file */ - for (;;) { - i = BIO_read(file, buf, bufsize); - if (i <= 0) - break; +#ifndef OPENSSL_NO_KTLS + if (use_sendfile_for_req && !BIO_get_ktls_send(SSL_get_wbio(con))) { + BIO_printf(bio_err, "Warning: sendfile requested but KTLS is not available\n"); + use_sendfile_for_req = 0; + } + if (use_sendfile_for_req) { + FILE *fp = NULL; + int fd; + struct stat st; + off_t offset = 0; + size_t filesize; + + BIO_get_fp(file, &fp); + fd = fileno(fp); + if (fstat(fd, &st) < 0) { + BIO_printf(io, "Error fstat '%s'\r\n", p); + ERR_print_errors(io); + goto write_error; + } -#ifdef RENEG - total_bytes += i; - BIO_printf(bio_err, "%d\n", i); - if (total_bytes > 3 * 1024) { - total_bytes = 0; - BIO_printf(bio_err, "RENEGOTIATE\n"); - SSL_renegotiate(con); + filesize = st.st_size; + if (((int)BIO_flush(io)) < 0) + goto write_error; + + for (;;) { + i = SSL_sendfile(con, fd, offset, filesize, 0); + if (i < 0) { + BIO_printf(io, "Error SSL_sendfile '%s'\r\n", p); + ERR_print_errors(io); + break; + } else { + offset += i; + filesize -= i; + } + + if (filesize <= 0) { + if (!s_quiet) + BIO_printf(bio_err, "KTLS SENDFILE '%s' OK\n", p); + + break; + } } + } else #endif + { + for (;;) { + i = BIO_read(file, buf, bufsize); + if (i <= 0) + break; - for (j = 0; j < i;) { #ifdef RENEG - static count = 0; - if (++count == 13) { + total_bytes += i; + BIO_printf(bio_err, "%d\n", i); + if (total_bytes > 3 * 1024) { + total_bytes = 0; + BIO_printf(bio_err, "RENEGOTIATE\n"); SSL_renegotiate(con); } #endif - k = BIO_write(io, &(buf[j]), i - j); - if (k <= 0) { - if (!BIO_should_retry(io) - && !SSL_waiting_for_async(con)) - goto write_error; - else { - BIO_printf(bio_s_out, "rwrite W BLOCK\n"); + + for (j = 0; j < i;) { +#ifdef RENEG + static count = 0; + if (++count == 13) + SSL_renegotiate(con); +#endif + k = BIO_write(io, &(buf[j]), i - j); + if (k <= 0) { + if (!BIO_should_retry(io) + && !SSL_waiting_for_async(con)) { + goto write_error; + } else { + BIO_printf(bio_s_out, "rwrite W BLOCK\n"); + } + } else { + j += k; } - } else { - j += k; } } } @@ -3377,10 +3476,11 @@ static int www_body(int s, int stype, int prot, unsigned char *context) } end: /* make sure we re-use sessions */ - SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + do_ssl_shutdown(con); err: OPENSSL_free(buf); + BIO_free(ssl_bio); BIO_free_all(io); return ret; } @@ -3392,15 +3492,20 @@ static int rev_body(int s, int stype, int prot, unsigned char *context) int ret = 1; SSL *con; BIO *io, *ssl_bio, *sbio; +#ifdef CHARSET_EBCDIC + BIO *filter; +#endif - buf = app_malloc(bufsize, "server rev buffer"); + /* as we use BIO_gets(), and it always null terminates data, we need + * to allocate 1 byte longer buffer to fit the full 2^14 byte record */ + buf = app_malloc(bufsize + 1, "server rev buffer"); io = BIO_new(BIO_f_buffer()); ssl_bio = BIO_new(BIO_f_ssl()); if ((io == NULL) || (ssl_bio == NULL)) goto err; /* lets make the output buffer a reasonable size */ - if (!BIO_set_write_buffer_size(io, bufsize)) + if (BIO_set_write_buffer_size(io, bufsize) <= 0) goto err; if ((con = SSL_new(ctx)) == NULL) @@ -3419,18 +3524,29 @@ static int rev_body(int s, int stype, int prot, unsigned char *context) } sbio = BIO_new_socket(s, BIO_NOCLOSE); + if (sbio == NULL) { + SSL_free(con); + ERR_print_errors(bio_err); + goto err; + } + SSL_set_bio(con, sbio, sbio); SSL_set_accept_state(con); /* No need to free |con| after this. Done by BIO_free(ssl_bio) */ BIO_set_ssl(ssl_bio, con, BIO_CLOSE); BIO_push(io, ssl_bio); + ssl_bio = NULL; #ifdef CHARSET_EBCDIC - io = BIO_push(BIO_new(BIO_f_ebcdic_filter()), io); + filter = BIO_new(BIO_f_ebcdic_filter()); + if (filter == NULL) + goto err; + + io = BIO_push(filter, io); #endif if (s_debug) { - BIO_set_callback(SSL_get_rbio(con), bio_dump_callback); + BIO_set_callback_ex(SSL_get_rbio(con), bio_dump_callback); BIO_set_callback_arg(SSL_get_rbio(con), (char *)bio_s_out); } if (s_msg) { @@ -3456,15 +3572,9 @@ static int rev_body(int s, int stype, int prot, unsigned char *context) if (BIO_should_io_special(io) && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP renego during accept\n"); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); + + lookup_srp_user(&srp_callback_parm, bio_s_out); + continue; } #endif @@ -3473,7 +3583,7 @@ static int rev_body(int s, int stype, int prot, unsigned char *context) print_ssl_summary(con); for (;;) { - i = BIO_gets(io, buf, bufsize - 1); + i = BIO_gets(io, buf, bufsize + 1); if (i < 0) { /* error */ if (!BIO_should_retry(io)) { if (!s_quiet) @@ -3485,21 +3595,13 @@ static int rev_body(int s, int stype, int prot, unsigned char *context) if (BIO_should_io_special(io) && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP renego during read\n"); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); + + lookup_srp_user(&srp_callback_parm, bio_s_out); + continue; } #endif -#if !defined(OPENSSL_SYS_MSDOS) - sleep(1); -#endif + ossl_sleep(1000); continue; } } else if (i == 0) { /* end of input */ @@ -3531,11 +3633,12 @@ static int rev_body(int s, int stype, int prot, unsigned char *context) } end: /* make sure we re-use sessions */ - SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + do_ssl_shutdown(con); err: OPENSSL_free(buf); + BIO_free(ssl_bio); BIO_free_all(io); return ret; } @@ -3545,6 +3648,8 @@ static int generate_session_id(SSL *ssl, unsigned char *id, unsigned int *id_len) { unsigned int count = 0; + unsigned int session_id_prefix_len = strlen(session_id_prefix); + do { if (RAND_bytes(id, *id_len) <= 0) return 0; @@ -3556,8 +3661,8 @@ static int generate_session_id(SSL *ssl, unsigned char *id, * conflicts. */ memcpy(id, session_id_prefix, - (strlen(session_id_prefix) < *id_len) ? - strlen(session_id_prefix) : *id_len); + (session_id_prefix_len < *id_len) ? + session_id_prefix_len : *id_len); } while (SSL_has_matching_session_id(ssl, id, *id_len) && (++count < MAX_SESSION_ID_ATTEMPTS)); @@ -3568,7 +3673,7 @@ static int generate_session_id(SSL *ssl, unsigned char *id, /* * By default s_server uses an in-memory cache which caches SSL_SESSION - * structures without any serialisation. This hides some bugs which only + * structures without any serialization. This hides some bugs which only * become apparent in deployed servers. By implementing a basic external * session cache some issues can be debugged using s_server. */ diff --git a/apps/s_time.c b/apps/s_time.c index 1235e545c20a..1a58e19de53f 100644 --- a/apps/s_time.c +++ b/apps/s_time.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -22,9 +22,9 @@ #include <openssl/pem.h> #include "s_apps.h" #include <openssl/err.h> -#include <internal/sockets.h> +#include "internal/sockets.h" #if !defined(OPENSSL_SYS_MSDOS) -# include OPENSSL_UNISTD +# include <unistd.h> #endif #define SSL_CONNECT_NAME "localhost:4433" @@ -43,40 +43,64 @@ static const char fmt_http_get_cmd[] = "GET %s HTTP/1.0\r\n\r\n"; static const size_t fmt_http_get_cmd_size = sizeof(fmt_http_get_cmd) - 2; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_CONNECT, OPT_CIPHER, OPT_CIPHERSUITES, OPT_CERT, OPT_NAMEOPT, OPT_KEY, - OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NEW, OPT_REUSE, - OPT_BUGS, OPT_VERIFY, OPT_TIME, OPT_SSL3, - OPT_WWW + OPT_CAPATH, OPT_CAFILE, OPT_CASTORE, + OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, + OPT_NEW, OPT_REUSE, OPT_BUGS, OPT_VERIFY, OPT_TIME, OPT_SSL3, + OPT_WWW, OPT_TLS1, OPT_TLS1_1, OPT_TLS1_2, OPT_TLS1_3, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS s_time_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_SECTION("Connection"), {"connect", OPT_CONNECT, 's', "Where to connect as post:port (default is " SSL_CONNECT_NAME ")"}, + {"new", OPT_NEW, '-', "Just time new connections"}, + {"reuse", OPT_REUSE, '-', "Just time connection reuse"}, + {"bugs", OPT_BUGS, '-', "Turn on SSL bug compatibility"}, {"cipher", OPT_CIPHER, 's', "TLSv1.2 and below cipher list to be used"}, {"ciphersuites", OPT_CIPHERSUITES, 's', "Specify TLSv1.3 ciphersuites to be used"}, +#ifndef OPENSSL_NO_SSL3 + {"ssl3", OPT_SSL3, '-', "Just use SSLv3"}, +#endif +#ifndef OPENSSL_NO_TLS1 + {"tls1", OPT_TLS1, '-', "Just use TLSv1.0"}, +#endif +#ifndef OPENSSL_NO_TLS1_1 + {"tls1_1", OPT_TLS1_1, '-', "Just use TLSv1.1"}, +#endif +#ifndef OPENSSL_NO_TLS1_2 + {"tls1_2", OPT_TLS1_2, '-', "Just use TLSv1.2"}, +#endif +#ifndef OPENSSL_NO_TLS1_3 + {"tls1_3", OPT_TLS1_3, '-', "Just use TLSv1.3"}, +#endif + {"verify", OPT_VERIFY, 'p', + "Turn on peer certificate verification, set depth"}, + {"time", OPT_TIME, 'p', "Seconds to collect data, default " SECONDSSTR}, + {"www", OPT_WWW, 's', "Fetch specified page from the site"}, + + OPT_SECTION("Certificate"), + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, {"cert", OPT_CERT, '<', "Cert file to use, PEM format assumed"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, {"key", OPT_KEY, '<', "File with key, PEM; default is -cert file"}, - {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, {"cafile", OPT_CAFILE, '<', "PEM format file of CA's"}, {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, + {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, + {"CAstore", OPT_CASTORE, ':', "URI to store of CA's"}, {"no-CAfile", OPT_NOCAFILE, '-', "Do not load the default certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', "Do not load certificates from the default certificates directory"}, - {"new", OPT_NEW, '-', "Just time new connections"}, - {"reuse", OPT_REUSE, '-', "Just time connection reuse"}, - {"bugs", OPT_BUGS, '-', "Turn on SSL bug compatibility"}, - {"verify", OPT_VERIFY, 'p', - "Turn on peer certificate verification, set depth"}, - {"time", OPT_TIME, 'p', "Seconds to collect data, default " SECONDSSTR}, - {"www", OPT_WWW, 's', "Fetch specified page from the site"}, -#ifndef OPENSSL_NO_SSL3 - {"ssl3", OPT_SSL3, '-', "Just use SSLv3"}, -#endif + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store URI"}, + + OPT_PROV_OPTIONS, {NULL} }; @@ -94,15 +118,16 @@ int s_time_main(int argc, char **argv) SSL *scon = NULL; SSL_CTX *ctx = NULL; const SSL_METHOD *meth = NULL; - char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *ciphersuites = NULL; + char *CApath = NULL, *CAfile = NULL, *CAstore = NULL; + char *cipher = NULL, *ciphersuites = NULL; char *www_path = NULL; char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog; double totalTime = 0.0; - int noCApath = 0, noCAfile = 0; + int noCApath = 0, noCAfile = 0, noCAstore = 0; int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0; long bytes_read = 0, finishtime = 0; OPTION_CHOICE o; - int max_version = 0, ver, buf_len; + int min_version = 0, max_version = 0, ver, buf_len, fd; size_t buf_size; meth = TLS_client_method(); @@ -129,8 +154,7 @@ int s_time_main(int argc, char **argv) perform = 1; break; case OPT_VERIFY: - if (!opt_int(opt_arg(), &verify_args.depth)) - goto opthelp; + verify_args.depth = opt_int_arg(); BIO_printf(bio_err, "%s: verify depth is %d\n", prog, verify_args.depth); break; @@ -156,6 +180,12 @@ int s_time_main(int argc, char **argv) case OPT_NOCAFILE: noCAfile = 1; break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_CIPHER: cipher = opt_arg(); break; @@ -166,8 +196,7 @@ int s_time_main(int argc, char **argv) st_bugs = 1; break; case OPT_TIME: - if (!opt_int(opt_arg(), &maxtime)) - goto opthelp; + maxtime = opt_int_arg(); break; case OPT_WWW: www_path = opt_arg(); @@ -178,10 +207,33 @@ int s_time_main(int argc, char **argv) } break; case OPT_SSL3: + min_version = SSL3_VERSION; max_version = SSL3_VERSION; break; + case OPT_TLS1: + min_version = TLS1_VERSION; + max_version = TLS1_VERSION; + break; + case OPT_TLS1_1: + min_version = TLS1_1_VERSION; + max_version = TLS1_1_VERSION; + break; + case OPT_TLS1_2: + min_version = TLS1_2_VERSION; + max_version = TLS1_2_VERSION; + break; + case OPT_TLS1_3: + min_version = TLS1_3_VERSION; + max_version = TLS1_3_VERSION; + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; @@ -192,8 +244,9 @@ int s_time_main(int argc, char **argv) if ((ctx = SSL_CTX_new(meth)) == NULL) goto end; - SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_quiet_shutdown(ctx, 1); + if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) + goto end; if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) goto end; @@ -206,7 +259,8 @@ int s_time_main(int argc, char **argv) if (!set_cert_stuff(ctx, certfile, keyfile)) goto end; - if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { + if (!ctx_set_verify_locations(ctx, CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) { ERR_print_errors(bio_err); goto end; } @@ -289,7 +343,8 @@ int s_time_main(int argc, char **argv) continue; } SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); - BIO_closesocket(SSL_get_fd(scon)); + if ((fd = SSL_get_fd(scon)) >= 0) + BIO_closesocket(fd); nConn = 0; totalTime = 0.0; @@ -316,7 +371,8 @@ int s_time_main(int argc, char **argv) bytes_read += i; } SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); - BIO_closesocket(SSL_get_fd(scon)); + if ((fd = SSL_get_fd(scon)) >= 0) + BIO_closesocket(fd); nConn += 1; if (SSL_session_reused(scon)) { @@ -338,10 +394,13 @@ int s_time_main(int argc, char **argv) printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); - printf - ("%d connections in %ld real seconds, %ld bytes read per connection\n", - nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); - + if (nConn > 0) + printf + ("%d connections in %ld real seconds, %ld bytes read per connection\n", + nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); + else + printf("0 connections in %ld real seconds\n", + (long)time(NULL) - finishtime + maxtime); ret = 0; end: @@ -362,12 +421,19 @@ static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx) if ((conn = BIO_new(BIO_s_connect())) == NULL) return NULL; - BIO_set_conn_hostname(conn, host); - BIO_set_conn_mode(conn, BIO_SOCK_NODELAY); + if (BIO_set_conn_hostname(conn, host) <= 0 + || BIO_set_conn_mode(conn, BIO_SOCK_NODELAY) <= 0) { + BIO_free(conn); + return NULL; + } - if (scon == NULL) + if (scon == NULL) { serverCon = SSL_new(ctx); - else { + if (serverCon == NULL) { + BIO_free(conn); + return NULL; + } + } else { serverCon = scon; SSL_set_connect_state(serverCon); } diff --git a/apps/sess_id.c b/apps/sess_id.c index 8fd584f3b131..714c0f77877e 100644 --- a/apps/sess_id.c +++ b/apps/sess_id.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -19,22 +19,27 @@ #include <openssl/ssl.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_CERT, OPT_NOOUT, OPT_CONTEXT } OPTION_CHOICE; const OPTIONS sess_id_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"context", OPT_CONTEXT, 's', "Set the session ID context"}, + + OPT_SECTION("Input"), + {"in", OPT_IN, 's', "Input file - default stdin"}, {"inform", OPT_INFORM, 'F', "Input format - default PEM (DER or PEM)"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file - default stdout"}, {"outform", OPT_OUTFORM, 'f', "Output format - default PEM (PEM, DER or NSS)"}, - {"in", OPT_IN, 's', "Input file - default stdin"}, - {"out", OPT_OUT, '>', "Output file - default stdout"}, {"text", OPT_TEXT, '-', "Print ssl session id details"}, {"cert", OPT_CERT, '-', "Output certificate "}, {"noout", OPT_NOOUT, '-', "Don't output the encoded session info"}, - {"context", OPT_CONTEXT, 's', "Set the session ID context"}, {NULL} }; @@ -91,6 +96,8 @@ int sess_id_main(int argc, char **argv) break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; diff --git a/apps/smime.c b/apps/smime.c index 6fd473775f45..a2ff0b5be75c 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -1,7 +1,7 @@ /* - * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -33,7 +33,7 @@ static int smime_cb(int ok, X509_STORE_CTX *ctx); #define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS) typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_ENCRYPT, OPT_DECRYPT, OPT_SIGN, OPT_RESIGN, OPT_VERIFY, OPT_PK7OUT, OPT_TEXT, OPT_NOINTERN, OPT_NOVERIFY, OPT_NOCHAIN, OPT_NOCERTS, OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP, @@ -41,76 +41,97 @@ typedef enum OPTION_choice { OPT_CRLFEOL, OPT_ENGINE, OPT_PASSIN, OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP, OPT_MD, OPT_CIPHER, OPT_INKEY, OPT_KEYFORM, OPT_CERTFILE, OPT_CAFILE, - OPT_R_ENUM, + OPT_CAPATH, OPT_CASTORE, OPT_NOCAFILE, OPT_NOCAPATH, OPT_NOCASTORE, + OPT_R_ENUM, OPT_PROV_ENUM, OPT_CONFIG, OPT_V_ENUM, - OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH, OPT_IN, OPT_INFORM, OPT_OUT, + OPT_IN, OPT_INFORM, OPT_OUT, OPT_OUTFORM, OPT_CONTENT } OPTION_CHOICE; const OPTIONS smime_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"}, - {OPT_HELP_STR, 1, '-', - " cert.pem... recipient certs for encryption\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert...]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"in", OPT_IN, '<', "Input file"}, + {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"}, + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'c', + "Output format SMIME (default), PEM or DER"}, + {"inkey", OPT_INKEY, 's', + "Input private key (if not signer or recipient)"}, + {"keyform", OPT_KEYFORM, 'f', "Input private key format (ENGINE, other values ignored)"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + {"stream", OPT_STREAM, '-', "Enable CMS streaming" }, + {"indef", OPT_INDEF, '-', "Same as -stream" }, + {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"}, + OPT_CONFIG_OPTION, + + OPT_SECTION("Action"), {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"}, {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"}, {"sign", OPT_SIGN, '-', "Sign message"}, + {"resign", OPT_RESIGN, '-', "Resign a signed message"}, {"verify", OPT_VERIFY, '-', "Verify signed message"}, + + OPT_SECTION("Signing/Encryption"), + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"}, + {"", OPT_CIPHER, '-', "Any supported cipher"}, {"pk7out", OPT_PK7OUT, '-', "Output PKCS#7 structure"}, {"nointern", OPT_NOINTERN, '-', "Don't search certificates in message for signer"}, - {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, - {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"}, - {"nocerts", OPT_NOCERTS, '-', - "Don't include signers certificate when signing"}, {"nodetach", OPT_NODETACH, '-', "Use opaque signing"}, {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"}, {"binary", OPT_BINARY, '-', "Don't translate message to text"}, - {"certfile", OPT_CERTFILE, '<', "Other certificates file"}, {"signer", OPT_SIGNER, 's', "Signer certificate file"}, - {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"}, - {"in", OPT_IN, '<', "Input file"}, - {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"}, - {"inkey", OPT_INKEY, 's', - "Input private key (if not signer or recipient)"}, - {"keyform", OPT_KEYFORM, 'f', "Input private key format (PEM or ENGINE)"}, - {"out", OPT_OUT, '>', "Output file"}, - {"outform", OPT_OUTFORM, 'c', - "Output format SMIME (default), PEM or DER"}, {"content", OPT_CONTENT, '<', "Supply or override content for detached signature"}, + {"nocerts", OPT_NOCERTS, '-', + "Don't include signers certificate when signing"}, + + OPT_SECTION("Verification/Decryption"), + {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, + {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"}, + + {"certfile", OPT_CERTFILE, '<', "Other certificates file"}, + {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"}, + + OPT_SECTION("Email"), {"to", OPT_TO, 's', "To address"}, {"from", OPT_FROM, 's', "From address"}, {"subject", OPT_SUBJECT, 's', "Subject"}, {"text", OPT_TEXT, '-', "Include or delete text MIME headers"}, + {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, + + OPT_SECTION("Certificate chain"), {"CApath", OPT_CAPATH, '/', "Trusted certificates directory"}, {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, + {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"}, {"no-CAfile", OPT_NOCAFILE, '-', "Do not load the default certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', "Do not load certificates from the default certificates directory"}, - {"resign", OPT_RESIGN, '-', "Resign a signed message"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store"}, {"nochain", OPT_NOCHAIN, '-', "set PKCS7_NOCHAIN so certificates contained in the message are not used as untrusted CAs" }, - {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, - {"stream", OPT_STREAM, '-', "Enable CMS streaming" }, - {"indef", OPT_INDEF, '-', "Same as -stream" }, - {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"}, {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only"}, + OPT_R_OPTIONS, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"}, - {"", OPT_CIPHER, '-', "Any supported cipher"}, OPT_V_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"cert", 0, 0, "Recipient certs, used when encrypting"}, {NULL} }; int smime_main(int argc, char **argv) { + CONF *conf = NULL; BIO *in = NULL, *out = NULL, *indata = NULL; EVP_PKEY *key = NULL; PKCS7 *p7 = NULL; @@ -119,20 +140,22 @@ int smime_main(int argc, char **argv) X509 *cert = NULL, *recip = NULL, *signer = NULL; X509_STORE *store = NULL; X509_VERIFY_PARAM *vpm = NULL; - const EVP_CIPHER *cipher = NULL; - const EVP_MD *sign_md = NULL; - const char *CAfile = NULL, *CApath = NULL, *prog = NULL; + EVP_CIPHER *cipher = NULL; + EVP_MD *sign_md = NULL; + const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL, *prog = NULL; char *certfile = NULL, *keyfile = NULL, *contfile = NULL; char *infile = NULL, *outfile = NULL, *signerfile = NULL, *recipfile = NULL; - char *passinarg = NULL, *passin = NULL, *to = NULL, *from = NULL, *subject = NULL; + char *passinarg = NULL, *passin = NULL, *to = NULL, *from = NULL; + char *subject = NULL, *digestname = NULL, *ciphername = NULL; OPTION_CHOICE o; - int noCApath = 0, noCAfile = 0; + int noCApath = 0, noCAfile = 0, noCAstore = 0; int flags = PKCS7_DETACHED, operation = 0, ret = 0, indef = 0; int informat = FORMAT_SMIME, outformat = FORMAT_SMIME, keyform = - FORMAT_PEM; + FORMAT_UNDEF; int vpmtouched = 0, rv = 0; ENGINE *e = NULL; const char *mime_eol = "\n"; + OSSL_LIB_CTX *libctx = app_get0_libctx(); if ((vpm = X509_VERIFY_PARAM_new()) == NULL) return 1; @@ -226,6 +249,15 @@ int smime_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; + case OPT_CONFIG: + conf = app_load_config_modules(opt_arg()); + if (conf == NULL) + goto end; + break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; @@ -262,12 +294,10 @@ int smime_main(int argc, char **argv) recipfile = opt_arg(); break; case OPT_MD: - if (!opt_md(opt_arg(), &sign_md)) - goto opthelp; + digestname = opt_arg(); break; case OPT_CIPHER: - if (!opt_cipher(opt_unknown(), &cipher)) - goto opthelp; + ciphername = opt_unknown(); break; case OPT_INKEY: /* If previous -inkey argument add signer to list */ @@ -302,12 +332,18 @@ int smime_main(int argc, char **argv) case OPT_CAPATH: CApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_NOCAFILE: noCAfile = 1; break; case OPT_NOCAPATH: noCApath = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_CONTENT: contfile = opt_arg(); break; @@ -318,13 +354,31 @@ int smime_main(int argc, char **argv) break; } } + + /* Extra arguments are files with recipient keys. */ argc = opt_num_rest(); argv = opt_rest(); + if (!app_RAND_load()) + goto end; + + if (digestname != NULL) { + if (!opt_md(digestname, &sign_md)) + goto opthelp; + } + if (ciphername != NULL) { + if (!opt_cipher_any(ciphername, &cipher)) + goto opthelp; + } if (!(operation & SMIME_SIGNERS) && (skkeys != NULL || sksigners != NULL)) { BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); goto opthelp; } + if (!operation) { + BIO_puts(bio_err, + "No operation (-encrypt|-sign|...) specified\n"); + goto opthelp; + } if (operation & SMIME_SIGNERS) { /* Check to see if any final signer needs to be appended */ @@ -360,8 +414,6 @@ int smime_main(int argc, char **argv) BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); goto opthelp; } - } else if (!operation) { - goto opthelp; } if (!app_passwd(passinarg, NULL, &passin, NULL)) { @@ -387,7 +439,7 @@ int smime_main(int argc, char **argv) if (operation == SMIME_ENCRYPT) { if (cipher == NULL) { #ifndef OPENSSL_NO_DES - cipher = EVP_des_ede3_cbc(); + cipher = (EVP_CIPHER *)EVP_des_ede3_cbc(); #else BIO_printf(bio_err, "No cipher selected\n"); goto end; @@ -397,7 +449,7 @@ int smime_main(int argc, char **argv) if (encerts == NULL) goto end; while (*argv != NULL) { - cert = load_cert(*argv, FORMAT_PEM, + cert = load_cert(*argv, FORMAT_UNDEF, "recipient certificate file"); if (cert == NULL) goto end; @@ -408,15 +460,14 @@ int smime_main(int argc, char **argv) } if (certfile != NULL) { - if (!load_certs(certfile, &other, FORMAT_PEM, NULL, - "certificate file")) { + if (!load_certs(certfile, 0, &other, NULL, "certificates")) { ERR_print_errors(bio_err); goto end; } } if (recipfile != NULL && (operation == SMIME_DECRYPT)) { - if ((recip = load_cert(recipfile, FORMAT_PEM, + if ((recip = load_cert(recipfile, FORMAT_UNDEF, "recipient certificate file")) == NULL) { ERR_print_errors(bio_err); goto end; @@ -434,7 +485,7 @@ int smime_main(int argc, char **argv) } if (keyfile != NULL) { - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key"); if (key == NULL) goto end; } @@ -444,18 +495,25 @@ int smime_main(int argc, char **argv) goto end; if (operation & SMIME_IP) { + PKCS7 *p7_in = NULL; + + p7 = PKCS7_new_ex(libctx, app_get0_propq()); + if (p7 == NULL) { + BIO_printf(bio_err, "Error allocating PKCS7 object\n"); + goto end; + } if (informat == FORMAT_SMIME) { - p7 = SMIME_read_PKCS7(in, &indata); + p7_in = SMIME_read_PKCS7_ex(in, &indata, &p7); } else if (informat == FORMAT_PEM) { - p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + p7_in = PEM_read_bio_PKCS7(in, &p7, NULL, NULL); } else if (informat == FORMAT_ASN1) { - p7 = d2i_PKCS7_bio(in, NULL); + p7_in = d2i_PKCS7_bio(in, &p7); } else { BIO_printf(bio_err, "Bad input format for PKCS#7 file\n"); goto end; } - if (p7 == NULL) { + if (p7_in == NULL) { BIO_printf(bio_err, "Error reading S/MIME message\n"); goto end; } @@ -473,7 +531,8 @@ int smime_main(int argc, char **argv) goto end; if (operation == SMIME_VERIFY) { - if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) + if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) == NULL) goto end; X509_STORE_set_verify_cb(store, smime_cb); if (vpmtouched) @@ -485,7 +544,7 @@ int smime_main(int argc, char **argv) if (operation == SMIME_ENCRYPT) { if (indef) flags |= PKCS7_STREAM; - p7 = PKCS7_encrypt(encerts, in, cipher, flags); + p7 = PKCS7_encrypt_ex(encerts, in, cipher, flags, libctx, app_get0_propq()); } else if (operation & SMIME_SIGNERS) { int i; /* @@ -500,7 +559,7 @@ int smime_main(int argc, char **argv) flags |= PKCS7_STREAM; } flags |= PKCS7_PARTIAL; - p7 = PKCS7_sign(NULL, NULL, other, in, flags); + p7 = PKCS7_sign_ex(NULL, NULL, other, in, flags, libctx, app_get0_propq()); if (p7 == NULL) goto end; if (flags & PKCS7_NOCERTS) { @@ -515,13 +574,13 @@ int smime_main(int argc, char **argv) for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { signerfile = sk_OPENSSL_STRING_value(sksigners, i); keyfile = sk_OPENSSL_STRING_value(skkeys, i); - signer = load_cert(signerfile, FORMAT_PEM, - "signer certificate"); + signer = load_cert(signerfile, FORMAT_UNDEF, "signer certificate"); if (signer == NULL) goto end; - key = load_key(keyfile, keyform, 0, passin, e, "signing key file"); + key = load_key(keyfile, keyform, 0, passin, e, "signing key"); if (key == NULL) goto end; + if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags)) goto end; X509_free(signer); @@ -604,12 +663,15 @@ int smime_main(int argc, char **argv) X509_free(recip); X509_free(signer); EVP_PKEY_free(key); + EVP_MD_free(sign_md); + EVP_CIPHER_free(cipher); PKCS7_free(p7); release_engine(e); BIO_free(in); BIO_free(indata); BIO_free_all(out); OPENSSL_free(passin); + NCONF_free(conf); return ret; } diff --git a/apps/speed.c b/apps/speed.c index 89bf18480fa1..addf7e32137f 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -1,20 +1,27 @@ /* - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 */ #undef SECONDS -#define SECONDS 3 -#define RSA_SECONDS 10 -#define DSA_SECONDS 10 -#define ECDSA_SECONDS 10 -#define ECDH_SECONDS 10 -#define EdDSA_SECONDS 10 +#define SECONDS 3 +#define PKEY_SECONDS 10 + +#define RSA_SECONDS PKEY_SECONDS +#define DSA_SECONDS PKEY_SECONDS +#define ECDSA_SECONDS PKEY_SECONDS +#define ECDH_SECONDS PKEY_SECONDS +#define EdDSA_SECONDS PKEY_SECONDS +#define SM2_SECONDS PKEY_SECONDS +#define FFDH_SECONDS PKEY_SECONDS + +/* We need to use some deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED #include <stdio.h> #include <stdlib.h> @@ -22,14 +29,22 @@ #include <math.h> #include "apps.h" #include "progs.h" +#include "internal/numbers.h" #include <openssl/crypto.h> #include <openssl/rand.h> #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/objects.h> +#include <openssl/core_names.h> #include <openssl/async.h> #if !defined(OPENSSL_SYS_MSDOS) -# include OPENSSL_UNISTD +# include <unistd.h> +#endif + +#if defined(__TANDEM) +# if defined(OPENSSL_TANDEM_FLOSS) +# include <floss.h(floss_fork)> +# endif #endif #if defined(_WIN32) @@ -37,66 +52,14 @@ #endif #include <openssl/bn.h> -#ifndef OPENSSL_NO_DES -# include <openssl/des.h> -#endif -#include <openssl/aes.h> -#ifndef OPENSSL_NO_CAMELLIA -# include <openssl/camellia.h> -#endif -#ifndef OPENSSL_NO_MD2 -# include <openssl/md2.h> -#endif -#ifndef OPENSSL_NO_MDC2 -# include <openssl/mdc2.h> -#endif -#ifndef OPENSSL_NO_MD4 -# include <openssl/md4.h> -#endif -#ifndef OPENSSL_NO_MD5 -# include <openssl/md5.h> -#endif -#include <openssl/hmac.h> -#include <openssl/sha.h> -#ifndef OPENSSL_NO_RMD160 -# include <openssl/ripemd.h> -#endif -#ifndef OPENSSL_NO_WHIRLPOOL -# include <openssl/whrlpool.h> -#endif -#ifndef OPENSSL_NO_RC4 -# include <openssl/rc4.h> -#endif -#ifndef OPENSSL_NO_RC5 -# include <openssl/rc5.h> -#endif -#ifndef OPENSSL_NO_RC2 -# include <openssl/rc2.h> -#endif -#ifndef OPENSSL_NO_IDEA -# include <openssl/idea.h> -#endif -#ifndef OPENSSL_NO_SEED -# include <openssl/seed.h> -#endif -#ifndef OPENSSL_NO_BF -# include <openssl/blowfish.h> -#endif -#ifndef OPENSSL_NO_CAST -# include <openssl/cast.h> -#endif -#ifndef OPENSSL_NO_RSA -# include <openssl/rsa.h> -# include "./testrsa.h" +#include <openssl/rsa.h> +#include "./testrsa.h" +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> #endif #include <openssl/x509.h> -#ifndef OPENSSL_NO_DSA -# include <openssl/dsa.h> -# include "./testdsa.h" -#endif -#ifndef OPENSSL_NO_EC -# include <openssl/ec.h> -#endif +#include <openssl/dsa.h> +#include "./testdsa.h" #include <openssl/modes.h> #ifndef HAVE_FORK @@ -104,6 +67,7 @@ # define HAVE_FORK 0 # else # define HAVE_FORK 1 +# include <sys/wait.h> # endif #endif @@ -116,6 +80,11 @@ #define MAX_MISALIGNMENT 63 #define MAX_ECDH_SIZE 256 #define MISALIGN 64 +#define MAX_FFDH_SIZE 1024 + +#ifndef RSA_DEFAULT_PRIME_NUM +# define RSA_DEFAULT_PRIME_NUM 2 +#endif typedef struct openssl_speed_sec_st { int sym; @@ -124,70 +93,15 @@ typedef struct openssl_speed_sec_st { int ecdsa; int ecdh; int eddsa; + int sm2; + int ffdh; } openssl_speed_sec_t; static volatile int run = 0; -static int mr = 0; +static int mr = 0; /* machine-readeable output format to merge fork results */ static int usertime = 1; -#ifndef OPENSSL_NO_MD2 -static int EVP_Digest_MD2_loop(void *args); -#endif - -#ifndef OPENSSL_NO_MDC2 -static int EVP_Digest_MDC2_loop(void *args); -#endif -#ifndef OPENSSL_NO_MD4 -static int EVP_Digest_MD4_loop(void *args); -#endif -#ifndef OPENSSL_NO_MD5 -static int MD5_loop(void *args); -static int HMAC_loop(void *args); -#endif -static int SHA1_loop(void *args); -static int SHA256_loop(void *args); -static int SHA512_loop(void *args); -#ifndef OPENSSL_NO_WHIRLPOOL -static int WHIRLPOOL_loop(void *args); -#endif -#ifndef OPENSSL_NO_RMD160 -static int EVP_Digest_RMD160_loop(void *args); -#endif -#ifndef OPENSSL_NO_RC4 -static int RC4_loop(void *args); -#endif -#ifndef OPENSSL_NO_DES -static int DES_ncbc_encrypt_loop(void *args); -static int DES_ede3_cbc_encrypt_loop(void *args); -#endif -static int AES_cbc_128_encrypt_loop(void *args); -static int AES_cbc_192_encrypt_loop(void *args); -static int AES_ige_128_encrypt_loop(void *args); -static int AES_cbc_256_encrypt_loop(void *args); -static int AES_ige_192_encrypt_loop(void *args); -static int AES_ige_256_encrypt_loop(void *args); -static int CRYPTO_gcm128_aad_loop(void *args); -static int RAND_bytes_loop(void *args); -static int EVP_Update_loop(void *args); -static int EVP_Update_loop_ccm(void *args); -static int EVP_Update_loop_aead(void *args); -static int EVP_Digest_loop(void *args); -#ifndef OPENSSL_NO_RSA -static int RSA_sign_loop(void *args); -static int RSA_verify_loop(void *args); -#endif -#ifndef OPENSSL_NO_DSA -static int DSA_sign_loop(void *args); -static int DSA_verify_loop(void *args); -#endif -#ifndef OPENSSL_NO_EC -static int ECDSA_sign_loop(void *args); -static int ECDSA_verify_loop(void *args); -static int EdDSA_sign_loop(void *args); -static int EdDSA_verify_loop(void *args); -#endif - static double Time_F(int s); static void print_message(const char *s, long num, int length, int tm); static void pkey_print_message(const char *str, const char *str2, @@ -200,6 +114,7 @@ static int do_multi(int multi, int size_num); static const int lengths_list[] = { 16, 64, 256, 1024, 8 * 1024, 16 * 1024 }; +#define SIZE_NUM OSSL_NELEM(lengths_list) static const int *lengths = lengths_list; static const int aead_lengths_list[] = { @@ -272,17 +187,12 @@ static double Time_F(int s) return ret; } #else -static double Time_F(int s) -{ - return app_tminterval(s, usertime); -} +# error "SIGALRM not defined and the platform is not Windows" #endif static void multiblock_speed(const EVP_CIPHER *evp_cipher, int lengths_single, const openssl_speed_sec_t *seconds); -#define found(value, pairs, result)\ - opt_found(value, result, pairs, OSSL_NELEM(pairs)) static int opt_found(const char *name, unsigned int *result, const OPT_PAIR pairs[], unsigned int nbelem) { @@ -295,23 +205,21 @@ static int opt_found(const char *name, unsigned int *result, } return 0; } +#define opt_found(value, pairs, result)\ + opt_found(value, result, pairs, OSSL_NELEM(pairs)) typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_ELAPSED, OPT_EVP, OPT_DECRYPT, OPT_ENGINE, OPT_MULTI, - OPT_MR, OPT_MB, OPT_MISALIGN, OPT_ASYNCJOBS, OPT_R_ENUM, - OPT_PRIMES, OPT_SECONDS, OPT_BYTES, OPT_AEAD + OPT_COMMON, + OPT_ELAPSED, OPT_EVP, OPT_HMAC, OPT_DECRYPT, OPT_ENGINE, OPT_MULTI, + OPT_MR, OPT_MB, OPT_MISALIGN, OPT_ASYNCJOBS, OPT_R_ENUM, OPT_PROV_ENUM, + OPT_PRIMES, OPT_SECONDS, OPT_BYTES, OPT_AEAD, OPT_CMAC } OPTION_CHOICE; const OPTIONS speed_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [options] ciphers...\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [algorithm...]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"evp", OPT_EVP, 's', "Use EVP-named cipher or digest"}, - {"decrypt", OPT_DECRYPT, '-', - "Time decryption instead of encryption (only EVP)"}, - {"aead", OPT_AEAD, '-', - "Benchmark EVP-named AEAD cipher in TLS-like sequence"}, {"mb", OPT_MB, '-', "Enable (tls1>=1) multi-block mode on EVP-named cipher"}, {"mr", OPT_MR, '-', "Produce machine readable output"}, @@ -322,160 +230,114 @@ const OPTIONS speed_options[] = { {"async_jobs", OPT_ASYNCJOBS, 'p', "Enable async mode and start specified number of jobs"}, #endif - OPT_R_OPTIONS, #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif + {"primes", OPT_PRIMES, 'p', "Specify number of primes (for RSA only)"}, + + OPT_SECTION("Selection"), + {"evp", OPT_EVP, 's', "Use EVP-named cipher or digest"}, + {"hmac", OPT_HMAC, 's', "HMAC using EVP-named digest"}, + {"cmac", OPT_CMAC, 's', "CMAC using EVP-named cipher"}, + {"decrypt", OPT_DECRYPT, '-', + "Time decryption instead of encryption (only EVP)"}, + {"aead", OPT_AEAD, '-', + "Benchmark EVP-named AEAD cipher in TLS-like sequence"}, + + OPT_SECTION("Timing"), {"elapsed", OPT_ELAPSED, '-', "Use wall-clock time instead of CPU user time as divisor"}, - {"primes", OPT_PRIMES, 'p', "Specify number of primes (for RSA only)"}, {"seconds", OPT_SECONDS, 'p', "Run benchmarks for specified amount of seconds"}, {"bytes", OPT_BYTES, 'p', "Run [non-PKI] benchmarks on custom-sized buffer"}, {"misalign", OPT_MISALIGN, 'p', "Use specified offset to mis-align buffers"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"algorithm", 0, 0, "Algorithm(s) to test (optional; otherwise tests all)"}, {NULL} }; -#define D_MD2 0 -#define D_MDC2 1 -#define D_MD4 2 -#define D_MD5 3 -#define D_HMAC 4 -#define D_SHA1 5 -#define D_RMD160 6 -#define D_RC4 7 -#define D_CBC_DES 8 -#define D_EDE3_DES 9 -#define D_CBC_IDEA 10 -#define D_CBC_SEED 11 -#define D_CBC_RC2 12 -#define D_CBC_RC5 13 -#define D_CBC_BF 14 -#define D_CBC_CAST 15 -#define D_CBC_128_AES 16 -#define D_CBC_192_AES 17 -#define D_CBC_256_AES 18 -#define D_CBC_128_CML 19 -#define D_CBC_192_CML 20 -#define D_CBC_256_CML 21 -#define D_EVP 22 -#define D_SHA256 23 -#define D_SHA512 24 -#define D_WHIRLPOOL 25 -#define D_IGE_128_AES 26 -#define D_IGE_192_AES 27 -#define D_IGE_256_AES 28 -#define D_GHASH 29 -#define D_RAND 30 -/* name of algorithms to test */ -static const char *names[] = { - "md2", "mdc2", "md4", "md5", "hmac(md5)", "sha1", "rmd160", "rc4", - "des cbc", "des ede3", "idea cbc", "seed cbc", - "rc2 cbc", "rc5-32/12 cbc", "blowfish cbc", "cast cbc", - "aes-128 cbc", "aes-192 cbc", "aes-256 cbc", - "camellia-128 cbc", "camellia-192 cbc", "camellia-256 cbc", - "evp", "sha256", "sha512", "whirlpool", - "aes-128 ige", "aes-192 ige", "aes-256 ige", "ghash", - "rand" +enum { + D_MD2, D_MDC2, D_MD4, D_MD5, D_SHA1, D_RMD160, + D_SHA256, D_SHA512, D_WHIRLPOOL, D_HMAC, + D_CBC_DES, D_EDE3_DES, D_RC4, D_CBC_IDEA, D_CBC_SEED, + D_CBC_RC2, D_CBC_RC5, D_CBC_BF, D_CBC_CAST, + D_CBC_128_AES, D_CBC_192_AES, D_CBC_256_AES, + D_CBC_128_CML, D_CBC_192_CML, D_CBC_256_CML, + D_EVP, D_GHASH, D_RAND, D_EVP_CMAC, ALGOR_NUM +}; +/* name of algorithms to test. MUST BE KEEP IN SYNC with above enum ! */ +static const char *names[ALGOR_NUM] = { + "md2", "mdc2", "md4", "md5", "sha1", "rmd160", + "sha256", "sha512", "whirlpool", "hmac(md5)", + "des-cbc", "des-ede3", "rc4", "idea-cbc", "seed-cbc", + "rc2-cbc", "rc5-cbc", "blowfish", "cast-cbc", + "aes-128-cbc", "aes-192-cbc", "aes-256-cbc", + "camellia-128-cbc", "camellia-192-cbc", "camellia-256-cbc", + "evp", "ghash", "rand", "cmac" }; -#define ALGOR_NUM OSSL_NELEM(names) -/* list of configured algorithm (remaining) */ +/* list of configured algorithm (remaining), with some few alias */ static const OPT_PAIR doit_choices[] = { -#ifndef OPENSSL_NO_MD2 {"md2", D_MD2}, -#endif -#ifndef OPENSSL_NO_MDC2 {"mdc2", D_MDC2}, -#endif -#ifndef OPENSSL_NO_MD4 {"md4", D_MD4}, -#endif -#ifndef OPENSSL_NO_MD5 {"md5", D_MD5}, {"hmac", D_HMAC}, -#endif {"sha1", D_SHA1}, {"sha256", D_SHA256}, {"sha512", D_SHA512}, -#ifndef OPENSSL_NO_WHIRLPOOL {"whirlpool", D_WHIRLPOOL}, -#endif -#ifndef OPENSSL_NO_RMD160 {"ripemd", D_RMD160}, {"rmd160", D_RMD160}, {"ripemd160", D_RMD160}, -#endif -#ifndef OPENSSL_NO_RC4 {"rc4", D_RC4}, -#endif -#ifndef OPENSSL_NO_DES {"des-cbc", D_CBC_DES}, {"des-ede3", D_EDE3_DES}, -#endif {"aes-128-cbc", D_CBC_128_AES}, {"aes-192-cbc", D_CBC_192_AES}, {"aes-256-cbc", D_CBC_256_AES}, - {"aes-128-ige", D_IGE_128_AES}, - {"aes-192-ige", D_IGE_192_AES}, - {"aes-256-ige", D_IGE_256_AES}, -#ifndef OPENSSL_NO_RC2 + {"camellia-128-cbc", D_CBC_128_CML}, + {"camellia-192-cbc", D_CBC_192_CML}, + {"camellia-256-cbc", D_CBC_256_CML}, {"rc2-cbc", D_CBC_RC2}, {"rc2", D_CBC_RC2}, -#endif -#ifndef OPENSSL_NO_RC5 {"rc5-cbc", D_CBC_RC5}, {"rc5", D_CBC_RC5}, -#endif -#ifndef OPENSSL_NO_IDEA {"idea-cbc", D_CBC_IDEA}, {"idea", D_CBC_IDEA}, -#endif -#ifndef OPENSSL_NO_SEED {"seed-cbc", D_CBC_SEED}, {"seed", D_CBC_SEED}, -#endif -#ifndef OPENSSL_NO_BF {"bf-cbc", D_CBC_BF}, {"blowfish", D_CBC_BF}, {"bf", D_CBC_BF}, -#endif -#ifndef OPENSSL_NO_CAST {"cast-cbc", D_CBC_CAST}, {"cast", D_CBC_CAST}, {"cast5", D_CBC_CAST}, -#endif {"ghash", D_GHASH}, {"rand", D_RAND} }; -static double results[ALGOR_NUM][OSSL_NELEM(lengths_list)]; +static double results[ALGOR_NUM][SIZE_NUM]; -#ifndef OPENSSL_NO_DSA -# define R_DSA_512 0 -# define R_DSA_1024 1 -# define R_DSA_2048 2 -static const OPT_PAIR dsa_choices[] = { +enum { R_DSA_512, R_DSA_1024, R_DSA_2048, DSA_NUM }; +static const OPT_PAIR dsa_choices[DSA_NUM] = { {"dsa512", R_DSA_512}, {"dsa1024", R_DSA_1024}, {"dsa2048", R_DSA_2048} }; -# define DSA_NUM OSSL_NELEM(dsa_choices) - static double dsa_results[DSA_NUM][2]; /* 2 ops: sign then verify */ -#endif /* OPENSSL_NO_DSA */ - -#define R_RSA_512 0 -#define R_RSA_1024 1 -#define R_RSA_2048 2 -#define R_RSA_3072 3 -#define R_RSA_4096 4 -#define R_RSA_7680 5 -#define R_RSA_15360 6 -#ifndef OPENSSL_NO_RSA -static const OPT_PAIR rsa_choices[] = { + +enum { + R_RSA_512, R_RSA_1024, R_RSA_2048, R_RSA_3072, R_RSA_4096, R_RSA_7680, + R_RSA_15360, RSA_NUM +}; +static const OPT_PAIR rsa_choices[RSA_NUM] = { {"rsa512", R_RSA_512}, {"rsa1024", R_RSA_1024}, {"rsa2048", R_RSA_2048}, @@ -484,49 +346,43 @@ static const OPT_PAIR rsa_choices[] = { {"rsa7680", R_RSA_7680}, {"rsa15360", R_RSA_15360} }; -# define RSA_NUM OSSL_NELEM(rsa_choices) static double rsa_results[RSA_NUM][2]; /* 2 ops: sign then verify */ -#endif /* OPENSSL_NO_RSA */ -enum { - R_EC_P160, - R_EC_P192, - R_EC_P224, - R_EC_P256, - R_EC_P384, - R_EC_P521, +#ifndef OPENSSL_NO_DH +enum ff_params_t { + R_FFDH_2048, R_FFDH_3072, R_FFDH_4096, R_FFDH_6144, R_FFDH_8192, FFDH_NUM +}; + +static const OPT_PAIR ffdh_choices[FFDH_NUM] = { + {"ffdh2048", R_FFDH_2048}, + {"ffdh3072", R_FFDH_3072}, + {"ffdh4096", R_FFDH_4096}, + {"ffdh6144", R_FFDH_6144}, + {"ffdh8192", R_FFDH_8192}, +}; + +static double ffdh_results[FFDH_NUM][1]; /* 1 op: derivation */ +#endif /* OPENSSL_NO_DH */ + +enum ec_curves_t { + R_EC_P160, R_EC_P192, R_EC_P224, R_EC_P256, R_EC_P384, R_EC_P521, #ifndef OPENSSL_NO_EC2M - R_EC_K163, - R_EC_K233, - R_EC_K283, - R_EC_K409, - R_EC_K571, - R_EC_B163, - R_EC_B233, - R_EC_B283, - R_EC_B409, - R_EC_B571, + R_EC_K163, R_EC_K233, R_EC_K283, R_EC_K409, R_EC_K571, + R_EC_B163, R_EC_B233, R_EC_B283, R_EC_B409, R_EC_B571, #endif - R_EC_BRP256R1, - R_EC_BRP256T1, - R_EC_BRP384R1, - R_EC_BRP384T1, - R_EC_BRP512R1, - R_EC_BRP512T1, - R_EC_X25519, - R_EC_X448 + R_EC_BRP256R1, R_EC_BRP256T1, R_EC_BRP384R1, R_EC_BRP384T1, + R_EC_BRP512R1, R_EC_BRP512T1, ECDSA_NUM }; - -#ifndef OPENSSL_NO_EC -static OPT_PAIR ecdsa_choices[] = { +/* list of ecdsa curves */ +static const OPT_PAIR ecdsa_choices[ECDSA_NUM] = { {"ecdsap160", R_EC_P160}, {"ecdsap192", R_EC_P192}, {"ecdsap224", R_EC_P224}, {"ecdsap256", R_EC_P256}, {"ecdsap384", R_EC_P384}, {"ecdsap521", R_EC_P521}, -# ifndef OPENSSL_NO_EC2M +#ifndef OPENSSL_NO_EC2M {"ecdsak163", R_EC_K163}, {"ecdsak233", R_EC_K233}, {"ecdsak283", R_EC_K283}, @@ -537,7 +393,7 @@ static OPT_PAIR ecdsa_choices[] = { {"ecdsab283", R_EC_B283}, {"ecdsab409", R_EC_B409}, {"ecdsab571", R_EC_B571}, -# endif +#endif {"ecdsabrp256r1", R_EC_BRP256R1}, {"ecdsabrp256t1", R_EC_BRP256T1}, {"ecdsabrp384r1", R_EC_BRP384R1}, @@ -545,18 +401,16 @@ static OPT_PAIR ecdsa_choices[] = { {"ecdsabrp512r1", R_EC_BRP512R1}, {"ecdsabrp512t1", R_EC_BRP512T1} }; -# define ECDSA_NUM OSSL_NELEM(ecdsa_choices) - -static double ecdsa_results[ECDSA_NUM][2]; /* 2 ops: sign then verify */ - -static const OPT_PAIR ecdh_choices[] = { +enum { R_EC_X25519 = ECDSA_NUM, R_EC_X448, EC_NUM }; +/* list of ecdh curves, extension of |ecdsa_choices| list above */ +static const OPT_PAIR ecdh_choices[EC_NUM] = { {"ecdhp160", R_EC_P160}, {"ecdhp192", R_EC_P192}, {"ecdhp224", R_EC_P224}, {"ecdhp256", R_EC_P256}, {"ecdhp384", R_EC_P384}, {"ecdhp521", R_EC_P521}, -# ifndef OPENSSL_NO_EC2M +#ifndef OPENSSL_NO_EC2M {"ecdhk163", R_EC_K163}, {"ecdhk233", R_EC_K233}, {"ecdhk283", R_EC_K283}, @@ -567,7 +421,7 @@ static const OPT_PAIR ecdh_choices[] = { {"ecdhb283", R_EC_B283}, {"ecdhb409", R_EC_B409}, {"ecdhb571", R_EC_B571}, -# endif +#endif {"ecdhbrp256r1", R_EC_BRP256R1}, {"ecdhbrp256t1", R_EC_BRP256T1}, {"ecdhbrp384r1", R_EC_BRP384R1}, @@ -577,28 +431,30 @@ static const OPT_PAIR ecdh_choices[] = { {"ecdhx25519", R_EC_X25519}, {"ecdhx448", R_EC_X448} }; -# define EC_NUM OSSL_NELEM(ecdh_choices) -static double ecdh_results[EC_NUM][1]; /* 1 op: derivation */ +static double ecdh_results[EC_NUM][1]; /* 1 op: derivation */ +static double ecdsa_results[ECDSA_NUM][2]; /* 2 ops: sign then verify */ -#define R_EC_Ed25519 0 -#define R_EC_Ed448 1 -static OPT_PAIR eddsa_choices[] = { +enum { R_EC_Ed25519, R_EC_Ed448, EdDSA_NUM }; +static const OPT_PAIR eddsa_choices[EdDSA_NUM] = { {"ed25519", R_EC_Ed25519}, {"ed448", R_EC_Ed448} -}; -# define EdDSA_NUM OSSL_NELEM(eddsa_choices) +}; static double eddsa_results[EdDSA_NUM][2]; /* 2 ops: sign then verify */ -#endif /* OPENSSL_NO_EC */ -#ifndef SIGALRM -# define COND(d) (count < (d)) -# define COUNT(d) (d) -#else -# define COND(unused_cond) (run && count<0x7fffffff) -# define COUNT(d) (count) -#endif /* SIGALRM */ +#ifndef OPENSSL_NO_SM2 +enum { R_EC_CURVESM2, SM2_NUM }; +static const OPT_PAIR sm2_choices[SM2_NUM] = { + {"curveSM2", R_EC_CURVESM2} +}; +# define SM2_ID "TLSv1.3+GM+Cipher+Suite" +# define SM2_ID_LEN sizeof("TLSv1.3+GM+Cipher+Suite") - 1 +static double sm2_results[SM2_NUM][2]; /* 2 ops: sign then verify */ +#endif /* OPENSSL_NO_SM2 */ + +#define COND(unused_cond) (run && count < INT_MAX) +#define COUNT(d) (count) typedef struct loopargs_st { ASYNC_JOB *inprogress_job; @@ -608,25 +464,32 @@ typedef struct loopargs_st { unsigned char *buf_malloc; unsigned char *buf2_malloc; unsigned char *key; - unsigned int siglen; + size_t buflen; size_t sigsize; -#ifndef OPENSSL_NO_RSA - RSA *rsa_key[RSA_NUM]; -#endif -#ifndef OPENSSL_NO_DSA - DSA *dsa_key[DSA_NUM]; -#endif -#ifndef OPENSSL_NO_EC - EC_KEY *ecdsa[ECDSA_NUM]; + EVP_PKEY_CTX *rsa_sign_ctx[RSA_NUM]; + EVP_PKEY_CTX *rsa_verify_ctx[RSA_NUM]; + EVP_PKEY_CTX *dsa_sign_ctx[DSA_NUM]; + EVP_PKEY_CTX *dsa_verify_ctx[DSA_NUM]; + EVP_PKEY_CTX *ecdsa_sign_ctx[ECDSA_NUM]; + EVP_PKEY_CTX *ecdsa_verify_ctx[ECDSA_NUM]; EVP_PKEY_CTX *ecdh_ctx[EC_NUM]; EVP_MD_CTX *eddsa_ctx[EdDSA_NUM]; + EVP_MD_CTX *eddsa_ctx2[EdDSA_NUM]; +#ifndef OPENSSL_NO_SM2 + EVP_MD_CTX *sm2_ctx[SM2_NUM]; + EVP_MD_CTX *sm2_vfy_ctx[SM2_NUM]; + EVP_PKEY *sm2_pkey[SM2_NUM]; +#endif unsigned char *secret_a; unsigned char *secret_b; size_t outlen[EC_NUM]; +#ifndef OPENSSL_NO_DH + EVP_PKEY_CTX *ffdh_ctx[FFDH_NUM]; + unsigned char *secret_ff_a; + unsigned char *secret_ff_b; #endif EVP_CIPHER_CTX *ctx; - HMAC_CTX *hctx; - GCM128_CONTEXT *gcm_ctx; + EVP_MAC_CTX *mctx; } loopargs_t; static int run_benchmark(int async_jobs, int (*loop_function) (void *), loopargs_t * loopargs); @@ -634,273 +497,216 @@ static int run_benchmark(int async_jobs, int (*loop_function) (void *), static unsigned int testnum; /* Nb of iterations to do per algorithm and key-size */ -static long c[ALGOR_NUM][OSSL_NELEM(lengths_list)]; +static long c[ALGOR_NUM][SIZE_NUM]; -#ifndef OPENSSL_NO_MD2 -static int EVP_Digest_MD2_loop(void *args) +static char *evp_mac_mdname = "md5"; +static char *evp_hmac_name = NULL; +static const char *evp_md_name = NULL; +static char *evp_mac_ciphername = "aes-128-cbc"; +static char *evp_cmac_name = NULL; + +static int have_md(const char *name) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char md2[MD2_DIGEST_LENGTH]; - int count; + int ret = 0; + EVP_MD *md = NULL; - for (count = 0; COND(c[D_MD2][testnum]); count++) { - if (!EVP_Digest(buf, (size_t)lengths[testnum], md2, NULL, EVP_md2(), - NULL)) - return -1; + if (opt_md_silent(name, &md)) { + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + + if (ctx != NULL && EVP_DigestInit(ctx, md) > 0) + ret = 1; + EVP_MD_CTX_free(ctx); + EVP_MD_free(md); } - return count; + return ret; } -#endif -#ifndef OPENSSL_NO_MDC2 -static int EVP_Digest_MDC2_loop(void *args) +static int have_cipher(const char *name) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char mdc2[MDC2_DIGEST_LENGTH]; - int count; + int ret = 0; + EVP_CIPHER *cipher = NULL; - for (count = 0; COND(c[D_MDC2][testnum]); count++) { - if (!EVP_Digest(buf, (size_t)lengths[testnum], mdc2, NULL, EVP_mdc2(), - NULL)) - return -1; + if (opt_cipher_silent(name, &cipher)) { + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + if (ctx != NULL + && EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 1) > 0) + ret = 1; + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); } - return count; + return ret; } -#endif -#ifndef OPENSSL_NO_MD4 -static int EVP_Digest_MD4_loop(void *args) +static int EVP_Digest_loop(const char *mdname, int algindex, void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - unsigned char md4[MD4_DIGEST_LENGTH]; + unsigned char digest[EVP_MAX_MD_SIZE]; int count; + EVP_MD *md = NULL; - for (count = 0; COND(c[D_MD4][testnum]); count++) { - if (!EVP_Digest(buf, (size_t)lengths[testnum], md4, NULL, EVP_md4(), - NULL)) - return -1; + if (!opt_md_silent(mdname, &md)) + return -1; + for (count = 0; COND(c[algindex][testnum]); count++) { + if (!EVP_Digest(buf, (size_t)lengths[testnum], digest, NULL, md, + NULL)) { + count = -1; + break; + } } + EVP_MD_free(md); return count; } -#endif -#ifndef OPENSSL_NO_MD5 -static int MD5_loop(void *args) +static int EVP_Digest_md_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char md5[MD5_DIGEST_LENGTH]; - int count; - for (count = 0; COND(c[D_MD5][testnum]); count++) - MD5(buf, lengths[testnum], md5); - return count; + return EVP_Digest_loop(evp_md_name, D_EVP, args); } -static int HMAC_loop(void *args) +static int EVP_Digest_MD2_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - HMAC_CTX *hctx = tempargs->hctx; - unsigned char hmac[MD5_DIGEST_LENGTH]; - int count; - - for (count = 0; COND(c[D_HMAC][testnum]); count++) { - HMAC_Init_ex(hctx, NULL, 0, NULL, NULL); - HMAC_Update(hctx, buf, lengths[testnum]); - HMAC_Final(hctx, hmac, NULL); - } - return count; + return EVP_Digest_loop("md2", D_MD2, args); } -#endif -static int SHA1_loop(void *args) +static int EVP_Digest_MDC2_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char sha[SHA_DIGEST_LENGTH]; - int count; - for (count = 0; COND(c[D_SHA1][testnum]); count++) - SHA1(buf, lengths[testnum], sha); - return count; + return EVP_Digest_loop("mdc2", D_MDC2, args); } -static int SHA256_loop(void *args) +static int EVP_Digest_MD4_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char sha256[SHA256_DIGEST_LENGTH]; - int count; - for (count = 0; COND(c[D_SHA256][testnum]); count++) - SHA256(buf, lengths[testnum], sha256); - return count; + return EVP_Digest_loop("md4", D_MD4, args); } -static int SHA512_loop(void *args) +static int MD5_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char sha512[SHA512_DIGEST_LENGTH]; - int count; - for (count = 0; COND(c[D_SHA512][testnum]); count++) - SHA512(buf, lengths[testnum], sha512); - return count; + return EVP_Digest_loop("md5", D_MD5, args); } -#ifndef OPENSSL_NO_WHIRLPOOL -static int WHIRLPOOL_loop(void *args) +static int EVP_MAC_loop(int algindex, void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - unsigned char whirlpool[WHIRLPOOL_DIGEST_LENGTH]; + EVP_MAC_CTX *mctx = tempargs->mctx; + unsigned char mac[EVP_MAX_MD_SIZE]; int count; - for (count = 0; COND(c[D_WHIRLPOOL][testnum]); count++) - WHIRLPOOL(buf, lengths[testnum], whirlpool); - return count; -} -#endif -#ifndef OPENSSL_NO_RMD160 -static int EVP_Digest_RMD160_loop(void *args) -{ - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char rmd160[RIPEMD160_DIGEST_LENGTH]; - int count; - for (count = 0; COND(c[D_RMD160][testnum]); count++) { - if (!EVP_Digest(buf, (size_t)lengths[testnum], &(rmd160[0]), - NULL, EVP_ripemd160(), NULL)) + for (count = 0; COND(c[algindex][testnum]); count++) { + size_t outl; + + if (!EVP_MAC_init(mctx, NULL, 0, NULL) + || !EVP_MAC_update(mctx, buf, lengths[testnum]) + || !EVP_MAC_final(mctx, mac, &outl, sizeof(mac))) return -1; } return count; } -#endif -#ifndef OPENSSL_NO_RC4 -static RC4_KEY rc4_ks; -static int RC4_loop(void *args) +static int HMAC_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - int count; - for (count = 0; COND(c[D_RC4][testnum]); count++) - RC4(&rc4_ks, (size_t)lengths[testnum], buf, buf); - return count; + return EVP_MAC_loop(D_HMAC, args); } -#endif -#ifndef OPENSSL_NO_DES -static unsigned char DES_iv[8]; -static DES_key_schedule sch; -static DES_key_schedule sch2; -static DES_key_schedule sch3; -static int DES_ncbc_encrypt_loop(void *args) +static int CMAC_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - int count; - for (count = 0; COND(c[D_CBC_DES][testnum]); count++) - DES_ncbc_encrypt(buf, buf, lengths[testnum], &sch, - &DES_iv, DES_ENCRYPT); - return count; + return EVP_MAC_loop(D_EVP_CMAC, args); } -static int DES_ede3_cbc_encrypt_loop(void *args) +static int SHA1_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - int count; - for (count = 0; COND(c[D_EDE3_DES][testnum]); count++) - DES_ede3_cbc_encrypt(buf, buf, lengths[testnum], - &sch, &sch2, &sch3, &DES_iv, DES_ENCRYPT); - return count; + return EVP_Digest_loop("sha1", D_SHA1, args); } -#endif - -#define MAX_BLOCK_SIZE 128 -static unsigned char iv[2 * MAX_BLOCK_SIZE / 8]; -static AES_KEY aes_ks1, aes_ks2, aes_ks3; -static int AES_cbc_128_encrypt_loop(void *args) +static int SHA256_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - int count; - for (count = 0; COND(c[D_CBC_128_AES][testnum]); count++) - AES_cbc_encrypt(buf, buf, - (size_t)lengths[testnum], &aes_ks1, iv, AES_ENCRYPT); - return count; + return EVP_Digest_loop("sha256", D_SHA256, args); } -static int AES_cbc_192_encrypt_loop(void *args) +static int SHA512_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - int count; - for (count = 0; COND(c[D_CBC_192_AES][testnum]); count++) - AES_cbc_encrypt(buf, buf, - (size_t)lengths[testnum], &aes_ks2, iv, AES_ENCRYPT); - return count; + return EVP_Digest_loop("sha512", D_SHA512, args); } -static int AES_cbc_256_encrypt_loop(void *args) +static int WHIRLPOOL_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - int count; - for (count = 0; COND(c[D_CBC_256_AES][testnum]); count++) - AES_cbc_encrypt(buf, buf, - (size_t)lengths[testnum], &aes_ks3, iv, AES_ENCRYPT); - return count; + return EVP_Digest_loop("whirlpool", D_WHIRLPOOL, args); } -static int AES_ige_128_encrypt_loop(void *args) +static int EVP_Digest_RMD160_loop(void *args) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char *buf2 = tempargs->buf2; - int count; - for (count = 0; COND(c[D_IGE_128_AES][testnum]); count++) - AES_ige_encrypt(buf, buf2, - (size_t)lengths[testnum], &aes_ks1, iv, AES_ENCRYPT); - return count; + return EVP_Digest_loop("ripemd160", D_RMD160, args); } -static int AES_ige_192_encrypt_loop(void *args) +static int algindex; + +static int EVP_Cipher_loop(void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - unsigned char *buf2 = tempargs->buf2; int count; - for (count = 0; COND(c[D_IGE_192_AES][testnum]); count++) - AES_ige_encrypt(buf, buf2, - (size_t)lengths[testnum], &aes_ks2, iv, AES_ENCRYPT); + + if (tempargs->ctx == NULL) + return -1; + for (count = 0; COND(c[algindex][testnum]); count++) + if (EVP_Cipher(tempargs->ctx, buf, buf, (size_t)lengths[testnum]) <= 0) + return -1; return count; } -static int AES_ige_256_encrypt_loop(void *args) +static int GHASH_loop(void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - unsigned char *buf2 = tempargs->buf2; + EVP_MAC_CTX *mctx = tempargs->mctx; int count; - for (count = 0; COND(c[D_IGE_256_AES][testnum]); count++) - AES_ige_encrypt(buf, buf2, - (size_t)lengths[testnum], &aes_ks3, iv, AES_ENCRYPT); + + /* just do the update in the loop to be comparable with 1.1.1 */ + for (count = 0; COND(c[D_GHASH][testnum]); count++) { + if (!EVP_MAC_update(mctx, buf, lengths[testnum])) + return -1; + } return count; } -static int CRYPTO_gcm128_aad_loop(void *args) +#define MAX_BLOCK_SIZE 128 + +static unsigned char iv[2 * MAX_BLOCK_SIZE / 8]; + +static EVP_CIPHER_CTX *init_evp_cipher_ctx(const char *ciphername, + const unsigned char *key, + int keylen) { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - GCM128_CONTEXT *gcm_ctx = tempargs->gcm_ctx; - int count; - for (count = 0; COND(c[D_GHASH][testnum]); count++) - CRYPTO_gcm128_aad(gcm_ctx, buf, lengths[testnum]); - return count; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; + + if (!opt_cipher_silent(ciphername, &cipher)) + return NULL; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + goto end; + + if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 1)) { + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + goto end; + } + + if (EVP_CIPHER_CTX_set_key_length(ctx, keylen) <= 0) { + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + goto end; + } + + if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1)) { + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + goto end; + } + +end: + EVP_CIPHER_free(cipher); + return ctx; } static int RAND_bytes_loop(void *args) @@ -914,7 +720,6 @@ static int RAND_bytes_loop(void *args) return count; } -static long save_count = 0; static int decrypt = 0; static int EVP_Update_loop(void *args) { @@ -922,11 +727,9 @@ static int EVP_Update_loop(void *args) unsigned char *buf = tempargs->buf; EVP_CIPHER_CTX *ctx = tempargs->ctx; int outl, count, rc; -#ifndef SIGALRM - int nb_iter = save_count * 4 * lengths[0] / lengths[testnum]; -#endif + if (decrypt) { - for (count = 0; COND(nb_iter); count++) { + for (count = 0; COND(c[D_EVP][testnum]); count++) { rc = EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); if (rc != 1) { /* reset iv in case of counter overflow */ @@ -934,7 +737,7 @@ static int EVP_Update_loop(void *args) } } } else { - for (count = 0; COND(nb_iter); count++) { + for (count = 0; COND(c[D_EVP][testnum]); count++) { rc = EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); if (rc != 1) { /* reset iv in case of counter overflow */ @@ -961,29 +764,28 @@ static int EVP_Update_loop_ccm(void *args) EVP_CIPHER_CTX *ctx = tempargs->ctx; int outl, count; unsigned char tag[12]; -#ifndef SIGALRM - int nb_iter = save_count * 4 * lengths[0] / lengths[testnum]; -#endif + if (decrypt) { - for (count = 0; COND(nb_iter); count++) { - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(tag), tag); + for (count = 0; COND(c[D_EVP][testnum]); count++) { + (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(tag), + tag); /* reset iv */ - EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); + (void)EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); /* counter is reset on every update */ - EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + (void)EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); } } else { - for (count = 0; COND(nb_iter); count++) { + for (count = 0; COND(c[D_EVP][testnum]); count++) { /* restore iv length field */ - EVP_EncryptUpdate(ctx, NULL, &outl, NULL, lengths[testnum]); + (void)EVP_EncryptUpdate(ctx, NULL, &outl, NULL, lengths[testnum]); /* counter is reset on every update */ - EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + (void)EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); } } if (decrypt) - EVP_DecryptFinal_ex(ctx, buf, &outl); + (void)EVP_DecryptFinal_ex(ctx, buf, &outl); else - EVP_EncryptFinal_ex(ctx, buf, &outl); + (void)EVP_EncryptFinal_ex(ctx, buf, &outl); return count; } @@ -1000,48 +802,27 @@ static int EVP_Update_loop_aead(void *args) int outl, count; unsigned char aad[13] = { 0xcc }; unsigned char faketag[16] = { 0xcc }; -#ifndef SIGALRM - int nb_iter = save_count * 4 * lengths[0] / lengths[testnum]; -#endif + if (decrypt) { - for (count = 0; COND(nb_iter); count++) { - EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, - sizeof(faketag), faketag); - EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); - EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); - EVP_DecryptFinal_ex(ctx, buf + outl, &outl); + for (count = 0; COND(c[D_EVP][testnum]); count++) { + (void)EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); + (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + sizeof(faketag), faketag); + (void)EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); + (void)EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + (void)EVP_DecryptFinal_ex(ctx, buf + outl, &outl); } } else { - for (count = 0; COND(nb_iter); count++) { - EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv); - EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); - EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); - EVP_EncryptFinal_ex(ctx, buf + outl, &outl); + for (count = 0; COND(c[D_EVP][testnum]); count++) { + (void)EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv); + (void)EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); + (void)EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + (void)EVP_EncryptFinal_ex(ctx, buf + outl, &outl); } } return count; } -static const EVP_MD *evp_md = NULL; -static int EVP_Digest_loop(void *args) -{ - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; - unsigned char md[EVP_MAX_MD_SIZE]; - int count; -#ifndef SIGALRM - int nb_iter = save_count * 4 * lengths[0] / lengths[testnum]; -#endif - - for (count = 0; COND(nb_iter); count++) { - if (!EVP_Digest(buf, lengths[testnum], md, NULL, evp_md, NULL)) - return -1; - } - return count; -} - -#ifndef OPENSSL_NO_RSA static long rsa_c[RSA_NUM][2]; /* # RSA iteration test */ static int RSA_sign_loop(void *args) @@ -1049,12 +830,14 @@ static int RSA_sign_loop(void *args) loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; unsigned char *buf2 = tempargs->buf2; - unsigned int *rsa_num = &tempargs->siglen; - RSA **rsa_key = tempargs->rsa_key; + size_t *rsa_num = &tempargs->sigsize; + EVP_PKEY_CTX **rsa_sign_ctx = tempargs->rsa_sign_ctx; int ret, count; + for (count = 0; COND(rsa_c[testnum][0]); count++) { - ret = RSA_sign(NID_md5_sha1, buf, 36, buf2, rsa_num, rsa_key[testnum]); - if (ret == 0) { + *rsa_num = tempargs->buflen; + ret = EVP_PKEY_sign(rsa_sign_ctx[testnum], buf2, rsa_num, buf, 36); + if (ret <= 0) { BIO_printf(bio_err, "RSA sign failure\n"); ERR_print_errors(bio_err); count = -1; @@ -1069,12 +852,12 @@ static int RSA_verify_loop(void *args) loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; unsigned char *buf2 = tempargs->buf2; - unsigned int rsa_num = tempargs->siglen; - RSA **rsa_key = tempargs->rsa_key; + size_t rsa_num = tempargs->sigsize; + EVP_PKEY_CTX **rsa_verify_ctx = tempargs->rsa_verify_ctx; int ret, count; + for (count = 0; COND(rsa_c[testnum][1]); count++) { - ret = - RSA_verify(NID_md5_sha1, buf, 36, buf2, rsa_num, rsa_key[testnum]); + ret = EVP_PKEY_verify(rsa_verify_ctx[testnum], buf2, rsa_num, buf, 36); if (ret <= 0) { BIO_printf(bio_err, "RSA verify failure\n"); ERR_print_errors(bio_err); @@ -1084,21 +867,41 @@ static int RSA_verify_loop(void *args) } return count; } -#endif -#ifndef OPENSSL_NO_DSA +#ifndef OPENSSL_NO_DH +static long ffdh_c[FFDH_NUM][1]; + +static int FFDH_derive_key_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ffdh_ctx = tempargs->ffdh_ctx[testnum]; + unsigned char *derived_secret = tempargs->secret_ff_a; + int count; + + for (count = 0; COND(ffdh_c[testnum][0]); count++) { + /* outlen can be overwritten with a too small value (no padding used) */ + size_t outlen = MAX_FFDH_SIZE; + + EVP_PKEY_derive(ffdh_ctx, derived_secret, &outlen); + } + return count; +} +#endif /* OPENSSL_NO_DH */ + static long dsa_c[DSA_NUM][2]; static int DSA_sign_loop(void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; unsigned char *buf2 = tempargs->buf2; - DSA **dsa_key = tempargs->dsa_key; - unsigned int *siglen = &tempargs->siglen; + size_t *dsa_num = &tempargs->sigsize; + EVP_PKEY_CTX **dsa_sign_ctx = tempargs->dsa_sign_ctx; int ret, count; + for (count = 0; COND(dsa_c[testnum][0]); count++) { - ret = DSA_sign(0, buf, 20, buf2, siglen, dsa_key[testnum]); - if (ret == 0) { + *dsa_num = tempargs->buflen; + ret = EVP_PKEY_sign(dsa_sign_ctx[testnum], buf2, dsa_num, buf, 20); + if (ret <= 0) { BIO_printf(bio_err, "DSA sign failure\n"); ERR_print_errors(bio_err); count = -1; @@ -1113,11 +916,12 @@ static int DSA_verify_loop(void *args) loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; unsigned char *buf2 = tempargs->buf2; - DSA **dsa_key = tempargs->dsa_key; - unsigned int siglen = tempargs->siglen; + size_t dsa_num = tempargs->sigsize; + EVP_PKEY_CTX **dsa_verify_ctx = tempargs->dsa_verify_ctx; int ret, count; + for (count = 0; COND(dsa_c[testnum][1]); count++) { - ret = DSA_verify(0, buf, 20, buf2, siglen, dsa_key[testnum]); + ret = EVP_PKEY_verify(dsa_verify_ctx[testnum], buf2, dsa_num, buf, 20); if (ret <= 0) { BIO_printf(bio_err, "DSA verify failure\n"); ERR_print_errors(bio_err); @@ -1127,21 +931,21 @@ static int DSA_verify_loop(void *args) } return count; } -#endif -#ifndef OPENSSL_NO_EC static long ecdsa_c[ECDSA_NUM][2]; static int ECDSA_sign_loop(void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - EC_KEY **ecdsa = tempargs->ecdsa; - unsigned char *ecdsasig = tempargs->buf2; - unsigned int *ecdsasiglen = &tempargs->siglen; + unsigned char *buf2 = tempargs->buf2; + size_t *ecdsa_num = &tempargs->sigsize; + EVP_PKEY_CTX **ecdsa_sign_ctx = tempargs->ecdsa_sign_ctx; int ret, count; + for (count = 0; COND(ecdsa_c[testnum][0]); count++) { - ret = ECDSA_sign(0, buf, 20, ecdsasig, ecdsasiglen, ecdsa[testnum]); - if (ret == 0) { + *ecdsa_num = tempargs->buflen; + ret = EVP_PKEY_sign(ecdsa_sign_ctx[testnum], buf2, ecdsa_num, buf, 20); + if (ret <= 0) { BIO_printf(bio_err, "ECDSA sign failure\n"); ERR_print_errors(bio_err); count = -1; @@ -1155,13 +959,15 @@ static int ECDSA_verify_loop(void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - EC_KEY **ecdsa = tempargs->ecdsa; - unsigned char *ecdsasig = tempargs->buf2; - unsigned int ecdsasiglen = tempargs->siglen; + unsigned char *buf2 = tempargs->buf2; + size_t ecdsa_num = tempargs->sigsize; + EVP_PKEY_CTX **ecdsa_verify_ctx = tempargs->ecdsa_verify_ctx; int ret, count; + for (count = 0; COND(ecdsa_c[testnum][1]); count++) { - ret = ECDSA_verify(0, buf, 20, ecdsasig, ecdsasiglen, ecdsa[testnum]); - if (ret != 1) { + ret = EVP_PKEY_verify(ecdsa_verify_ctx[testnum], buf2, ecdsa_num, + buf, 20); + if (ret <= 0) { BIO_printf(bio_err, "ECDSA verify failure\n"); ERR_print_errors(bio_err); count = -1; @@ -1214,7 +1020,7 @@ static int EdDSA_verify_loop(void *args) { loopargs_t *tempargs = *(loopargs_t **) args; unsigned char *buf = tempargs->buf; - EVP_MD_CTX **edctx = tempargs->eddsa_ctx; + EVP_MD_CTX **edctx = tempargs->eddsa_ctx2; unsigned char *eddsasig = tempargs->buf2; size_t eddsasigsize = tempargs->sigsize; int ret, count; @@ -1230,7 +1036,75 @@ static int EdDSA_verify_loop(void *args) } return count; } -#endif /* OPENSSL_NO_EC */ + +#ifndef OPENSSL_NO_SM2 +static long sm2_c[SM2_NUM][2]; +static int SM2_sign_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + unsigned char *buf = tempargs->buf; + EVP_MD_CTX **sm2ctx = tempargs->sm2_ctx; + unsigned char *sm2sig = tempargs->buf2; + size_t sm2sigsize; + int ret, count; + EVP_PKEY **sm2_pkey = tempargs->sm2_pkey; + const size_t max_size = EVP_PKEY_get_size(sm2_pkey[testnum]); + + for (count = 0; COND(sm2_c[testnum][0]); count++) { + sm2sigsize = max_size; + + if (!EVP_DigestSignInit(sm2ctx[testnum], NULL, EVP_sm3(), + NULL, sm2_pkey[testnum])) { + BIO_printf(bio_err, "SM2 init sign failure\n"); + ERR_print_errors(bio_err); + count = -1; + break; + } + ret = EVP_DigestSign(sm2ctx[testnum], sm2sig, &sm2sigsize, + buf, 20); + if (ret == 0) { + BIO_printf(bio_err, "SM2 sign failure\n"); + ERR_print_errors(bio_err); + count = -1; + break; + } + /* update the latest returned size and always use the fixed buffer size */ + tempargs->sigsize = sm2sigsize; + } + + return count; +} + +static int SM2_verify_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + unsigned char *buf = tempargs->buf; + EVP_MD_CTX **sm2ctx = tempargs->sm2_vfy_ctx; + unsigned char *sm2sig = tempargs->buf2; + size_t sm2sigsize = tempargs->sigsize; + int ret, count; + EVP_PKEY **sm2_pkey = tempargs->sm2_pkey; + + for (count = 0; COND(sm2_c[testnum][1]); count++) { + if (!EVP_DigestVerifyInit(sm2ctx[testnum], NULL, EVP_sm3(), + NULL, sm2_pkey[testnum])) { + BIO_printf(bio_err, "SM2 verify init failure\n"); + ERR_print_errors(bio_err); + count = -1; + break; + } + ret = EVP_DigestVerify(sm2ctx[testnum], sm2sig, sm2sigsize, + buf, 20); + if (ret != 1) { + BIO_printf(bio_err, "SM2 verify failure\n"); + ERR_print_errors(bio_err); + count = -1; + break; + } + } + return count; +} +#endif /* OPENSSL_NO_SM2 */ static int run_benchmark(int async_jobs, int (*loop_function) (void *), loopargs_t * loopargs) @@ -1383,124 +1257,170 @@ static int run_benchmark(int async_jobs, return error ? -1 : total_op_count; } +typedef struct ec_curve_st { + const char *name; + unsigned int nid; + unsigned int bits; + size_t sigsize; /* only used for EdDSA curves */ +} EC_CURVE; + +static EVP_PKEY *get_ecdsa(const EC_CURVE *curve) +{ + EVP_PKEY_CTX *kctx = NULL; + EVP_PKEY *key = NULL; + + /* Ensure that the error queue is empty */ + if (ERR_peek_error()) { + BIO_printf(bio_err, + "WARNING: the error queue contains previous unhandled errors.\n"); + ERR_print_errors(bio_err); + } + + /* + * Let's try to create a ctx directly from the NID: this works for + * curves like Curve25519 that are not implemented through the low + * level EC interface. + * If this fails we try creating a EVP_PKEY_EC generic param ctx, + * then we set the curve by NID before deriving the actual keygen + * ctx for that specific curve. + */ + kctx = EVP_PKEY_CTX_new_id(curve->nid, NULL); + if (kctx == NULL) { + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *params = NULL; + /* + * If we reach this code EVP_PKEY_CTX_new_id() failed and a + * "int_ctx_new:unsupported algorithm" error was added to the + * error queue. + * We remove it from the error queue as we are handling it. + */ + unsigned long error = ERR_peek_error(); + + if (error == ERR_peek_last_error() /* oldest and latest errors match */ + /* check that the error origin matches */ + && ERR_GET_LIB(error) == ERR_LIB_EVP + && (ERR_GET_REASON(error) == EVP_R_UNSUPPORTED_ALGORITHM + || ERR_GET_REASON(error) == ERR_R_UNSUPPORTED)) + ERR_get_error(); /* pop error from queue */ + if (ERR_peek_error()) { + BIO_printf(bio_err, + "Unhandled error in the error queue during EC key setup.\n"); + ERR_print_errors(bio_err); + return NULL; + } + + /* Create the context for parameter generation */ + if ((pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL + || EVP_PKEY_paramgen_init(pctx) <= 0 + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, + curve->nid) <= 0 + || EVP_PKEY_paramgen(pctx, ¶ms) <= 0) { + BIO_printf(bio_err, "EC params init failure.\n"); + ERR_print_errors(bio_err); + EVP_PKEY_CTX_free(pctx); + return NULL; + } + EVP_PKEY_CTX_free(pctx); + + /* Create the context for the key generation */ + kctx = EVP_PKEY_CTX_new(params, NULL); + EVP_PKEY_free(params); + } + if (kctx == NULL + || EVP_PKEY_keygen_init(kctx) <= 0 + || EVP_PKEY_keygen(kctx, &key) <= 0) { + BIO_printf(bio_err, "EC key generation failure.\n"); + ERR_print_errors(bio_err); + key = NULL; + } + EVP_PKEY_CTX_free(kctx); + return key; +} + +#define stop_it(do_it, test_num)\ + memset(do_it + test_num, 0, OSSL_NELEM(do_it) - test_num); + int speed_main(int argc, char **argv) { ENGINE *e = NULL; loopargs_t *loopargs = NULL; const char *prog; const char *engine_id = NULL; - const EVP_CIPHER *evp_cipher = NULL; + EVP_CIPHER *evp_cipher = NULL; + EVP_MAC *mac = NULL; double d = 0.0; OPTION_CHOICE o; int async_init = 0, multiblock = 0, pr_header = 0; - int doit[ALGOR_NUM] = { 0 }; + uint8_t doit[ALGOR_NUM] = { 0 }; int ret = 1, misalign = 0, lengths_single = 0, aead = 0; long count = 0; - unsigned int size_num = OSSL_NELEM(lengths_list); - unsigned int i, k, loop, loopargs_len = 0, async_jobs = 0; + unsigned int size_num = SIZE_NUM; + unsigned int i, k, loopargs_len = 0, async_jobs = 0; int keylen; int buflen; + BIGNUM *bn = NULL; + EVP_PKEY_CTX *genctx = NULL; #ifndef NO_FORK int multi = 0; #endif -#if !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_DSA) \ - || !defined(OPENSSL_NO_EC) - long rsa_count = 1; -#endif + long op_count = 1; openssl_speed_sec_t seconds = { SECONDS, RSA_SECONDS, DSA_SECONDS, ECDSA_SECONDS, ECDH_SECONDS, - EdDSA_SECONDS }; + EdDSA_SECONDS, SM2_SECONDS, + FFDH_SECONDS }; - /* What follows are the buffers and key material. */ -#ifndef OPENSSL_NO_RC5 - RC5_32_KEY rc5_ks; -#endif -#ifndef OPENSSL_NO_RC2 - RC2_KEY rc2_ks; -#endif -#ifndef OPENSSL_NO_IDEA - IDEA_KEY_SCHEDULE idea_ks; -#endif -#ifndef OPENSSL_NO_SEED - SEED_KEY_SCHEDULE seed_ks; -#endif -#ifndef OPENSSL_NO_BF - BF_KEY bf_ks; -#endif -#ifndef OPENSSL_NO_CAST - CAST_KEY cast_ks; -#endif - static const unsigned char key16[16] = { - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12 - }; - static const unsigned char key24[24] = { - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, - 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34 - }; static const unsigned char key32[32] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56 }; -#ifndef OPENSSL_NO_CAMELLIA - static const unsigned char ckey24[24] = { - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, - 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34 - }; - static const unsigned char ckey32[32] = { - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, - 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, - 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56 - }; - CAMELLIA_KEY camellia_ks1, camellia_ks2, camellia_ks3; -#endif -#ifndef OPENSSL_NO_DES - static DES_cblock key = { - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 - }; - static DES_cblock key2 = { - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12 - }; - static DES_cblock key3 = { - 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34 - }; -#endif -#ifndef OPENSSL_NO_RSA - static const unsigned int rsa_bits[RSA_NUM] = { - 512, 1024, 2048, 3072, 4096, 7680, 15360 - }; - static const unsigned char *rsa_data[RSA_NUM] = { - test512, test1024, test2048, test3072, test4096, test7680, test15360 + static const unsigned char deskey[] = { + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, /* key1 */ + 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, /* key2 */ + 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34 /* key3 */ }; - static const int rsa_data_length[RSA_NUM] = { - sizeof(test512), sizeof(test1024), - sizeof(test2048), sizeof(test3072), - sizeof(test4096), sizeof(test7680), - sizeof(test15360) + static const struct { + const unsigned char *data; + unsigned int length; + unsigned int bits; + } rsa_keys[] = { + { test512, sizeof(test512), 512 }, + { test1024, sizeof(test1024), 1024 }, + { test2048, sizeof(test2048), 2048 }, + { test3072, sizeof(test3072), 3072 }, + { test4096, sizeof(test4096), 4096 }, + { test7680, sizeof(test7680), 7680 }, + { test15360, sizeof(test15360), 15360 } }; - int rsa_doit[RSA_NUM] = { 0 }; + uint8_t rsa_doit[RSA_NUM] = { 0 }; int primes = RSA_DEFAULT_PRIME_NUM; -#endif -#ifndef OPENSSL_NO_DSA +#ifndef OPENSSL_NO_DH + typedef struct ffdh_params_st { + const char *name; + unsigned int nid; + unsigned int bits; + } FFDH_PARAMS; + + static const FFDH_PARAMS ffdh_params[FFDH_NUM] = { + {"ffdh2048", NID_ffdhe2048, 2048}, + {"ffdh3072", NID_ffdhe3072, 3072}, + {"ffdh4096", NID_ffdhe4096, 4096}, + {"ffdh6144", NID_ffdhe6144, 6144}, + {"ffdh8192", NID_ffdhe8192, 8192} + }; + uint8_t ffdh_doit[FFDH_NUM] = { 0 }; + +#endif /* OPENSSL_NO_DH */ static const unsigned int dsa_bits[DSA_NUM] = { 512, 1024, 2048 }; - int dsa_doit[DSA_NUM] = { 0 }; -#endif -#ifndef OPENSSL_NO_EC + uint8_t dsa_doit[DSA_NUM] = { 0 }; /* * We only test over the following curves as they are representative, To * add tests over more curves, simply add the curve NID and curve name to - * the following arrays and increase the |ecdh_choices| list accordingly. + * the following arrays and increase the |ecdh_choices| and |ecdsa_choices| + * lists accordingly. */ - static const struct { - const char *name; - unsigned int nid; - unsigned int bits; - } test_curves[] = { + static const EC_CURVE ec_curves[EC_NUM] = { /* Prime Curves */ {"secp160r1", NID_secp160r1, 160}, {"nistp192", NID_X9_62_prime192v1, 192}, @@ -1508,7 +1428,7 @@ int speed_main(int argc, char **argv) {"nistp256", NID_X9_62_prime256v1, 256}, {"nistp384", NID_secp384r1, 384}, {"nistp521", NID_secp521r1, 521}, -# ifndef OPENSSL_NO_EC2M +#ifndef OPENSSL_NO_EC2M /* Binary Curves */ {"nistk163", NID_sect163k1, 163}, {"nistk233", NID_sect233k1, 233}, @@ -1520,7 +1440,7 @@ int speed_main(int argc, char **argv) {"nistb283", NID_sect283r1, 283}, {"nistb409", NID_sect409r1, 409}, {"nistb571", NID_sect571r1, 571}, -# endif +#endif {"brainpoolP256r1", NID_brainpoolP256r1, 256}, {"brainpoolP256t1", NID_brainpoolP256t1, 256}, {"brainpoolP384r1", NID_brainpoolP384r1, 384}, @@ -1531,22 +1451,36 @@ int speed_main(int argc, char **argv) {"X25519", NID_X25519, 253}, {"X448", NID_X448, 448} }; - static const struct { - const char *name; - unsigned int nid; - unsigned int bits; - size_t sigsize; - } test_ed_curves[] = { + static const EC_CURVE ed_curves[EdDSA_NUM] = { /* EdDSA */ {"Ed25519", NID_ED25519, 253, 64}, {"Ed448", NID_ED448, 456, 114} }; - int ecdsa_doit[ECDSA_NUM] = { 0 }; - int ecdh_doit[EC_NUM] = { 0 }; - int eddsa_doit[EdDSA_NUM] = { 0 }; - OPENSSL_assert(OSSL_NELEM(test_curves) >= EC_NUM); - OPENSSL_assert(OSSL_NELEM(test_ed_curves) >= EdDSA_NUM); -#endif /* ndef OPENSSL_NO_EC */ +#ifndef OPENSSL_NO_SM2 + static const EC_CURVE sm2_curves[SM2_NUM] = { + /* SM2 */ + {"CurveSM2", NID_sm2, 256} + }; + uint8_t sm2_doit[SM2_NUM] = { 0 }; +#endif + uint8_t ecdsa_doit[ECDSA_NUM] = { 0 }; + uint8_t ecdh_doit[EC_NUM] = { 0 }; + uint8_t eddsa_doit[EdDSA_NUM] = { 0 }; + + /* checks declarated curves against choices list. */ + OPENSSL_assert(ed_curves[EdDSA_NUM - 1].nid == NID_ED448); + OPENSSL_assert(strcmp(eddsa_choices[EdDSA_NUM - 1].name, "ed448") == 0); + + OPENSSL_assert(ec_curves[EC_NUM - 1].nid == NID_X448); + OPENSSL_assert(strcmp(ecdh_choices[EC_NUM - 1].name, "ecdhx448") == 0); + + OPENSSL_assert(ec_curves[ECDSA_NUM - 1].nid == NID_brainpoolP512t1); + OPENSSL_assert(strcmp(ecdsa_choices[ECDSA_NUM - 1].name, "ecdsabrp512t1") == 0); + +#ifndef OPENSSL_NO_SM2 + OPENSSL_assert(sm2_curves[SM2_NUM - 1].nid == NID_sm2); + OPENSSL_assert(strcmp(sm2_choices[SM2_NUM - 1].name, "curveSM2") == 0); +#endif prog = opt_init(argc, argv, speed_options); while ((o = opt_next()) != OPT_EOF) { @@ -1564,18 +1498,43 @@ int speed_main(int argc, char **argv) usertime = 0; break; case OPT_EVP: - evp_md = NULL; - evp_cipher = EVP_get_cipherbyname(opt_arg()); - if (evp_cipher == NULL) - evp_md = EVP_get_digestbyname(opt_arg()); - if (evp_cipher == NULL && evp_md == NULL) { + if (doit[D_EVP]) { + BIO_printf(bio_err, "%s: -evp option cannot be used more than once\n", prog); + goto opterr; + } + ERR_set_mark(); + if (!opt_cipher_silent(opt_arg(), &evp_cipher)) { + if (have_md(opt_arg())) + evp_md_name = opt_arg(); + } + if (evp_cipher == NULL && evp_md_name == NULL) { + ERR_clear_last_mark(); BIO_printf(bio_err, "%s: %s is an unknown cipher or digest\n", prog, opt_arg()); goto end; } + ERR_pop_to_mark(); doit[D_EVP] = 1; break; + case OPT_HMAC: + if (!have_md(opt_arg())) { + BIO_printf(bio_err, "%s: %s is an unknown digest\n", + prog, opt_arg()); + goto end; + } + evp_mac_mdname = opt_arg(); + doit[D_HMAC] = 1; + break; + case OPT_CMAC: + if (!have_cipher(opt_arg())) { + BIO_printf(bio_err, "%s: %s is an unknown cipher\n", + prog, opt_arg()); + goto end; + } + evp_mac_ciphername = opt_arg(); + doit[D_EVP_CMAC] = 1; + break; case OPT_DECRYPT: decrypt = 1; break; @@ -1590,7 +1549,7 @@ int speed_main(int argc, char **argv) case OPT_MULTI: #ifndef NO_FORK multi = atoi(opt_arg()); - if (multi >= INT_MAX / (int)sizeof(int)) { + if ((size_t)multi >= SIZE_MAX / sizeof(int)) { BIO_printf(bio_err, "%s: multi argument too large\n", prog); return 0; } @@ -1612,8 +1571,7 @@ int speed_main(int argc, char **argv) #endif break; case OPT_MISALIGN: - if (!opt_int(opt_arg(), &misalign)) - goto end; + misalign = opt_int_arg(); if (misalign > MISALIGN) { BIO_printf(bio_err, "%s: Maximum offset is %d\n", prog, MISALIGN); @@ -1636,13 +1594,17 @@ int speed_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; - case OPT_PRIMES: - if (!opt_int(opt_arg(), &primes)) + case OPT_PROV_CASES: + if (!opt_provider(o)) goto end; break; + case OPT_PRIMES: + primes = opt_int_arg(); + break; case OPT_SECONDS: seconds.sym = seconds.rsa = seconds.dsa = seconds.ecdsa - = seconds.ecdh = seconds.eddsa = atoi(opt_arg()); + = seconds.ecdh = seconds.eddsa + = seconds.sm2 = seconds.ffdh = atoi(opt_arg()); break; case OPT_BYTES: lengths_single = atoi(opt_arg()); @@ -1654,89 +1616,112 @@ int speed_main(int argc, char **argv) break; } } + + /* Remaining arguments are algorithms. */ argc = opt_num_rest(); argv = opt_rest(); - /* Remaining arguments are algorithms. */ + if (!app_RAND_load()) + goto end; + for (; *argv; argv++) { - if (found(*argv, doit_choices, &i)) { + const char *algo = *argv; + + if (opt_found(algo, doit_choices, &i)) { doit[i] = 1; continue; } -#ifndef OPENSSL_NO_DES - if (strcmp(*argv, "des") == 0) { + if (strcmp(algo, "des") == 0) { doit[D_CBC_DES] = doit[D_EDE3_DES] = 1; continue; } -#endif - if (strcmp(*argv, "sha") == 0) { + if (strcmp(algo, "sha") == 0) { doit[D_SHA1] = doit[D_SHA256] = doit[D_SHA512] = 1; continue; } -#ifndef OPENSSL_NO_RSA - if (strcmp(*argv, "openssl") == 0) - continue; - if (strcmp(*argv, "rsa") == 0) { - for (loop = 0; loop < OSSL_NELEM(rsa_doit); loop++) - rsa_doit[loop] = 1; - continue; - } - if (found(*argv, rsa_choices, &i)) { - rsa_doit[i] = 1; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + if (strcmp(algo, "openssl") == 0) /* just for compatibility */ continue; - } #endif -#ifndef OPENSSL_NO_DSA - if (strcmp(*argv, "dsa") == 0) { - dsa_doit[R_DSA_512] = dsa_doit[R_DSA_1024] = - dsa_doit[R_DSA_2048] = 1; - continue; + if (strncmp(algo, "rsa", 3) == 0) { + if (algo[3] == '\0') { + memset(rsa_doit, 1, sizeof(rsa_doit)); + continue; + } + if (opt_found(algo, rsa_choices, &i)) { + rsa_doit[i] = 1; + continue; + } } - if (found(*argv, dsa_choices, &i)) { - dsa_doit[i] = 2; - continue; +#ifndef OPENSSL_NO_DH + if (strncmp(algo, "ffdh", 4) == 0) { + if (algo[4] == '\0') { + memset(ffdh_doit, 1, sizeof(ffdh_doit)); + continue; + } + if (opt_found(algo, ffdh_choices, &i)) { + ffdh_doit[i] = 2; + continue; + } } #endif - if (strcmp(*argv, "aes") == 0) { + if (strncmp(algo, "dsa", 3) == 0) { + if (algo[3] == '\0') { + memset(dsa_doit, 1, sizeof(dsa_doit)); + continue; + } + if (opt_found(algo, dsa_choices, &i)) { + dsa_doit[i] = 2; + continue; + } + } + if (strcmp(algo, "aes") == 0) { doit[D_CBC_128_AES] = doit[D_CBC_192_AES] = doit[D_CBC_256_AES] = 1; continue; } -#ifndef OPENSSL_NO_CAMELLIA - if (strcmp(*argv, "camellia") == 0) { + if (strcmp(algo, "camellia") == 0) { doit[D_CBC_128_CML] = doit[D_CBC_192_CML] = doit[D_CBC_256_CML] = 1; continue; } -#endif -#ifndef OPENSSL_NO_EC - if (strcmp(*argv, "ecdsa") == 0) { - for (loop = 0; loop < OSSL_NELEM(ecdsa_doit); loop++) - ecdsa_doit[loop] = 1; - continue; + if (strncmp(algo, "ecdsa", 5) == 0) { + if (algo[5] == '\0') { + memset(ecdsa_doit, 1, sizeof(ecdsa_doit)); + continue; + } + if (opt_found(algo, ecdsa_choices, &i)) { + ecdsa_doit[i] = 2; + continue; + } } - if (found(*argv, ecdsa_choices, &i)) { - ecdsa_doit[i] = 2; - continue; + if (strncmp(algo, "ecdh", 4) == 0) { + if (algo[4] == '\0') { + memset(ecdh_doit, 1, sizeof(ecdh_doit)); + continue; + } + if (opt_found(algo, ecdh_choices, &i)) { + ecdh_doit[i] = 2; + continue; + } } - if (strcmp(*argv, "ecdh") == 0) { - for (loop = 0; loop < OSSL_NELEM(ecdh_doit); loop++) - ecdh_doit[loop] = 1; + if (strcmp(algo, "eddsa") == 0) { + memset(eddsa_doit, 1, sizeof(eddsa_doit)); continue; } - if (found(*argv, ecdh_choices, &i)) { - ecdh_doit[i] = 2; + if (opt_found(algo, eddsa_choices, &i)) { + eddsa_doit[i] = 2; continue; } - if (strcmp(*argv, "eddsa") == 0) { - for (loop = 0; loop < OSSL_NELEM(eddsa_doit); loop++) - eddsa_doit[loop] = 1; +#ifndef OPENSSL_NO_SM2 + if (strcmp(algo, "sm2") == 0) { + memset(sm2_doit, 1, sizeof(sm2_doit)); continue; } - if (found(*argv, eddsa_choices, &i)) { - eddsa_doit[i] = 2; + if (opt_found(algo, sm2_choices, &i)) { + sm2_doit[i] = 2; continue; } #endif - BIO_printf(bio_err, "%s: Unknown algorithm %s\n", prog, *argv); + BIO_printf(bio_err, "%s: Unknown algorithm %s\n", prog, algo); goto end; } @@ -1745,22 +1730,22 @@ int speed_main(int argc, char **argv) if (evp_cipher == NULL) { BIO_printf(bio_err, "-aead can be used only with an AEAD cipher\n"); goto end; - } else if (!(EVP_CIPHER_flags(evp_cipher) & + } else if (!(EVP_CIPHER_get_flags(evp_cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) { BIO_printf(bio_err, "%s is not an AEAD cipher\n", - OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher))); + EVP_CIPHER_get0_name(evp_cipher)); goto end; } } if (multiblock) { if (evp_cipher == NULL) { - BIO_printf(bio_err,"-mb can be used only with a multi-block" - " capable cipher\n"); + BIO_printf(bio_err, "-mb can be used only with a multi-block" + " capable cipher\n"); goto end; - } else if (!(EVP_CIPHER_flags(evp_cipher) & + } else if (!(EVP_CIPHER_get_flags(evp_cipher) & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { BIO_printf(bio_err, "%s is not a multi-block capable\n", - OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher))); + EVP_CIPHER_get0_name(evp_cipher)); goto end; } else if (async_jobs > 0) { BIO_printf(bio_err, "Async mode is not supported with -mb"); @@ -1794,6 +1779,10 @@ int speed_main(int argc, char **argv) buflen = lengths[size_num - 1]; if (buflen < 36) /* size of random vector in RSA benchmark */ buflen = 36; + if (INT_MAX - (MAX_MISALIGNMENT + 1) < buflen) { + BIO_printf(bio_err, "Error: buffer size too large\n"); + goto end; + } buflen += MAX_MISALIGNMENT + 1; loopargs[i].buf_malloc = app_malloc(buflen, "input buffer"); loopargs[i].buf2_malloc = app_malloc(buflen, "input buffer"); @@ -1803,9 +1792,13 @@ int speed_main(int argc, char **argv) /* Align the start of buffers on a 64 byte boundary */ loopargs[i].buf = loopargs[i].buf_malloc + misalign; loopargs[i].buf2 = loopargs[i].buf2_malloc + misalign; -#ifndef OPENSSL_NO_EC + loopargs[i].buflen = buflen - misalign; + loopargs[i].sigsize = buflen - misalign; loopargs[i].secret_a = app_malloc(MAX_ECDH_SIZE, "ECDH secret a"); loopargs[i].secret_b = app_malloc(MAX_ECDH_SIZE, "ECDH secret b"); +#ifndef OPENSSL_NO_DH + loopargs[i].secret_ff_a = app_malloc(MAX_FFDH_SIZE, "FFDH secret a"); + loopargs[i].secret_ff_b = app_malloc(MAX_FFDH_SIZE, "FFDH secret b"); #endif } @@ -1818,25 +1811,43 @@ int speed_main(int argc, char **argv) e = setup_engine(engine_id, 0); /* No parameters; turn on everything. */ - if ((argc == 0) && !doit[D_EVP]) { - for (i = 0; i < ALGOR_NUM; i++) - if (i != D_EVP) - doit[i] = 1; -#ifndef OPENSSL_NO_RSA - for (i = 0; i < RSA_NUM; i++) - rsa_doit[i] = 1; -#endif -#ifndef OPENSSL_NO_DSA - for (i = 0; i < DSA_NUM; i++) - dsa_doit[i] = 1; + if (argc == 0 && !doit[D_EVP] && !doit[D_HMAC] && !doit[D_EVP_CMAC]) { + memset(doit, 1, sizeof(doit)); + doit[D_EVP] = doit[D_EVP_CMAC] = 0; + ERR_set_mark(); + for (i = D_MD2; i <= D_WHIRLPOOL; i++) { + if (!have_md(names[i])) + doit[i] = 0; + } + for (i = D_CBC_DES; i <= D_CBC_256_CML; i++) { + if (!have_cipher(names[i])) + doit[i] = 0; + } + if ((mac = EVP_MAC_fetch(app_get0_libctx(), "GMAC", + app_get0_propq())) != NULL) { + EVP_MAC_free(mac); + mac = NULL; + } else { + doit[D_GHASH] = 0; + } + if ((mac = EVP_MAC_fetch(app_get0_libctx(), "HMAC", + app_get0_propq())) != NULL) { + EVP_MAC_free(mac); + mac = NULL; + } else { + doit[D_HMAC] = 0; + } + ERR_pop_to_mark(); + memset(rsa_doit, 1, sizeof(rsa_doit)); +#ifndef OPENSSL_NO_DH + memset(ffdh_doit, 1, sizeof(ffdh_doit)); #endif -#ifndef OPENSSL_NO_EC - for (loop = 0; loop < OSSL_NELEM(ecdsa_doit); loop++) - ecdsa_doit[loop] = 1; - for (loop = 0; loop < OSSL_NELEM(ecdh_doit); loop++) - ecdh_doit[loop] = 1; - for (loop = 0; loop < OSSL_NELEM(eddsa_doit); loop++) - eddsa_doit[loop] = 1; + memset(dsa_doit, 1, sizeof(dsa_doit)); + memset(ecdsa_doit, 1, sizeof(ecdsa_doit)); + memset(ecdh_doit, 1, sizeof(ecdh_doit)); + memset(eddsa_doit, 1, sizeof(eddsa_doit)); +#ifndef OPENSSL_NO_SM2 + memset(sm2_doit, 1, sizeof(sm2_doit)); #endif } for (i = 0; i < ALGOR_NUM; i++) @@ -1848,308 +1859,10 @@ int speed_main(int argc, char **argv) "You have chosen to measure elapsed time " "instead of user CPU time.\n"); -#ifndef OPENSSL_NO_RSA - for (i = 0; i < loopargs_len; i++) { - if (primes > RSA_DEFAULT_PRIME_NUM) { - /* for multi-prime RSA, skip this */ - break; - } - for (k = 0; k < RSA_NUM; k++) { - const unsigned char *p; - - p = rsa_data[k]; - loopargs[i].rsa_key[k] = - d2i_RSAPrivateKey(NULL, &p, rsa_data_length[k]); - if (loopargs[i].rsa_key[k] == NULL) { - BIO_printf(bio_err, - "internal error loading RSA key number %d\n", k); - goto end; - } - } - } -#endif -#ifndef OPENSSL_NO_DSA - for (i = 0; i < loopargs_len; i++) { - loopargs[i].dsa_key[0] = get_dsa(512); - loopargs[i].dsa_key[1] = get_dsa(1024); - loopargs[i].dsa_key[2] = get_dsa(2048); - } -#endif -#ifndef OPENSSL_NO_DES - DES_set_key_unchecked(&key, &sch); - DES_set_key_unchecked(&key2, &sch2); - DES_set_key_unchecked(&key3, &sch3); -#endif - AES_set_encrypt_key(key16, 128, &aes_ks1); - AES_set_encrypt_key(key24, 192, &aes_ks2); - AES_set_encrypt_key(key32, 256, &aes_ks3); -#ifndef OPENSSL_NO_CAMELLIA - Camellia_set_key(key16, 128, &camellia_ks1); - Camellia_set_key(ckey24, 192, &camellia_ks2); - Camellia_set_key(ckey32, 256, &camellia_ks3); -#endif -#ifndef OPENSSL_NO_IDEA - IDEA_set_encrypt_key(key16, &idea_ks); -#endif -#ifndef OPENSSL_NO_SEED - SEED_set_key(key16, &seed_ks); -#endif -#ifndef OPENSSL_NO_RC4 - RC4_set_key(&rc4_ks, 16, key16); -#endif -#ifndef OPENSSL_NO_RC2 - RC2_set_key(&rc2_ks, 16, key16, 128); -#endif -#ifndef OPENSSL_NO_RC5 - RC5_32_set_key(&rc5_ks, 16, key16, 12); -#endif -#ifndef OPENSSL_NO_BF - BF_set_key(&bf_ks, 16, key16); -#endif -#ifndef OPENSSL_NO_CAST - CAST_set_key(&cast_ks, 16, key16); -#endif -#ifndef SIGALRM -# ifndef OPENSSL_NO_DES - BIO_printf(bio_err, "First we calculate the approximate speed ...\n"); - count = 10; - do { - long it; - count *= 2; - Time_F(START); - for (it = count; it; it--) - DES_ecb_encrypt((DES_cblock *)loopargs[0].buf, - (DES_cblock *)loopargs[0].buf, &sch, DES_ENCRYPT); - d = Time_F(STOP); - } while (d < 3); - save_count = count; - c[D_MD2][0] = count / 10; - c[D_MDC2][0] = count / 10; - c[D_MD4][0] = count; - c[D_MD5][0] = count; - c[D_HMAC][0] = count; - c[D_SHA1][0] = count; - c[D_RMD160][0] = count; - c[D_RC4][0] = count * 5; - c[D_CBC_DES][0] = count; - c[D_EDE3_DES][0] = count / 3; - c[D_CBC_IDEA][0] = count; - c[D_CBC_SEED][0] = count; - c[D_CBC_RC2][0] = count; - c[D_CBC_RC5][0] = count; - c[D_CBC_BF][0] = count; - c[D_CBC_CAST][0] = count; - c[D_CBC_128_AES][0] = count; - c[D_CBC_192_AES][0] = count; - c[D_CBC_256_AES][0] = count; - c[D_CBC_128_CML][0] = count; - c[D_CBC_192_CML][0] = count; - c[D_CBC_256_CML][0] = count; - c[D_SHA256][0] = count; - c[D_SHA512][0] = count; - c[D_WHIRLPOOL][0] = count; - c[D_IGE_128_AES][0] = count; - c[D_IGE_192_AES][0] = count; - c[D_IGE_256_AES][0] = count; - c[D_GHASH][0] = count; - c[D_RAND][0] = count; - - for (i = 1; i < size_num; i++) { - long l0, l1; - - l0 = (long)lengths[0]; - l1 = (long)lengths[i]; - - c[D_MD2][i] = c[D_MD2][0] * 4 * l0 / l1; - c[D_MDC2][i] = c[D_MDC2][0] * 4 * l0 / l1; - c[D_MD4][i] = c[D_MD4][0] * 4 * l0 / l1; - c[D_MD5][i] = c[D_MD5][0] * 4 * l0 / l1; - c[D_HMAC][i] = c[D_HMAC][0] * 4 * l0 / l1; - c[D_SHA1][i] = c[D_SHA1][0] * 4 * l0 / l1; - c[D_RMD160][i] = c[D_RMD160][0] * 4 * l0 / l1; - c[D_SHA256][i] = c[D_SHA256][0] * 4 * l0 / l1; - c[D_SHA512][i] = c[D_SHA512][0] * 4 * l0 / l1; - c[D_WHIRLPOOL][i] = c[D_WHIRLPOOL][0] * 4 * l0 / l1; - c[D_GHASH][i] = c[D_GHASH][0] * 4 * l0 / l1; - c[D_RAND][i] = c[D_RAND][0] * 4 * l0 / l1; - - l0 = (long)lengths[i - 1]; - - c[D_RC4][i] = c[D_RC4][i - 1] * l0 / l1; - c[D_CBC_DES][i] = c[D_CBC_DES][i - 1] * l0 / l1; - c[D_EDE3_DES][i] = c[D_EDE3_DES][i - 1] * l0 / l1; - c[D_CBC_IDEA][i] = c[D_CBC_IDEA][i - 1] * l0 / l1; - c[D_CBC_SEED][i] = c[D_CBC_SEED][i - 1] * l0 / l1; - c[D_CBC_RC2][i] = c[D_CBC_RC2][i - 1] * l0 / l1; - c[D_CBC_RC5][i] = c[D_CBC_RC5][i - 1] * l0 / l1; - c[D_CBC_BF][i] = c[D_CBC_BF][i - 1] * l0 / l1; - c[D_CBC_CAST][i] = c[D_CBC_CAST][i - 1] * l0 / l1; - c[D_CBC_128_AES][i] = c[D_CBC_128_AES][i - 1] * l0 / l1; - c[D_CBC_192_AES][i] = c[D_CBC_192_AES][i - 1] * l0 / l1; - c[D_CBC_256_AES][i] = c[D_CBC_256_AES][i - 1] * l0 / l1; - c[D_CBC_128_CML][i] = c[D_CBC_128_CML][i - 1] * l0 / l1; - c[D_CBC_192_CML][i] = c[D_CBC_192_CML][i - 1] * l0 / l1; - c[D_CBC_256_CML][i] = c[D_CBC_256_CML][i - 1] * l0 / l1; - c[D_IGE_128_AES][i] = c[D_IGE_128_AES][i - 1] * l0 / l1; - c[D_IGE_192_AES][i] = c[D_IGE_192_AES][i - 1] * l0 / l1; - c[D_IGE_256_AES][i] = c[D_IGE_256_AES][i - 1] * l0 / l1; - } - -# ifndef OPENSSL_NO_RSA - rsa_c[R_RSA_512][0] = count / 2000; - rsa_c[R_RSA_512][1] = count / 400; - for (i = 1; i < RSA_NUM; i++) { - rsa_c[i][0] = rsa_c[i - 1][0] / 8; - rsa_c[i][1] = rsa_c[i - 1][1] / 4; - if (rsa_doit[i] <= 1 && rsa_c[i][0] == 0) - rsa_doit[i] = 0; - else { - if (rsa_c[i][0] == 0) { - rsa_c[i][0] = 1; /* Set minimum iteration Nb to 1. */ - rsa_c[i][1] = 20; - } - } - } -# endif - -# ifndef OPENSSL_NO_DSA - dsa_c[R_DSA_512][0] = count / 1000; - dsa_c[R_DSA_512][1] = count / 1000 / 2; - for (i = 1; i < DSA_NUM; i++) { - dsa_c[i][0] = dsa_c[i - 1][0] / 4; - dsa_c[i][1] = dsa_c[i - 1][1] / 4; - if (dsa_doit[i] <= 1 && dsa_c[i][0] == 0) - dsa_doit[i] = 0; - else { - if (dsa_c[i][0] == 0) { - dsa_c[i][0] = 1; /* Set minimum iteration Nb to 1. */ - dsa_c[i][1] = 1; - } - } - } -# endif - -# ifndef OPENSSL_NO_EC - ecdsa_c[R_EC_P160][0] = count / 1000; - ecdsa_c[R_EC_P160][1] = count / 1000 / 2; - for (i = R_EC_P192; i <= R_EC_P521; i++) { - ecdsa_c[i][0] = ecdsa_c[i - 1][0] / 2; - ecdsa_c[i][1] = ecdsa_c[i - 1][1] / 2; - if (ecdsa_doit[i] <= 1 && ecdsa_c[i][0] == 0) - ecdsa_doit[i] = 0; - else { - if (ecdsa_c[i][0] == 0) { - ecdsa_c[i][0] = 1; - ecdsa_c[i][1] = 1; - } - } - } -# ifndef OPENSSL_NO_EC2M - ecdsa_c[R_EC_K163][0] = count / 1000; - ecdsa_c[R_EC_K163][1] = count / 1000 / 2; - for (i = R_EC_K233; i <= R_EC_K571; i++) { - ecdsa_c[i][0] = ecdsa_c[i - 1][0] / 2; - ecdsa_c[i][1] = ecdsa_c[i - 1][1] / 2; - if (ecdsa_doit[i] <= 1 && ecdsa_c[i][0] == 0) - ecdsa_doit[i] = 0; - else { - if (ecdsa_c[i][0] == 0) { - ecdsa_c[i][0] = 1; - ecdsa_c[i][1] = 1; - } - } - } - ecdsa_c[R_EC_B163][0] = count / 1000; - ecdsa_c[R_EC_B163][1] = count / 1000 / 2; - for (i = R_EC_B233; i <= R_EC_B571; i++) { - ecdsa_c[i][0] = ecdsa_c[i - 1][0] / 2; - ecdsa_c[i][1] = ecdsa_c[i - 1][1] / 2; - if (ecdsa_doit[i] <= 1 && ecdsa_c[i][0] == 0) - ecdsa_doit[i] = 0; - else { - if (ecdsa_c[i][0] == 0) { - ecdsa_c[i][0] = 1; - ecdsa_c[i][1] = 1; - } - } - } -# endif - - ecdh_c[R_EC_P160][0] = count / 1000; - for (i = R_EC_P192; i <= R_EC_P521; i++) { - ecdh_c[i][0] = ecdh_c[i - 1][0] / 2; - if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0) - ecdh_doit[i] = 0; - else { - if (ecdh_c[i][0] == 0) { - ecdh_c[i][0] = 1; - } - } - } -# ifndef OPENSSL_NO_EC2M - ecdh_c[R_EC_K163][0] = count / 1000; - for (i = R_EC_K233; i <= R_EC_K571; i++) { - ecdh_c[i][0] = ecdh_c[i - 1][0] / 2; - if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0) - ecdh_doit[i] = 0; - else { - if (ecdh_c[i][0] == 0) { - ecdh_c[i][0] = 1; - } - } - } - ecdh_c[R_EC_B163][0] = count / 1000; - for (i = R_EC_B233; i <= R_EC_B571; i++) { - ecdh_c[i][0] = ecdh_c[i - 1][0] / 2; - if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0) - ecdh_doit[i] = 0; - else { - if (ecdh_c[i][0] == 0) { - ecdh_c[i][0] = 1; - } - } - } -# endif - /* repeated code good to factorize */ - ecdh_c[R_EC_BRP256R1][0] = count / 1000; - for (i = R_EC_BRP384R1; i <= R_EC_BRP512R1; i += 2) { - ecdh_c[i][0] = ecdh_c[i - 2][0] / 2; - if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0) - ecdh_doit[i] = 0; - else { - if (ecdh_c[i][0] == 0) { - ecdh_c[i][0] = 1; - } - } - } - ecdh_c[R_EC_BRP256T1][0] = count / 1000; - for (i = R_EC_BRP384T1; i <= R_EC_BRP512T1; i += 2) { - ecdh_c[i][0] = ecdh_c[i - 2][0] / 2; - if (ecdh_doit[i] <= 1 && ecdh_c[i][0] == 0) - ecdh_doit[i] = 0; - else { - if (ecdh_c[i][0] == 0) { - ecdh_c[i][0] = 1; - } - } - } - /* default iteration count for the last two EC Curves */ - ecdh_c[R_EC_X25519][0] = count / 1800; - ecdh_c[R_EC_X448][0] = count / 7200; - - eddsa_c[R_EC_Ed25519][0] = count / 1800; - eddsa_c[R_EC_Ed448][0] = count / 7200; -# endif - -# else -/* not worth fixing */ -# error "You cannot disable DES on systems without SIGALRM." -# endif /* OPENSSL_NO_DES */ -#elif SIGALRM > 0 +#if SIGALRM > 0 signal(SIGALRM, alarmed); -#endif /* SIGALRM */ +#endif -#ifndef OPENSSL_NO_MD2 if (doit[D_MD2]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_MD2], c[D_MD2][testnum], lengths[testnum], @@ -2158,10 +1871,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, EVP_Digest_MD2_loop, loopargs); d = Time_F(STOP); print_result(D_MD2, testnum, count, d); + if (count < 0) + break; } } -#endif -#ifndef OPENSSL_NO_MDC2 + if (doit[D_MDC2]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_MDC2], c[D_MDC2][testnum], lengths[testnum], @@ -2170,11 +1884,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, EVP_Digest_MDC2_loop, loopargs); d = Time_F(STOP); print_result(D_MDC2, testnum, count, d); + if (count < 0) + break; } } -#endif -#ifndef OPENSSL_NO_MD4 if (doit[D_MD4]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_MD4], c[D_MD4][testnum], lengths[testnum], @@ -2183,11 +1897,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, EVP_Digest_MD4_loop, loopargs); d = Time_F(STOP); print_result(D_MD4, testnum, count, d); + if (count < 0) + break; } } -#endif -#ifndef OPENSSL_NO_MD5 if (doit[D_MD5]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_MD5], c[D_MD5][testnum], lengths[testnum], @@ -2196,35 +1910,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, MD5_loop, loopargs); d = Time_F(STOP); print_result(D_MD5, testnum, count, d); + if (count < 0) + break; } } - if (doit[D_HMAC]) { - static const char hmac_key[] = "This is a key..."; - int len = strlen(hmac_key); - - for (i = 0; i < loopargs_len; i++) { - loopargs[i].hctx = HMAC_CTX_new(); - if (loopargs[i].hctx == NULL) { - BIO_printf(bio_err, "HMAC malloc failure, exiting..."); - exit(1); - } - - HMAC_Init_ex(loopargs[i].hctx, hmac_key, len, EVP_md5(), NULL); - } - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_HMAC], c[D_HMAC][testnum], lengths[testnum], - seconds.sym); - Time_F(START); - count = run_benchmark(async_jobs, HMAC_loop, loopargs); - d = Time_F(STOP); - print_result(D_HMAC, testnum, count, d); - } - for (i = 0; i < loopargs_len; i++) { - HMAC_CTX_free(loopargs[i].hctx); - } - } -#endif if (doit[D_SHA1]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_SHA1], c[D_SHA1][testnum], lengths[testnum], @@ -2233,8 +1923,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, SHA1_loop, loopargs); d = Time_F(STOP); print_result(D_SHA1, testnum, count, d); + if (count < 0) + break; } } + if (doit[D_SHA256]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_SHA256], c[D_SHA256][testnum], @@ -2243,8 +1936,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, SHA256_loop, loopargs); d = Time_F(STOP); print_result(D_SHA256, testnum, count, d); + if (count < 0) + break; } } + if (doit[D_SHA512]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_SHA512], c[D_SHA512][testnum], @@ -2253,9 +1949,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, SHA512_loop, loopargs); d = Time_F(STOP); print_result(D_SHA512, testnum, count, d); + if (count < 0) + break; } } -#ifndef OPENSSL_NO_WHIRLPOOL + if (doit[D_WHIRLPOOL]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_WHIRLPOOL], c[D_WHIRLPOOL][testnum], @@ -2264,11 +1962,11 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, WHIRLPOOL_loop, loopargs); d = Time_F(STOP); print_result(D_WHIRLPOOL, testnum, count, d); + if (count < 0) + break; } } -#endif -#ifndef OPENSSL_NO_RMD160 if (doit[D_RMD160]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_RMD160], c[D_RMD160][testnum], @@ -2277,319 +1975,215 @@ int speed_main(int argc, char **argv) count = run_benchmark(async_jobs, EVP_Digest_RMD160_loop, loopargs); d = Time_F(STOP); print_result(D_RMD160, testnum, count, d); + if (count < 0) + break; } } -#endif -#ifndef OPENSSL_NO_RC4 - if (doit[D_RC4]) { + + if (doit[D_HMAC]) { + static const char hmac_key[] = "This is a key..."; + int len = strlen(hmac_key); + OSSL_PARAM params[3]; + + mac = EVP_MAC_fetch(app_get0_libctx(), "HMAC", app_get0_propq()); + if (mac == NULL || evp_mac_mdname == NULL) + goto end; + + evp_hmac_name = app_malloc(sizeof("hmac()") + strlen(evp_mac_mdname), + "HMAC name"); + sprintf(evp_hmac_name, "hmac(%s)", evp_mac_mdname); + names[D_HMAC] = evp_hmac_name; + + params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, + evp_mac_mdname, 0); + params[1] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + (char *)hmac_key, len); + params[2] = OSSL_PARAM_construct_end(); + + for (i = 0; i < loopargs_len; i++) { + loopargs[i].mctx = EVP_MAC_CTX_new(mac); + if (loopargs[i].mctx == NULL) + goto end; + + if (!EVP_MAC_CTX_set_params(loopargs[i].mctx, params)) + goto skip_hmac; /* Digest not found */ + } for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_RC4], c[D_RC4][testnum], lengths[testnum], + print_message(names[D_HMAC], c[D_HMAC][testnum], lengths[testnum], seconds.sym); Time_F(START); - count = run_benchmark(async_jobs, RC4_loop, loopargs); + count = run_benchmark(async_jobs, HMAC_loop, loopargs); d = Time_F(STOP); - print_result(D_RC4, testnum, count, d); + print_result(D_HMAC, testnum, count, d); + if (count < 0) + break; } + for (i = 0; i < loopargs_len; i++) + EVP_MAC_CTX_free(loopargs[i].mctx); + EVP_MAC_free(mac); + mac = NULL; } -#endif -#ifndef OPENSSL_NO_DES +skip_hmac: if (doit[D_CBC_DES]) { - for (testnum = 0; testnum < size_num; testnum++) { + int st = 1; + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ctx = init_evp_cipher_ctx("des-cbc", deskey, + sizeof(deskey) / 3); + st = loopargs[i].ctx != NULL; + } + algindex = D_CBC_DES; + for (testnum = 0; st && testnum < size_num; testnum++) { print_message(names[D_CBC_DES], c[D_CBC_DES][testnum], lengths[testnum], seconds.sym); Time_F(START); - count = run_benchmark(async_jobs, DES_ncbc_encrypt_loop, loopargs); + count = run_benchmark(async_jobs, EVP_Cipher_loop, loopargs); d = Time_F(STOP); print_result(D_CBC_DES, testnum, count, d); } + for (i = 0; i < loopargs_len; i++) + EVP_CIPHER_CTX_free(loopargs[i].ctx); } if (doit[D_EDE3_DES]) { - for (testnum = 0; testnum < size_num; testnum++) { + int st = 1; + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ctx = init_evp_cipher_ctx("des-ede3-cbc", deskey, + sizeof(deskey)); + st = loopargs[i].ctx != NULL; + } + algindex = D_EDE3_DES; + for (testnum = 0; st && testnum < size_num; testnum++) { print_message(names[D_EDE3_DES], c[D_EDE3_DES][testnum], lengths[testnum], seconds.sym); Time_F(START); count = - run_benchmark(async_jobs, DES_ede3_cbc_encrypt_loop, loopargs); + run_benchmark(async_jobs, EVP_Cipher_loop, loopargs); d = Time_F(STOP); print_result(D_EDE3_DES, testnum, count, d); } + for (i = 0; i < loopargs_len; i++) + EVP_CIPHER_CTX_free(loopargs[i].ctx); } -#endif - if (doit[D_CBC_128_AES]) { - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_CBC_128_AES], c[D_CBC_128_AES][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - count = - run_benchmark(async_jobs, AES_cbc_128_encrypt_loop, loopargs); - d = Time_F(STOP); - print_result(D_CBC_128_AES, testnum, count, d); - } - } - if (doit[D_CBC_192_AES]) { - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_CBC_192_AES], c[D_CBC_192_AES][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - count = - run_benchmark(async_jobs, AES_cbc_192_encrypt_loop, loopargs); - d = Time_F(STOP); - print_result(D_CBC_192_AES, testnum, count, d); - } - } - if (doit[D_CBC_256_AES]) { - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_CBC_256_AES], c[D_CBC_256_AES][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - count = - run_benchmark(async_jobs, AES_cbc_256_encrypt_loop, loopargs); - d = Time_F(STOP); - print_result(D_CBC_256_AES, testnum, count, d); - } - } + for (k = 0; k < 3; k++) { + algindex = D_CBC_128_AES + k; + if (doit[algindex]) { + int st = 1; - if (doit[D_IGE_128_AES]) { - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_IGE_128_AES], c[D_IGE_128_AES][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - count = - run_benchmark(async_jobs, AES_ige_128_encrypt_loop, loopargs); - d = Time_F(STOP); - print_result(D_IGE_128_AES, testnum, count, d); + keylen = 16 + k * 8; + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ctx = init_evp_cipher_ctx(names[algindex], + key32, keylen); + st = loopargs[i].ctx != NULL; + } + + for (testnum = 0; st && testnum < size_num; testnum++) { + print_message(names[algindex], c[algindex][testnum], + lengths[testnum], seconds.sym); + Time_F(START); + count = + run_benchmark(async_jobs, EVP_Cipher_loop, loopargs); + d = Time_F(STOP); + print_result(algindex, testnum, count, d); + } + for (i = 0; i < loopargs_len; i++) + EVP_CIPHER_CTX_free(loopargs[i].ctx); } } - if (doit[D_IGE_192_AES]) { - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_IGE_192_AES], c[D_IGE_192_AES][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - count = - run_benchmark(async_jobs, AES_ige_192_encrypt_loop, loopargs); - d = Time_F(STOP); - print_result(D_IGE_192_AES, testnum, count, d); + + for (k = 0; k < 3; k++) { + algindex = D_CBC_128_CML + k; + if (doit[algindex]) { + int st = 1; + + keylen = 16 + k * 8; + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ctx = init_evp_cipher_ctx(names[algindex], + key32, keylen); + st = loopargs[i].ctx != NULL; + } + + for (testnum = 0; st && testnum < size_num; testnum++) { + print_message(names[algindex], c[algindex][testnum], + lengths[testnum], seconds.sym); + Time_F(START); + count = + run_benchmark(async_jobs, EVP_Cipher_loop, loopargs); + d = Time_F(STOP); + print_result(algindex, testnum, count, d); + } + for (i = 0; i < loopargs_len; i++) + EVP_CIPHER_CTX_free(loopargs[i].ctx); } } - if (doit[D_IGE_256_AES]) { - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_IGE_256_AES], c[D_IGE_256_AES][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - count = - run_benchmark(async_jobs, AES_ige_256_encrypt_loop, loopargs); - d = Time_F(STOP); - print_result(D_IGE_256_AES, testnum, count, d); + + for (algindex = D_RC4; algindex <= D_CBC_CAST; algindex++) { + if (doit[algindex]) { + int st = 1; + + keylen = 16; + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ctx = init_evp_cipher_ctx(names[algindex], + key32, keylen); + st = loopargs[i].ctx != NULL; + } + + for (testnum = 0; st && testnum < size_num; testnum++) { + print_message(names[algindex], c[algindex][testnum], + lengths[testnum], seconds.sym); + Time_F(START); + count = + run_benchmark(async_jobs, EVP_Cipher_loop, loopargs); + d = Time_F(STOP); + print_result(algindex, testnum, count, d); + } + for (i = 0; i < loopargs_len; i++) + EVP_CIPHER_CTX_free(loopargs[i].ctx); } } if (doit[D_GHASH]) { + static const char gmac_iv[] = "0123456789ab"; + OSSL_PARAM params[3]; + + mac = EVP_MAC_fetch(app_get0_libctx(), "GMAC", app_get0_propq()); + if (mac == NULL) + goto end; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_CIPHER, + "aes-128-gcm", 0); + params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_IV, + (char *)gmac_iv, + sizeof(gmac_iv) - 1); + params[2] = OSSL_PARAM_construct_end(); + for (i = 0; i < loopargs_len; i++) { - loopargs[i].gcm_ctx = - CRYPTO_gcm128_new(&aes_ks1, (block128_f) AES_encrypt); - CRYPTO_gcm128_setiv(loopargs[i].gcm_ctx, - (unsigned char *)"0123456789ab", 12); - } + loopargs[i].mctx = EVP_MAC_CTX_new(mac); + if (loopargs[i].mctx == NULL) + goto end; + if (!EVP_MAC_init(loopargs[i].mctx, key32, 16, params)) + goto end; + } for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_GHASH], c[D_GHASH][testnum], - lengths[testnum], seconds.sym); + print_message(names[D_GHASH], c[D_GHASH][testnum], lengths[testnum], + seconds.sym); Time_F(START); - count = run_benchmark(async_jobs, CRYPTO_gcm128_aad_loop, loopargs); + count = run_benchmark(async_jobs, GHASH_loop, loopargs); d = Time_F(STOP); print_result(D_GHASH, testnum, count, d); + if (count < 0) + break; } for (i = 0; i < loopargs_len; i++) - CRYPTO_gcm128_release(loopargs[i].gcm_ctx); - } -#ifndef OPENSSL_NO_CAMELLIA - if (doit[D_CBC_128_CML]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_128_CML]); - doit[D_CBC_128_CML] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_128_CML], c[D_CBC_128_CML][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - for (count = 0; COND(c[D_CBC_128_CML][testnum]); count++) - Camellia_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &camellia_ks1, - iv, CAMELLIA_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_128_CML, testnum, count, d); - } - } - if (doit[D_CBC_192_CML]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_192_CML]); - doit[D_CBC_192_CML] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_192_CML], c[D_CBC_192_CML][testnum], - lengths[testnum], seconds.sym); - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported, exiting..."); - exit(1); - } - Time_F(START); - for (count = 0; COND(c[D_CBC_192_CML][testnum]); count++) - Camellia_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &camellia_ks2, - iv, CAMELLIA_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_192_CML, testnum, count, d); - } - } - if (doit[D_CBC_256_CML]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_256_CML]); - doit[D_CBC_256_CML] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_256_CML], c[D_CBC_256_CML][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - for (count = 0; COND(c[D_CBC_256_CML][testnum]); count++) - Camellia_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &camellia_ks3, - iv, CAMELLIA_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_256_CML, testnum, count, d); - } - } -#endif -#ifndef OPENSSL_NO_IDEA - if (doit[D_CBC_IDEA]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_IDEA]); - doit[D_CBC_IDEA] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_IDEA], c[D_CBC_IDEA][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - for (count = 0; COND(c[D_CBC_IDEA][testnum]); count++) - IDEA_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &idea_ks, - iv, IDEA_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_IDEA, testnum, count, d); - } - } -#endif -#ifndef OPENSSL_NO_SEED - if (doit[D_CBC_SEED]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_SEED]); - doit[D_CBC_SEED] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_SEED], c[D_CBC_SEED][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - for (count = 0; COND(c[D_CBC_SEED][testnum]); count++) - SEED_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &seed_ks, iv, 1); - d = Time_F(STOP); - print_result(D_CBC_SEED, testnum, count, d); - } - } -#endif -#ifndef OPENSSL_NO_RC2 - if (doit[D_CBC_RC2]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_RC2]); - doit[D_CBC_RC2] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_RC2], c[D_CBC_RC2][testnum], - lengths[testnum], seconds.sym); - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported, exiting..."); - exit(1); - } - Time_F(START); - for (count = 0; COND(c[D_CBC_RC2][testnum]); count++) - RC2_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &rc2_ks, - iv, RC2_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_RC2, testnum, count, d); - } - } -#endif -#ifndef OPENSSL_NO_RC5 - if (doit[D_CBC_RC5]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_RC5]); - doit[D_CBC_RC5] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_RC5], c[D_CBC_RC5][testnum], - lengths[testnum], seconds.sym); - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported, exiting..."); - exit(1); - } - Time_F(START); - for (count = 0; COND(c[D_CBC_RC5][testnum]); count++) - RC5_32_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &rc5_ks, - iv, RC5_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_RC5, testnum, count, d); - } - } -#endif -#ifndef OPENSSL_NO_BF - if (doit[D_CBC_BF]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_BF]); - doit[D_CBC_BF] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_BF], c[D_CBC_BF][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - for (count = 0; COND(c[D_CBC_BF][testnum]); count++) - BF_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &bf_ks, - iv, BF_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_BF, testnum, count, d); - } + EVP_MAC_CTX_free(loopargs[i].mctx); + EVP_MAC_free(mac); + mac = NULL; } -#endif -#ifndef OPENSSL_NO_CAST - if (doit[D_CBC_CAST]) { - if (async_jobs > 0) { - BIO_printf(bio_err, "Async mode is not supported with %s\n", - names[D_CBC_CAST]); - doit[D_CBC_CAST] = 0; - } - for (testnum = 0; testnum < size_num && async_init == 0; testnum++) { - print_message(names[D_CBC_CAST], c[D_CBC_CAST][testnum], - lengths[testnum], seconds.sym); - Time_F(START); - for (count = 0; COND(c[D_CBC_CAST][testnum]); count++) - CAST_cbc_encrypt(loopargs[0].buf, loopargs[0].buf, - (size_t)lengths[testnum], &cast_ks, - iv, CAST_ENCRYPT); - d = Time_F(STOP); - print_result(D_CBC_CAST, testnum, count, d); - } - } -#endif + if (doit[D_RAND]) { for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_RAND], c[D_RAND][testnum], lengths[testnum], @@ -2603,20 +2197,20 @@ int speed_main(int argc, char **argv) if (doit[D_EVP]) { if (evp_cipher != NULL) { - int (*loopfunc)(void *args) = EVP_Update_loop; + int (*loopfunc) (void *) = EVP_Update_loop; - if (multiblock && (EVP_CIPHER_flags(evp_cipher) & + if (multiblock && (EVP_CIPHER_get_flags(evp_cipher) & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { multiblock_speed(evp_cipher, lengths_single, &seconds); ret = 0; goto end; } - names[D_EVP] = OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher)); + names[D_EVP] = EVP_CIPHER_get0_name(evp_cipher); - if (EVP_CIPHER_mode(evp_cipher) == EVP_CIPH_CCM_MODE) { + if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_CCM_MODE) { loopfunc = EVP_Update_loop_ccm; - } else if (aead && (EVP_CIPHER_flags(evp_cipher) & + } else if (aead && (EVP_CIPHER_get_flags(evp_cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) { loopfunc = EVP_Update_loop_aead; if (lengths == lengths_list) { @@ -2626,7 +2220,7 @@ int speed_main(int argc, char **argv) } for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_EVP], save_count, lengths[testnum], + print_message(names[D_EVP], c[D_EVP][testnum], lengths[testnum], seconds.sym); for (k = 0; k < loopargs_len; k++) { @@ -2644,7 +2238,7 @@ int speed_main(int argc, char **argv) EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0); - keylen = EVP_CIPHER_CTX_key_length(loopargs[k].ctx); + keylen = EVP_CIPHER_CTX_get_key_length(loopargs[k].ctx); loopargs[k].key = app_malloc(keylen, "evp_cipher key"); EVP_CIPHER_CTX_rand_key(loopargs[k].ctx, loopargs[k].key); if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, @@ -2654,81 +2248,139 @@ int speed_main(int argc, char **argv) exit(1); } OPENSSL_clear_free(loopargs[k].key, keylen); + + /* SIV mode only allows for a single Update operation */ + if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_SIV_MODE) + (void)EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, + EVP_CTRL_SET_SPEED, 1, NULL); } Time_F(START); count = run_benchmark(async_jobs, loopfunc, loopargs); d = Time_F(STOP); - for (k = 0; k < loopargs_len; k++) { + for (k = 0; k < loopargs_len; k++) EVP_CIPHER_CTX_free(loopargs[k].ctx); - } print_result(D_EVP, testnum, count, d); } - } else if (evp_md != NULL) { - names[D_EVP] = OBJ_nid2ln(EVP_MD_type(evp_md)); + } else if (evp_md_name != NULL) { + names[D_EVP] = evp_md_name; for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_EVP], save_count, lengths[testnum], + print_message(names[D_EVP], c[D_EVP][testnum], lengths[testnum], seconds.sym); Time_F(START); - count = run_benchmark(async_jobs, EVP_Digest_loop, loopargs); + count = run_benchmark(async_jobs, EVP_Digest_md_loop, loopargs); d = Time_F(STOP); print_result(D_EVP, testnum, count, d); + if (count < 0) + break; } } } + if (doit[D_EVP_CMAC]) { + OSSL_PARAM params[3]; + EVP_CIPHER *cipher = NULL; + + mac = EVP_MAC_fetch(app_get0_libctx(), "CMAC", app_get0_propq()); + if (mac == NULL || evp_mac_ciphername == NULL) + goto end; + if (!opt_cipher(evp_mac_ciphername, &cipher)) + goto end; + + keylen = EVP_CIPHER_get_key_length(cipher); + EVP_CIPHER_free(cipher); + if (keylen <= 0 || keylen > (int)sizeof(key32)) { + BIO_printf(bio_err, "\nRequested CMAC cipher with unsupported key length.\n"); + goto end; + } + evp_cmac_name = app_malloc(sizeof("cmac()") + + strlen(evp_mac_ciphername), "CMAC name"); + sprintf(evp_cmac_name, "cmac(%s)", evp_mac_ciphername); + names[D_EVP_CMAC] = evp_cmac_name; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_CIPHER, + evp_mac_ciphername, 0); + params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + (char *)key32, keylen); + params[2] = OSSL_PARAM_construct_end(); + + for (i = 0; i < loopargs_len; i++) { + loopargs[i].mctx = EVP_MAC_CTX_new(mac); + if (loopargs[i].mctx == NULL) + goto end; + + if (!EVP_MAC_CTX_set_params(loopargs[i].mctx, params)) + goto end; + } + + for (testnum = 0; testnum < size_num; testnum++) { + print_message(names[D_EVP_CMAC], c[D_EVP_CMAC][testnum], + lengths[testnum], seconds.sym); + Time_F(START); + count = run_benchmark(async_jobs, CMAC_loop, loopargs); + d = Time_F(STOP); + print_result(D_EVP_CMAC, testnum, count, d); + if (count < 0) + break; + } + for (i = 0; i < loopargs_len; i++) + EVP_MAC_CTX_free(loopargs[i].mctx); + EVP_MAC_free(mac); + mac = NULL; + } + for (i = 0; i < loopargs_len; i++) if (RAND_bytes(loopargs[i].buf, 36) <= 0) goto end; -#ifndef OPENSSL_NO_RSA for (testnum = 0; testnum < RSA_NUM; testnum++) { + EVP_PKEY *rsa_key = NULL; int st = 0; + if (!rsa_doit[testnum]) continue; - for (i = 0; i < loopargs_len; i++) { - if (primes > 2) { - /* we haven't set keys yet, generate multi-prime RSA keys */ - BIGNUM *bn = BN_new(); - - if (bn == NULL) - goto end; - if (!BN_set_word(bn, RSA_F4)) { - BN_free(bn); - goto end; - } - BIO_printf(bio_err, "Generate multi-prime RSA key for %s\n", - rsa_choices[testnum].name); + if (primes > RSA_DEFAULT_PRIME_NUM) { + /* we haven't set keys yet, generate multi-prime RSA keys */ + bn = BN_new(); + st = bn != NULL + && BN_set_word(bn, RSA_F4) + && init_gen_str(&genctx, "RSA", NULL, 0, NULL, NULL) + && EVP_PKEY_CTX_set_rsa_keygen_bits(genctx, rsa_keys[testnum].bits) > 0 + && EVP_PKEY_CTX_set1_rsa_keygen_pubexp(genctx, bn) > 0 + && EVP_PKEY_CTX_set_rsa_keygen_primes(genctx, primes) > 0 + && EVP_PKEY_keygen(genctx, &rsa_key); + BN_free(bn); + bn = NULL; + EVP_PKEY_CTX_free(genctx); + genctx = NULL; + } else { + const unsigned char *p = rsa_keys[testnum].data; - loopargs[i].rsa_key[testnum] = RSA_new(); - if (loopargs[i].rsa_key[testnum] == NULL) { - BN_free(bn); - goto end; - } + st = (rsa_key = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &p, + rsa_keys[testnum].length)) != NULL; + } - if (!RSA_generate_multi_prime_key(loopargs[i].rsa_key[testnum], - rsa_bits[testnum], - primes, bn, NULL)) { - BN_free(bn); - goto end; - } - BN_free(bn); - } - st = RSA_sign(NID_md5_sha1, loopargs[i].buf, 36, loopargs[i].buf2, - &loopargs[i].siglen, loopargs[i].rsa_key[testnum]); - if (st == 0) - break; + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].rsa_sign_ctx[testnum] = EVP_PKEY_CTX_new(rsa_key, NULL); + loopargs[i].sigsize = loopargs[i].buflen; + if (loopargs[i].rsa_sign_ctx[testnum] == NULL + || EVP_PKEY_sign_init(loopargs[i].rsa_sign_ctx[testnum]) <= 0 + || EVP_PKEY_sign(loopargs[i].rsa_sign_ctx[testnum], + loopargs[i].buf2, + &loopargs[i].sigsize, + loopargs[i].buf, 36) <= 0) + st = 0; } - if (st == 0) { + if (!st) { BIO_printf(bio_err, - "RSA sign failure. No RSA sign will be done.\n"); + "RSA sign setup failure. No RSA sign will be done.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; } else { pkey_print_message("private", "rsa", - rsa_c[testnum][0], rsa_bits[testnum], + rsa_c[testnum][0], rsa_keys[testnum].bits, seconds.rsa); /* RSA_blinding_on(rsa_key[testnum],NULL); */ Time_F(START); @@ -2737,25 +2389,30 @@ int speed_main(int argc, char **argv) BIO_printf(bio_err, mr ? "+R1:%ld:%d:%.2f\n" : "%ld %u bits private RSA's in %.2fs\n", - count, rsa_bits[testnum], d); + count, rsa_keys[testnum].bits, d); rsa_results[testnum][0] = (double)count / d; - rsa_count = count; - } - - for (i = 0; i < loopargs_len; i++) { - st = RSA_verify(NID_md5_sha1, loopargs[i].buf, 36, loopargs[i].buf2, - loopargs[i].siglen, loopargs[i].rsa_key[testnum]); - if (st <= 0) - break; + op_count = count; + } + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].rsa_verify_ctx[testnum] = EVP_PKEY_CTX_new(rsa_key, + NULL); + if (loopargs[i].rsa_verify_ctx[testnum] == NULL + || EVP_PKEY_verify_init(loopargs[i].rsa_verify_ctx[testnum]) <= 0 + || EVP_PKEY_verify(loopargs[i].rsa_verify_ctx[testnum], + loopargs[i].buf2, + loopargs[i].sigsize, + loopargs[i].buf, 36) <= 0) + st = 0; } - if (st <= 0) { + if (!st) { BIO_printf(bio_err, - "RSA verify failure. No RSA verify will be done.\n"); + "RSA verify setup failure. No RSA verify will be done.\n"); ERR_print_errors(bio_err); rsa_doit[testnum] = 0; } else { pkey_print_message("public", "rsa", - rsa_c[testnum][1], rsa_bits[testnum], + rsa_c[testnum][1], rsa_keys[testnum].bits, seconds.rsa); Time_F(START); count = run_benchmark(async_jobs, RSA_verify_loop, loopargs); @@ -2763,41 +2420,44 @@ int speed_main(int argc, char **argv) BIO_printf(bio_err, mr ? "+R2:%ld:%d:%.2f\n" : "%ld %u bits public RSA's in %.2fs\n", - count, rsa_bits[testnum], d); + count, rsa_keys[testnum].bits, d); rsa_results[testnum][1] = (double)count / d; } - if (rsa_count <= 1) { + if (op_count <= 1) { /* if longer than 10s, don't do any more */ - for (testnum++; testnum < RSA_NUM; testnum++) - rsa_doit[testnum] = 0; + stop_it(rsa_doit, testnum); } + EVP_PKEY_free(rsa_key); } -#endif /* OPENSSL_NO_RSA */ - - for (i = 0; i < loopargs_len; i++) - if (RAND_bytes(loopargs[i].buf, 36) <= 0) - goto end; -#ifndef OPENSSL_NO_DSA for (testnum = 0; testnum < DSA_NUM; testnum++) { - int st = 0; + EVP_PKEY *dsa_key = NULL; + int st; + if (!dsa_doit[testnum]) continue; - /* DSA_generate_key(dsa_key[testnum]); */ - /* DSA_sign_setup(dsa_key[testnum],NULL); */ - for (i = 0; i < loopargs_len; i++) { - st = DSA_sign(0, loopargs[i].buf, 20, loopargs[i].buf2, - &loopargs[i].siglen, loopargs[i].dsa_key[testnum]); - if (st == 0) - break; + st = (dsa_key = get_dsa(dsa_bits[testnum])) != NULL; + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].dsa_sign_ctx[testnum] = EVP_PKEY_CTX_new(dsa_key, + NULL); + loopargs[i].sigsize = loopargs[i].buflen; + if (loopargs[i].dsa_sign_ctx[testnum] == NULL + || EVP_PKEY_sign_init(loopargs[i].dsa_sign_ctx[testnum]) <= 0 + + || EVP_PKEY_sign(loopargs[i].dsa_sign_ctx[testnum], + loopargs[i].buf2, + &loopargs[i].sigsize, + loopargs[i].buf, 20) <= 0) + st = 0; } - if (st == 0) { + if (!st) { BIO_printf(bio_err, - "DSA sign failure. No DSA sign will be done.\n"); + "DSA sign setup failure. No DSA sign will be done.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; } else { pkey_print_message("sign", "dsa", dsa_c[testnum][0], dsa_bits[testnum], @@ -2810,18 +2470,23 @@ int speed_main(int argc, char **argv) : "%ld %u bits DSA signs in %.2fs\n", count, dsa_bits[testnum], d); dsa_results[testnum][0] = (double)count / d; - rsa_count = count; - } - - for (i = 0; i < loopargs_len; i++) { - st = DSA_verify(0, loopargs[i].buf, 20, loopargs[i].buf2, - loopargs[i].siglen, loopargs[i].dsa_key[testnum]); - if (st <= 0) - break; + op_count = count; + } + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].dsa_verify_ctx[testnum] = EVP_PKEY_CTX_new(dsa_key, + NULL); + if (loopargs[i].dsa_verify_ctx[testnum] == NULL + || EVP_PKEY_verify_init(loopargs[i].dsa_verify_ctx[testnum]) <= 0 + || EVP_PKEY_verify(loopargs[i].dsa_verify_ctx[testnum], + loopargs[i].buf2, + loopargs[i].sigsize, + loopargs[i].buf, 36) <= 0) + st = 0; } - if (st <= 0) { + if (!st) { BIO_printf(bio_err, - "DSA verify failure. No DSA verify will be done.\n"); + "DSA verify setup failure. No DSA verify will be done.\n"); ERR_print_errors(bio_err); dsa_doit[testnum] = 0; } else { @@ -2838,96 +2503,88 @@ int speed_main(int argc, char **argv) dsa_results[testnum][1] = (double)count / d; } - if (rsa_count <= 1) { + if (op_count <= 1) { /* if longer than 10s, don't do any more */ - for (testnum++; testnum < DSA_NUM; testnum++) - dsa_doit[testnum] = 0; + stop_it(dsa_doit, testnum); } + EVP_PKEY_free(dsa_key); } -#endif /* OPENSSL_NO_DSA */ -#ifndef OPENSSL_NO_EC for (testnum = 0; testnum < ECDSA_NUM; testnum++) { - int st = 1; + EVP_PKEY *ecdsa_key = NULL; + int st; if (!ecdsa_doit[testnum]) - continue; /* Ignore Curve */ - for (i = 0; i < loopargs_len; i++) { - loopargs[i].ecdsa[testnum] = - EC_KEY_new_by_curve_name(test_curves[testnum].nid); - if (loopargs[i].ecdsa[testnum] == NULL) { + continue; + + st = (ecdsa_key = get_ecdsa(&ec_curves[testnum])) != NULL; + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ecdsa_sign_ctx[testnum] = EVP_PKEY_CTX_new(ecdsa_key, + NULL); + loopargs[i].sigsize = loopargs[i].buflen; + if (loopargs[i].ecdsa_sign_ctx[testnum] == NULL + || EVP_PKEY_sign_init(loopargs[i].ecdsa_sign_ctx[testnum]) <= 0 + + || EVP_PKEY_sign(loopargs[i].ecdsa_sign_ctx[testnum], + loopargs[i].buf2, + &loopargs[i].sigsize, + loopargs[i].buf, 20) <= 0) st = 0; - break; - } } - if (st == 0) { - BIO_printf(bio_err, "ECDSA failure.\n"); + if (!st) { + BIO_printf(bio_err, + "ECDSA sign setup failure. No ECDSA sign will be done.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; } else { - for (i = 0; i < loopargs_len; i++) { - EC_KEY_precompute_mult(loopargs[i].ecdsa[testnum], NULL); - /* Perform ECDSA signature test */ - EC_KEY_generate_key(loopargs[i].ecdsa[testnum]); - st = ECDSA_sign(0, loopargs[i].buf, 20, loopargs[i].buf2, - &loopargs[i].siglen, - loopargs[i].ecdsa[testnum]); - if (st == 0) - break; - } - if (st == 0) { - BIO_printf(bio_err, - "ECDSA sign failure. No ECDSA sign will be done.\n"); - ERR_print_errors(bio_err); - rsa_count = 1; - } else { - pkey_print_message("sign", "ecdsa", - ecdsa_c[testnum][0], - test_curves[testnum].bits, seconds.ecdsa); - Time_F(START); - count = run_benchmark(async_jobs, ECDSA_sign_loop, loopargs); - d = Time_F(STOP); - - BIO_printf(bio_err, - mr ? "+R5:%ld:%u:%.2f\n" : - "%ld %u bits ECDSA signs in %.2fs \n", - count, test_curves[testnum].bits, d); - ecdsa_results[testnum][0] = (double)count / d; - rsa_count = count; - } - - /* Perform ECDSA verification test */ - for (i = 0; i < loopargs_len; i++) { - st = ECDSA_verify(0, loopargs[i].buf, 20, loopargs[i].buf2, - loopargs[i].siglen, - loopargs[i].ecdsa[testnum]); - if (st != 1) - break; - } - if (st != 1) { - BIO_printf(bio_err, - "ECDSA verify failure. No ECDSA verify will be done.\n"); - ERR_print_errors(bio_err); - ecdsa_doit[testnum] = 0; - } else { - pkey_print_message("verify", "ecdsa", - ecdsa_c[testnum][1], - test_curves[testnum].bits, seconds.ecdsa); - Time_F(START); - count = run_benchmark(async_jobs, ECDSA_verify_loop, loopargs); - d = Time_F(STOP); - BIO_printf(bio_err, - mr ? "+R6:%ld:%u:%.2f\n" - : "%ld %u bits ECDSA verify in %.2fs\n", - count, test_curves[testnum].bits, d); - ecdsa_results[testnum][1] = (double)count / d; - } + pkey_print_message("sign", "ecdsa", + ecdsa_c[testnum][0], ec_curves[testnum].bits, + seconds.ecdsa); + Time_F(START); + count = run_benchmark(async_jobs, ECDSA_sign_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R5:%ld:%u:%.2f\n" + : "%ld %u bits ECDSA signs in %.2fs\n", + count, ec_curves[testnum].bits, d); + ecdsa_results[testnum][0] = (double)count / d; + op_count = count; + } + + for (i = 0; st && i < loopargs_len; i++) { + loopargs[i].ecdsa_verify_ctx[testnum] = EVP_PKEY_CTX_new(ecdsa_key, + NULL); + if (loopargs[i].ecdsa_verify_ctx[testnum] == NULL + || EVP_PKEY_verify_init(loopargs[i].ecdsa_verify_ctx[testnum]) <= 0 + || EVP_PKEY_verify(loopargs[i].ecdsa_verify_ctx[testnum], + loopargs[i].buf2, + loopargs[i].sigsize, + loopargs[i].buf, 20) <= 0) + st = 0; + } + if (!st) { + BIO_printf(bio_err, + "ECDSA verify setup failure. No ECDSA verify will be done.\n"); + ERR_print_errors(bio_err); + ecdsa_doit[testnum] = 0; + } else { + pkey_print_message("verify", "ecdsa", + ecdsa_c[testnum][1], ec_curves[testnum].bits, + seconds.ecdsa); + Time_F(START); + count = run_benchmark(async_jobs, ECDSA_verify_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R6:%ld:%u:%.2f\n" + : "%ld %u bits ECDSA verify in %.2fs\n", + count, ec_curves[testnum].bits, d); + ecdsa_results[testnum][1] = (double)count / d; + } - if (rsa_count <= 1) { - /* if longer than 10s, don't do any more */ - for (testnum++; testnum < ECDSA_NUM; testnum++) - ecdsa_doit[testnum] = 0; - } + if (op_count <= 1) { + /* if longer than 10s, don't do any more */ + stop_it(ecdsa_doit, testnum); } } @@ -2938,7 +2595,6 @@ int speed_main(int argc, char **argv) continue; for (i = 0; i < loopargs_len; i++) { - EVP_PKEY_CTX *kctx = NULL; EVP_PKEY_CTX *test_ctx = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *key_A = NULL; @@ -2946,106 +2602,38 @@ int speed_main(int argc, char **argv) size_t outlen; size_t test_outlen; - /* Ensure that the error queue is empty */ - if (ERR_peek_error()) { - BIO_printf(bio_err, - "WARNING: the error queue contains previous unhandled errors.\n"); - ERR_print_errors(bio_err); - } - - /* Let's try to create a ctx directly from the NID: this works for - * curves like Curve25519 that are not implemented through the low - * level EC interface. - * If this fails we try creating a EVP_PKEY_EC generic param ctx, - * then we set the curve by NID before deriving the actual keygen - * ctx for that specific curve. */ - kctx = EVP_PKEY_CTX_new_id(test_curves[testnum].nid, NULL); /* keygen ctx from NID */ - if (!kctx) { - EVP_PKEY_CTX *pctx = NULL; - EVP_PKEY *params = NULL; - - /* If we reach this code EVP_PKEY_CTX_new_id() failed and a - * "int_ctx_new:unsupported algorithm" error was added to the - * error queue. - * We remove it from the error queue as we are handling it. */ - unsigned long error = ERR_peek_error(); /* peek the latest error in the queue */ - if (error == ERR_peek_last_error() && /* oldest and latest errors match */ - /* check that the error origin matches */ - ERR_GET_LIB(error) == ERR_LIB_EVP && - ERR_GET_FUNC(error) == EVP_F_INT_CTX_NEW && - ERR_GET_REASON(error) == EVP_R_UNSUPPORTED_ALGORITHM) - ERR_get_error(); /* pop error from queue */ - if (ERR_peek_error()) { - BIO_printf(bio_err, - "Unhandled error in the error queue during ECDH init.\n"); - ERR_print_errors(bio_err); - rsa_count = 1; - break; - } - - if ( /* Create the context for parameter generation */ - !(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) || - /* Initialise the parameter generation */ - !EVP_PKEY_paramgen_init(pctx) || - /* Set the curve by NID */ - !EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, - test_curves - [testnum].nid) || - /* Create the parameter object params */ - !EVP_PKEY_paramgen(pctx, ¶ms)) { - ecdh_checks = 0; - BIO_printf(bio_err, "ECDH EC params init failure.\n"); - ERR_print_errors(bio_err); - rsa_count = 1; - break; - } - /* Create the context for the key generation */ - kctx = EVP_PKEY_CTX_new(params, NULL); - - EVP_PKEY_free(params); - params = NULL; - EVP_PKEY_CTX_free(pctx); - pctx = NULL; - } - if (kctx == NULL || /* keygen ctx is not null */ - EVP_PKEY_keygen_init(kctx) <= 0/* init keygen ctx */ ) { - ecdh_checks = 0; - BIO_printf(bio_err, "ECDH keygen failure.\n"); - ERR_print_errors(bio_err); - rsa_count = 1; - break; - } - - if (EVP_PKEY_keygen(kctx, &key_A) <= 0 || /* generate secret key A */ - EVP_PKEY_keygen(kctx, &key_B) <= 0 || /* generate secret key B */ - !(ctx = EVP_PKEY_CTX_new(key_A, NULL)) || /* derivation ctx from skeyA */ - EVP_PKEY_derive_init(ctx) <= 0 || /* init derivation ctx */ - EVP_PKEY_derive_set_peer(ctx, key_B) <= 0 || /* set peer pubkey in ctx */ - EVP_PKEY_derive(ctx, NULL, &outlen) <= 0 || /* determine max length */ - outlen == 0 || /* ensure outlen is a valid size */ - outlen > MAX_ECDH_SIZE /* avoid buffer overflow */ ) { + if ((key_A = get_ecdsa(&ec_curves[testnum])) == NULL /* generate secret key A */ + || (key_B = get_ecdsa(&ec_curves[testnum])) == NULL /* generate secret key B */ + || (ctx = EVP_PKEY_CTX_new(key_A, NULL)) == NULL /* derivation ctx from skeyA */ + || EVP_PKEY_derive_init(ctx) <= 0 /* init derivation ctx */ + || EVP_PKEY_derive_set_peer(ctx, key_B) <= 0 /* set peer pubkey in ctx */ + || EVP_PKEY_derive(ctx, NULL, &outlen) <= 0 /* determine max length */ + || outlen == 0 /* ensure outlen is a valid size */ + || outlen > MAX_ECDH_SIZE /* avoid buffer overflow */) { ecdh_checks = 0; BIO_printf(bio_err, "ECDH key generation failure.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; break; } - /* Here we perform a test run, comparing the output of a*B and b*A; + /* + * Here we perform a test run, comparing the output of a*B and b*A; * we try this here and assume that further EVP_PKEY_derive calls * never fail, so we can skip checks in the actually benchmarked - * code, for maximum performance. */ - if (!(test_ctx = EVP_PKEY_CTX_new(key_B, NULL)) || /* test ctx from skeyB */ - !EVP_PKEY_derive_init(test_ctx) || /* init derivation test_ctx */ - !EVP_PKEY_derive_set_peer(test_ctx, key_A) || /* set peer pubkey in test_ctx */ - !EVP_PKEY_derive(test_ctx, NULL, &test_outlen) || /* determine max length */ - !EVP_PKEY_derive(ctx, loopargs[i].secret_a, &outlen) || /* compute a*B */ - !EVP_PKEY_derive(test_ctx, loopargs[i].secret_b, &test_outlen) || /* compute b*A */ - test_outlen != outlen /* compare output length */ ) { + * code, for maximum performance. + */ + if ((test_ctx = EVP_PKEY_CTX_new(key_B, NULL)) == NULL /* test ctx from skeyB */ + || EVP_PKEY_derive_init(test_ctx) <= 0 /* init derivation test_ctx */ + || EVP_PKEY_derive_set_peer(test_ctx, key_A) <= 0 /* set peer pubkey in test_ctx */ + || EVP_PKEY_derive(test_ctx, NULL, &test_outlen) <= 0 /* determine max length */ + || EVP_PKEY_derive(ctx, loopargs[i].secret_a, &outlen) <= 0 /* compute a*B */ + || EVP_PKEY_derive(test_ctx, loopargs[i].secret_b, &test_outlen) <= 0 /* compute b*A */ + || test_outlen != outlen /* compare output length */) { ecdh_checks = 0; BIO_printf(bio_err, "ECDH computation failure.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; break; } @@ -3055,7 +2643,7 @@ int speed_main(int argc, char **argv) ecdh_checks = 0; BIO_printf(bio_err, "ECDH computations don't match.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; break; } @@ -3064,15 +2652,13 @@ int speed_main(int argc, char **argv) EVP_PKEY_free(key_A); EVP_PKEY_free(key_B); - EVP_PKEY_CTX_free(kctx); - kctx = NULL; EVP_PKEY_CTX_free(test_ctx); test_ctx = NULL; } if (ecdh_checks != 0) { pkey_print_message("", "ecdh", ecdh_c[testnum][0], - test_curves[testnum].bits, seconds.ecdh); + ec_curves[testnum].bits, seconds.ecdh); Time_F(START); count = run_benchmark(async_jobs, ECDH_EVP_derive_key_loop, loopargs); @@ -3080,15 +2666,14 @@ int speed_main(int argc, char **argv) BIO_printf(bio_err, mr ? "+R7:%ld:%d:%.2f\n" : "%ld %u-bits ECDH ops in %.2fs\n", count, - test_curves[testnum].bits, d); + ec_curves[testnum].bits, d); ecdh_results[testnum][0] = (double)count / d; - rsa_count = count; + op_count = count; } - if (rsa_count <= 1) { + if (op_count <= 1) { /* if longer than 10s, don't do any more */ - for (testnum++; testnum < OSSL_NELEM(ecdh_doit); testnum++) - ecdh_doit[testnum] = 0; + stop_it(ecdh_doit, testnum); } } @@ -3105,9 +2690,14 @@ int speed_main(int argc, char **argv) st = 0; break; } + loopargs[i].eddsa_ctx2[testnum] = EVP_MD_CTX_new(); + if (loopargs[i].eddsa_ctx2[testnum] == NULL) { + st = 0; + break; + } - if ((ed_pctx = EVP_PKEY_CTX_new_id(test_ed_curves[testnum].nid, NULL)) - == NULL + if ((ed_pctx = EVP_PKEY_CTX_new_id(ed_curves[testnum].nid, + NULL)) == NULL || EVP_PKEY_keygen_init(ed_pctx) <= 0 || EVP_PKEY_keygen(ed_pctx, &ed_pkey) <= 0) { st = 0; @@ -3122,16 +2712,24 @@ int speed_main(int argc, char **argv) EVP_PKEY_free(ed_pkey); break; } + if (!EVP_DigestVerifyInit(loopargs[i].eddsa_ctx2[testnum], NULL, + NULL, NULL, ed_pkey)) { + st = 0; + EVP_PKEY_free(ed_pkey); + break; + } + EVP_PKEY_free(ed_pkey); + ed_pkey = NULL; } if (st == 0) { BIO_printf(bio_err, "EdDSA failure.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; } else { for (i = 0; i < loopargs_len; i++) { /* Perform EdDSA signature test */ - loopargs[i].sigsize = test_ed_curves[testnum].sigsize; + loopargs[i].sigsize = ed_curves[testnum].sigsize; st = EVP_DigestSign(loopargs[i].eddsa_ctx[testnum], loopargs[i].buf2, &loopargs[i].sigsize, loopargs[i].buf, 20); @@ -3142,11 +2740,11 @@ int speed_main(int argc, char **argv) BIO_printf(bio_err, "EdDSA sign failure. No EdDSA sign will be done.\n"); ERR_print_errors(bio_err); - rsa_count = 1; + op_count = 1; } else { - pkey_print_message("sign", test_ed_curves[testnum].name, + pkey_print_message("sign", ed_curves[testnum].name, eddsa_c[testnum][0], - test_ed_curves[testnum].bits, seconds.eddsa); + ed_curves[testnum].bits, seconds.eddsa); Time_F(START); count = run_benchmark(async_jobs, EdDSA_sign_loop, loopargs); d = Time_F(STOP); @@ -3154,15 +2752,14 @@ int speed_main(int argc, char **argv) BIO_printf(bio_err, mr ? "+R8:%ld:%u:%s:%.2f\n" : "%ld %u bits %s signs in %.2fs \n", - count, test_ed_curves[testnum].bits, - test_ed_curves[testnum].name, d); + count, ed_curves[testnum].bits, + ed_curves[testnum].name, d); eddsa_results[testnum][0] = (double)count / d; - rsa_count = count; + op_count = count; } - /* Perform EdDSA verification test */ for (i = 0; i < loopargs_len; i++) { - st = EVP_DigestVerify(loopargs[i].eddsa_ctx[testnum], + st = EVP_DigestVerify(loopargs[i].eddsa_ctx2[testnum], loopargs[i].buf2, loopargs[i].sigsize, loopargs[i].buf, 20); if (st != 1) @@ -3174,62 +2771,360 @@ int speed_main(int argc, char **argv) ERR_print_errors(bio_err); eddsa_doit[testnum] = 0; } else { - pkey_print_message("verify", test_ed_curves[testnum].name, + pkey_print_message("verify", ed_curves[testnum].name, eddsa_c[testnum][1], - test_ed_curves[testnum].bits, seconds.eddsa); + ed_curves[testnum].bits, seconds.eddsa); Time_F(START); count = run_benchmark(async_jobs, EdDSA_verify_loop, loopargs); d = Time_F(STOP); BIO_printf(bio_err, mr ? "+R9:%ld:%u:%s:%.2f\n" : "%ld %u bits %s verify in %.2fs\n", - count, test_ed_curves[testnum].bits, - test_ed_curves[testnum].name, d); + count, ed_curves[testnum].bits, + ed_curves[testnum].name, d); eddsa_results[testnum][1] = (double)count / d; } - if (rsa_count <= 1) { + if (op_count <= 1) { + /* if longer than 10s, don't do any more */ + stop_it(eddsa_doit, testnum); + } + } + } + +#ifndef OPENSSL_NO_SM2 + for (testnum = 0; testnum < SM2_NUM; testnum++) { + int st = 1; + EVP_PKEY *sm2_pkey = NULL; + + if (!sm2_doit[testnum]) + continue; /* Ignore Curve */ + /* Init signing and verification */ + for (i = 0; i < loopargs_len; i++) { + EVP_PKEY_CTX *sm2_pctx = NULL; + EVP_PKEY_CTX *sm2_vfy_pctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + st = 0; + + loopargs[i].sm2_ctx[testnum] = EVP_MD_CTX_new(); + loopargs[i].sm2_vfy_ctx[testnum] = EVP_MD_CTX_new(); + if (loopargs[i].sm2_ctx[testnum] == NULL + || loopargs[i].sm2_vfy_ctx[testnum] == NULL) + break; + + sm2_pkey = NULL; + + st = !((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL)) == NULL + || EVP_PKEY_keygen_init(pctx) <= 0 + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, + sm2_curves[testnum].nid) <= 0 + || EVP_PKEY_keygen(pctx, &sm2_pkey) <= 0); + EVP_PKEY_CTX_free(pctx); + if (st == 0) + break; + + st = 0; /* set back to zero */ + /* attach it sooner to rely on main final cleanup */ + loopargs[i].sm2_pkey[testnum] = sm2_pkey; + loopargs[i].sigsize = EVP_PKEY_get_size(sm2_pkey); + + sm2_pctx = EVP_PKEY_CTX_new(sm2_pkey, NULL); + sm2_vfy_pctx = EVP_PKEY_CTX_new(sm2_pkey, NULL); + if (sm2_pctx == NULL || sm2_vfy_pctx == NULL) { + EVP_PKEY_CTX_free(sm2_vfy_pctx); + break; + } + + /* attach them directly to respective ctx */ + EVP_MD_CTX_set_pkey_ctx(loopargs[i].sm2_ctx[testnum], sm2_pctx); + EVP_MD_CTX_set_pkey_ctx(loopargs[i].sm2_vfy_ctx[testnum], sm2_vfy_pctx); + + /* + * No need to allow user to set an explicit ID here, just use + * the one defined in the 'draft-yang-tls-tl13-sm-suites' I-D. + */ + if (EVP_PKEY_CTX_set1_id(sm2_pctx, SM2_ID, SM2_ID_LEN) != 1 + || EVP_PKEY_CTX_set1_id(sm2_vfy_pctx, SM2_ID, SM2_ID_LEN) != 1) + break; + + if (!EVP_DigestSignInit(loopargs[i].sm2_ctx[testnum], NULL, + EVP_sm3(), NULL, sm2_pkey)) + break; + if (!EVP_DigestVerifyInit(loopargs[i].sm2_vfy_ctx[testnum], NULL, + EVP_sm3(), NULL, sm2_pkey)) + break; + st = 1; /* mark loop as succeeded */ + } + if (st == 0) { + BIO_printf(bio_err, "SM2 init failure.\n"); + ERR_print_errors(bio_err); + op_count = 1; + } else { + for (i = 0; i < loopargs_len; i++) { + /* Perform SM2 signature test */ + st = EVP_DigestSign(loopargs[i].sm2_ctx[testnum], + loopargs[i].buf2, &loopargs[i].sigsize, + loopargs[i].buf, 20); + if (st == 0) + break; + } + if (st == 0) { + BIO_printf(bio_err, + "SM2 sign failure. No SM2 sign will be done.\n"); + ERR_print_errors(bio_err); + op_count = 1; + } else { + pkey_print_message("sign", sm2_curves[testnum].name, + sm2_c[testnum][0], + sm2_curves[testnum].bits, seconds.sm2); + Time_F(START); + count = run_benchmark(async_jobs, SM2_sign_loop, loopargs); + d = Time_F(STOP); + + BIO_printf(bio_err, + mr ? "+R10:%ld:%u:%s:%.2f\n" : + "%ld %u bits %s signs in %.2fs \n", + count, sm2_curves[testnum].bits, + sm2_curves[testnum].name, d); + sm2_results[testnum][0] = (double)count / d; + op_count = count; + } + + /* Perform SM2 verification test */ + for (i = 0; i < loopargs_len; i++) { + st = EVP_DigestVerify(loopargs[i].sm2_vfy_ctx[testnum], + loopargs[i].buf2, loopargs[i].sigsize, + loopargs[i].buf, 20); + if (st != 1) + break; + } + if (st != 1) { + BIO_printf(bio_err, + "SM2 verify failure. No SM2 verify will be done.\n"); + ERR_print_errors(bio_err); + sm2_doit[testnum] = 0; + } else { + pkey_print_message("verify", sm2_curves[testnum].name, + sm2_c[testnum][1], + sm2_curves[testnum].bits, seconds.sm2); + Time_F(START); + count = run_benchmark(async_jobs, SM2_verify_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R11:%ld:%u:%s:%.2f\n" + : "%ld %u bits %s verify in %.2fs\n", + count, sm2_curves[testnum].bits, + sm2_curves[testnum].name, d); + sm2_results[testnum][1] = (double)count / d; + } + + if (op_count <= 1) { /* if longer than 10s, don't do any more */ - for (testnum++; testnum < EdDSA_NUM; testnum++) - eddsa_doit[testnum] = 0; + for (testnum++; testnum < SM2_NUM; testnum++) + sm2_doit[testnum] = 0; } } } +#endif /* OPENSSL_NO_SM2 */ + +#ifndef OPENSSL_NO_DH + for (testnum = 0; testnum < FFDH_NUM; testnum++) { + int ffdh_checks = 1; + + if (!ffdh_doit[testnum]) + continue; + + for (i = 0; i < loopargs_len; i++) { + EVP_PKEY *pkey_A = NULL; + EVP_PKEY *pkey_B = NULL; + EVP_PKEY_CTX *ffdh_ctx = NULL; + EVP_PKEY_CTX *test_ctx = NULL; + size_t secret_size; + size_t test_out; + + /* Ensure that the error queue is empty */ + if (ERR_peek_error()) { + BIO_printf(bio_err, + "WARNING: the error queue contains previous unhandled errors.\n"); + ERR_print_errors(bio_err); + } -#endif /* OPENSSL_NO_EC */ + pkey_A = EVP_PKEY_new(); + if (!pkey_A) { + BIO_printf(bio_err, "Error while initialising EVP_PKEY (out of memory?).\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + pkey_B = EVP_PKEY_new(); + if (!pkey_B) { + BIO_printf(bio_err, "Error while initialising EVP_PKEY (out of memory?).\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + + ffdh_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); + if (!ffdh_ctx) { + BIO_printf(bio_err, "Error while allocating EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + + if (EVP_PKEY_keygen_init(ffdh_ctx) <= 0) { + BIO_printf(bio_err, "Error while initialising EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_CTX_set_dh_nid(ffdh_ctx, ffdh_params[testnum].nid) <= 0) { + BIO_printf(bio_err, "Error setting DH key size for keygen.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + + if (EVP_PKEY_keygen(ffdh_ctx, &pkey_A) <= 0 || + EVP_PKEY_keygen(ffdh_ctx, &pkey_B) <= 0) { + BIO_printf(bio_err, "FFDH key generation failure.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + + EVP_PKEY_CTX_free(ffdh_ctx); + + /* + * check if the derivation works correctly both ways so that + * we know if future derive calls will fail, and we can skip + * error checking in benchmarked code + */ + ffdh_ctx = EVP_PKEY_CTX_new(pkey_A, NULL); + if (ffdh_ctx == NULL) { + BIO_printf(bio_err, "Error while allocating EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive_init(ffdh_ctx) <= 0) { + BIO_printf(bio_err, "FFDH derivation context init failure.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive_set_peer(ffdh_ctx, pkey_B) <= 0) { + BIO_printf(bio_err, "Assigning peer key for derivation failed.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive(ffdh_ctx, NULL, &secret_size) <= 0) { + BIO_printf(bio_err, "Checking size of shared secret failed.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + if (secret_size > MAX_FFDH_SIZE) { + BIO_printf(bio_err, "Assertion failure: shared secret too large.\n"); + op_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive(ffdh_ctx, + loopargs[i].secret_ff_a, + &secret_size) <= 0) { + BIO_printf(bio_err, "Shared secret derive failure.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + /* Now check from side B */ + test_ctx = EVP_PKEY_CTX_new(pkey_B, NULL); + if (!test_ctx) { + BIO_printf(bio_err, "Error while allocating EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive_init(test_ctx) <= 0 || + EVP_PKEY_derive_set_peer(test_ctx, pkey_A) <= 0 || + EVP_PKEY_derive(test_ctx, NULL, &test_out) <= 0 || + EVP_PKEY_derive(test_ctx, loopargs[i].secret_ff_b, &test_out) <= 0 || + test_out != secret_size) { + BIO_printf(bio_err, "FFDH computation failure.\n"); + op_count = 1; + ffdh_checks = 0; + break; + } + + /* compare the computed secrets */ + if (CRYPTO_memcmp(loopargs[i].secret_ff_a, + loopargs[i].secret_ff_b, secret_size)) { + BIO_printf(bio_err, "FFDH computations don't match.\n"); + ERR_print_errors(bio_err); + op_count = 1; + ffdh_checks = 0; + break; + } + + loopargs[i].ffdh_ctx[testnum] = ffdh_ctx; + + EVP_PKEY_free(pkey_A); + pkey_A = NULL; + EVP_PKEY_free(pkey_B); + pkey_B = NULL; + EVP_PKEY_CTX_free(test_ctx); + test_ctx = NULL; + } + if (ffdh_checks != 0) { + pkey_print_message("", "ffdh", ffdh_c[testnum][0], + ffdh_params[testnum].bits, seconds.ffdh); + Time_F(START); + count = + run_benchmark(async_jobs, FFDH_derive_key_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R12:%ld:%d:%.2f\n" : + "%ld %u-bits FFDH ops in %.2fs\n", count, + ffdh_params[testnum].bits, d); + ffdh_results[testnum][0] = (double)count / d; + op_count = count; + } + if (op_count <= 1) { + /* if longer than 10s, don't do any more */ + stop_it(ffdh_doit, testnum); + } + } +#endif /* OPENSSL_NO_DH */ #ifndef NO_FORK show_res: #endif if (!mr) { - printf("%s\n", OpenSSL_version(OPENSSL_VERSION)); + printf("version: %s\n", OpenSSL_version(OPENSSL_FULL_VERSION_STRING)); printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON)); - printf("options:"); - printf("%s ", BN_options()); -#ifndef OPENSSL_NO_MD2 - printf("%s ", MD2_options()); -#endif -#ifndef OPENSSL_NO_RC4 - printf("%s ", RC4_options()); -#endif -#ifndef OPENSSL_NO_DES - printf("%s ", DES_options()); -#endif - printf("%s ", AES_options()); -#ifndef OPENSSL_NO_IDEA - printf("%s ", IDEA_options()); -#endif -#ifndef OPENSSL_NO_BF - printf("%s ", BF_options()); -#endif - printf("\n%s\n", OpenSSL_version(OPENSSL_CFLAGS)); + printf("options: %s\n", BN_options()); + printf("%s\n", OpenSSL_version(OPENSSL_CFLAGS)); + printf("%s\n", OpenSSL_version(OPENSSL_CPU_INFO)); } if (pr_header) { - if (mr) + if (mr) { printf("+H"); - else { - printf - ("The 'numbers' are in 1000s of bytes per second processed.\n"); + } else { + printf("The 'numbers' are in 1000s of bytes per second processed.\n"); printf("type "); } for (testnum = 0; testnum < size_num; testnum++) @@ -3252,7 +3147,6 @@ int speed_main(int argc, char **argv) } printf("\n"); } -#ifndef OPENSSL_NO_RSA testnum = 1; for (k = 0; k < RSA_NUM; k++) { if (!rsa_doit[k]) @@ -3263,14 +3157,12 @@ int speed_main(int argc, char **argv) } if (mr) printf("+F2:%u:%u:%f:%f\n", - k, rsa_bits[k], rsa_results[k][0], rsa_results[k][1]); + k, rsa_keys[k].bits, rsa_results[k][0], rsa_results[k][1]); else printf("rsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n", - rsa_bits[k], 1.0 / rsa_results[k][0], 1.0 / rsa_results[k][1], + rsa_keys[k].bits, 1.0 / rsa_results[k][0], 1.0 / rsa_results[k][1], rsa_results[k][0], rsa_results[k][1]); } -#endif -#ifndef OPENSSL_NO_DSA testnum = 1; for (k = 0; k < DSA_NUM; k++) { if (!dsa_doit[k]) @@ -3287,8 +3179,6 @@ int speed_main(int argc, char **argv) dsa_bits[k], 1.0 / dsa_results[k][0], 1.0 / dsa_results[k][1], dsa_results[k][0], dsa_results[k][1]); } -#endif -#ifndef OPENSSL_NO_EC testnum = 1; for (k = 0; k < OSSL_NELEM(ecdsa_doit); k++) { if (!ecdsa_doit[k]) @@ -3300,11 +3190,11 @@ int speed_main(int argc, char **argv) if (mr) printf("+F4:%u:%u:%f:%f\n", - k, test_curves[k].bits, + k, ec_curves[k].bits, ecdsa_results[k][0], ecdsa_results[k][1]); else printf("%4u bits ecdsa (%s) %8.4fs %8.4fs %8.1f %8.1f\n", - test_curves[k].bits, test_curves[k].name, + ec_curves[k].bits, ec_curves[k].name, 1.0 / ecdsa_results[k][0], 1.0 / ecdsa_results[k][1], ecdsa_results[k][0], ecdsa_results[k][1]); } @@ -3319,12 +3209,12 @@ int speed_main(int argc, char **argv) } if (mr) printf("+F5:%u:%u:%f:%f\n", - k, test_curves[k].bits, + k, ec_curves[k].bits, ecdh_results[k][0], 1.0 / ecdh_results[k][0]); else printf("%4u bits ecdh (%s) %8.4fs %8.1f\n", - test_curves[k].bits, test_curves[k].name, + ec_curves[k].bits, ec_curves[k].name, 1.0 / ecdh_results[k][0], ecdh_results[k][0]); } @@ -3339,15 +3229,56 @@ int speed_main(int argc, char **argv) if (mr) printf("+F6:%u:%u:%s:%f:%f\n", - k, test_ed_curves[k].bits, test_ed_curves[k].name, + k, ed_curves[k].bits, ed_curves[k].name, eddsa_results[k][0], eddsa_results[k][1]); else printf("%4u bits EdDSA (%s) %8.4fs %8.4fs %8.1f %8.1f\n", - test_ed_curves[k].bits, test_ed_curves[k].name, + ed_curves[k].bits, ed_curves[k].name, 1.0 / eddsa_results[k][0], 1.0 / eddsa_results[k][1], eddsa_results[k][0], eddsa_results[k][1]); } + +#ifndef OPENSSL_NO_SM2 + testnum = 1; + for (k = 0; k < OSSL_NELEM(sm2_doit); k++) { + if (!sm2_doit[k]) + continue; + if (testnum && !mr) { + printf("%30ssign verify sign/s verify/s\n", " "); + testnum = 0; + } + + if (mr) + printf("+F7:%u:%u:%s:%f:%f\n", + k, sm2_curves[k].bits, sm2_curves[k].name, + sm2_results[k][0], sm2_results[k][1]); + else + printf("%4u bits SM2 (%s) %8.4fs %8.4fs %8.1f %8.1f\n", + sm2_curves[k].bits, sm2_curves[k].name, + 1.0 / sm2_results[k][0], 1.0 / sm2_results[k][1], + sm2_results[k][0], sm2_results[k][1]); + } #endif +#ifndef OPENSSL_NO_DH + testnum = 1; + for (k = 0; k < FFDH_NUM; k++) { + if (!ffdh_doit[k]) + continue; + if (testnum && !mr) { + printf("%23sop op/s\n", " "); + testnum = 0; + } + if (mr) + printf("+F8:%u:%u:%f:%f\n", + k, ffdh_params[k].bits, + ffdh_results[k][0], 1.0 / ffdh_results[k][0]); + + else + printf("%4u bits ffdh %8.4fs %8.1f\n", + ffdh_params[k].bits, + 1.0 / ffdh_results[k][0], ffdh_results[k][0]); + } +#endif /* OPENSSL_NO_DH */ ret = 0; @@ -3357,25 +3288,55 @@ int speed_main(int argc, char **argv) OPENSSL_free(loopargs[i].buf_malloc); OPENSSL_free(loopargs[i].buf2_malloc); -#ifndef OPENSSL_NO_RSA - for (k = 0; k < RSA_NUM; k++) - RSA_free(loopargs[i].rsa_key[k]); -#endif -#ifndef OPENSSL_NO_DSA - for (k = 0; k < DSA_NUM; k++) - DSA_free(loopargs[i].dsa_key[k]); + BN_free(bn); + EVP_PKEY_CTX_free(genctx); + for (k = 0; k < RSA_NUM; k++) { + EVP_PKEY_CTX_free(loopargs[i].rsa_sign_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].rsa_verify_ctx[k]); + } +#ifndef OPENSSL_NO_DH + OPENSSL_free(loopargs[i].secret_ff_a); + OPENSSL_free(loopargs[i].secret_ff_b); + for (k = 0; k < FFDH_NUM; k++) + EVP_PKEY_CTX_free(loopargs[i].ffdh_ctx[k]); #endif -#ifndef OPENSSL_NO_EC - for (k = 0; k < ECDSA_NUM; k++) - EC_KEY_free(loopargs[i].ecdsa[k]); + for (k = 0; k < DSA_NUM; k++) { + EVP_PKEY_CTX_free(loopargs[i].dsa_sign_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].dsa_verify_ctx[k]); + } + for (k = 0; k < ECDSA_NUM; k++) { + EVP_PKEY_CTX_free(loopargs[i].ecdsa_sign_ctx[k]); + EVP_PKEY_CTX_free(loopargs[i].ecdsa_verify_ctx[k]); + } for (k = 0; k < EC_NUM; k++) EVP_PKEY_CTX_free(loopargs[i].ecdh_ctx[k]); - for (k = 0; k < EdDSA_NUM; k++) + for (k = 0; k < EdDSA_NUM; k++) { EVP_MD_CTX_free(loopargs[i].eddsa_ctx[k]); + EVP_MD_CTX_free(loopargs[i].eddsa_ctx2[k]); + } +#ifndef OPENSSL_NO_SM2 + for (k = 0; k < SM2_NUM; k++) { + EVP_PKEY_CTX *pctx = NULL; + + /* free signing ctx */ + if (loopargs[i].sm2_ctx[k] != NULL + && (pctx = EVP_MD_CTX_get_pkey_ctx(loopargs[i].sm2_ctx[k])) != NULL) + EVP_PKEY_CTX_free(pctx); + EVP_MD_CTX_free(loopargs[i].sm2_ctx[k]); + /* free verification ctx */ + if (loopargs[i].sm2_vfy_ctx[k] != NULL + && (pctx = EVP_MD_CTX_get_pkey_ctx(loopargs[i].sm2_vfy_ctx[k])) != NULL) + EVP_PKEY_CTX_free(pctx); + EVP_MD_CTX_free(loopargs[i].sm2_vfy_ctx[k]); + /* free pkey */ + EVP_PKEY_free(loopargs[i].sm2_pkey[k]); + } +#endif OPENSSL_free(loopargs[i].secret_a); OPENSSL_free(loopargs[i].secret_b); -#endif } + OPENSSL_free(evp_hmac_name); + OPENSSL_free(evp_cmac_name); if (async_jobs > 0) { for (i = 0; i < loopargs_len; i++) @@ -3387,49 +3348,38 @@ int speed_main(int argc, char **argv) } OPENSSL_free(loopargs); release_engine(e); + EVP_CIPHER_free(evp_cipher); + EVP_MAC_free(mac); return ret; } static void print_message(const char *s, long num, int length, int tm) { -#ifdef SIGALRM BIO_printf(bio_err, mr ? "+DT:%s:%d:%d\n" : "Doing %s for %ds on %d size blocks: ", s, tm, length); (void)BIO_flush(bio_err); run = 1; alarm(tm); -#else - BIO_printf(bio_err, - mr ? "+DN:%s:%ld:%d\n" - : "Doing %s %ld times on %d size blocks: ", s, num, length); - (void)BIO_flush(bio_err); -#endif } static void pkey_print_message(const char *str, const char *str2, long num, unsigned int bits, int tm) { -#ifdef SIGALRM BIO_printf(bio_err, mr ? "+DTP:%d:%s:%s:%d\n" : "Doing %u bits %s %s's for %ds: ", bits, str, str2, tm); (void)BIO_flush(bio_err); run = 1; alarm(tm); -#else - BIO_printf(bio_err, - mr ? "+DNP:%ld:%d:%s:%s\n" - : "Doing %ld %u bits %s %s's: ", num, bits, str, str2); - (void)BIO_flush(bio_err); -#endif } static void print_result(int alg, int run_no, int count, double time_used) { if (count == -1) { - BIO_puts(bio_err, "EVP error!\n"); - exit(1); + BIO_printf(bio_err, "%s error!\n", names[alg]); + ERR_print_errors(bio_err); + return; } BIO_printf(bio_err, mr ? "+R:%d:%s:%f\n" @@ -3454,9 +3404,8 @@ static char *sstrsep(char **string, const char *delim) delim++; } - while (!isdelim[(unsigned char)(**string)]) { + while (!isdelim[(unsigned char)(**string)]) (*string)++; - } if (**string) { **string = 0; @@ -3471,6 +3420,7 @@ static int do_multi(int multi, int size_num) int n; int fd[2]; int *fds; + int status; static char sep[] = ":"; fds = app_malloc(sizeof(*fds) * multi, "fd buffer for do_multi"); @@ -3506,7 +3456,12 @@ static int do_multi(int multi, int size_num) char buf[1024]; char *p; - f = fdopen(fds[n], "r"); + if ((f = fdopen(fds[n], "r")) == NULL) { + BIO_printf(bio_err, "fdopen failure with 0x%x\n", + errno); + OPENSSL_free(fds); + return 1; + } while (fgets(buf, sizeof(buf), f)) { p = strchr(buf, '\n'); if (p) @@ -3540,9 +3495,7 @@ static int do_multi(int multi, int size_num) d = atof(sstrsep(&p, sep)); rsa_results[k][1] += d; - } -# ifndef OPENSSL_NO_DSA - else if (strncmp(buf, "+F3:", 4) == 0) { + } else if (strncmp(buf, "+F3:", 4) == 0) { int k; double d; @@ -3555,10 +3508,7 @@ static int do_multi(int multi, int size_num) d = atof(sstrsep(&p, sep)); dsa_results[k][1] += d; - } -# endif -# ifndef OPENSSL_NO_EC - else if (strncmp(buf, "+F4:", 4) == 0) { + } else if (strncmp(buf, "+F4:", 4) == 0) { int k; double d; @@ -3595,19 +3545,59 @@ static int do_multi(int multi, int size_num) d = atof(sstrsep(&p, sep)); eddsa_results[k][1] += d; - } -# endif +# ifndef OPENSSL_NO_SM2 + } else if (strncmp(buf, "+F7:", 4) == 0) { + int k; + double d; - else if (strncmp(buf, "+H:", 3) == 0) { + p = buf + 4; + k = atoi(sstrsep(&p, sep)); + sstrsep(&p, sep); + sstrsep(&p, sep); + + d = atof(sstrsep(&p, sep)); + sm2_results[k][0] += d; + + d = atof(sstrsep(&p, sep)); + sm2_results[k][1] += d; +# endif /* OPENSSL_NO_SM2 */ +# ifndef OPENSSL_NO_DH + } else if (strncmp(buf, "+F8:", 4) == 0) { + int k; + double d; + + p = buf + 4; + k = atoi(sstrsep(&p, sep)); + sstrsep(&p, sep); + + d = atof(sstrsep(&p, sep)); + ffdh_results[k][0] += d; +# endif /* OPENSSL_NO_DH */ + } else if (strncmp(buf, "+H:", 3) == 0) { ; - } else + } else { BIO_printf(bio_err, "Unknown type '%s' from child %d\n", buf, n); + } } fclose(f); } OPENSSL_free(fds); + for (n = 0; n < multi; ++n) { + while (wait(&status) == -1) + if (errno != EINTR) { + BIO_printf(bio_err, "Waitng for child failed with 0x%x\n", + errno); + return 1; + } + if (WIFEXITED(status) && WEXITSTATUS(status)) { + BIO_printf(bio_err, "Child exited with %d\n", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + BIO_printf(bio_err, "Child terminated by signal %d\n", + WTERMSIG(status)); + } + } return 1; } #endif @@ -3620,8 +3610,8 @@ static void multiblock_speed(const EVP_CIPHER *evp_cipher, int lengths_single, const int *mblengths = mblengths_list; int j, count, keylen, num = OSSL_NELEM(mblengths_list); const char *alg_name; - unsigned char *inp, *out, *key, no_key[32], no_iv[16]; - EVP_CIPHER_CTX *ctx; + unsigned char *inp = NULL, *out = NULL, *key, no_key[32], no_iv[16]; + EVP_CIPHER_CTX *ctx = NULL; double d = 0.0; if (lengths_single) { @@ -3631,22 +3621,32 @@ static void multiblock_speed(const EVP_CIPHER *evp_cipher, int lengths_single, inp = app_malloc(mblengths[num - 1], "multiblock input buffer"); out = app_malloc(mblengths[num - 1] + 1024, "multiblock output buffer"); - ctx = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(ctx, evp_cipher, NULL, NULL, no_iv); + if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + app_bail_out("failed to allocate cipher context\n"); + if (!EVP_EncryptInit_ex(ctx, evp_cipher, NULL, NULL, no_iv)) + app_bail_out("failed to initialise cipher context\n"); - keylen = EVP_CIPHER_CTX_key_length(ctx); + if ((keylen = EVP_CIPHER_CTX_get_key_length(ctx)) < 0) { + BIO_printf(bio_err, "Impossible negative key length: %d\n", keylen); + goto err; + } key = app_malloc(keylen, "evp_cipher key"); - EVP_CIPHER_CTX_rand_key(ctx, key); - EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL); + if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) + app_bail_out("failed to generate random cipher key\n"); + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL)) + app_bail_out("failed to set cipher key\n"); OPENSSL_clear_free(key, keylen); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_MAC_KEY, sizeof(no_key), no_key); - alg_name = OBJ_nid2ln(EVP_CIPHER_nid(evp_cipher)); + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_MAC_KEY, + sizeof(no_key), no_key) <= 0) + app_bail_out("failed to set AEAD key\n"); + if ((alg_name = EVP_CIPHER_get0_name(evp_cipher)) == NULL) + app_bail_out("failed to get cipher name\n"); for (j = 0; j < num; j++) { print_message(alg_name, 0, mblengths[j], seconds->sym); Time_F(START); - for (count = 0; run && count < 0x7fffffff; count++) { + for (count = 0; run && count < INT_MAX; count++) { unsigned char aad[EVP_AEAD_TLS1_AAD_LEN]; EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; size_t len = mblengths[j]; @@ -3670,8 +3670,9 @@ static void multiblock_speed(const EVP_CIPHER *evp_cipher, int lengths_single, mb_param.out = out; mb_param.inp = inp; mb_param.len = len; - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT, - sizeof(mb_param), &mb_param); + (void)EVP_CIPHER_CTX_ctrl(ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT, + sizeof(mb_param), &mb_param); } else { int pad; @@ -3717,6 +3718,7 @@ static void multiblock_speed(const EVP_CIPHER *evp_cipher, int lengths_single, fprintf(stdout, "\n"); } + err: OPENSSL_free(inp); OPENSSL_free(out); EVP_CIPHER_CTX_free(ctx); diff --git a/apps/spkac.c b/apps/spkac.c index f384af6eb60b..d92be7d6450e 100644 --- a/apps/spkac.c +++ b/apps/spkac.c @@ -1,7 +1,7 @@ /* - * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -21,29 +21,38 @@ #include <openssl/pem.h> typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_NOOUT, OPT_PUBKEY, OPT_VERIFY, OPT_IN, OPT_OUT, OPT_ENGINE, OPT_KEY, OPT_CHALLENGE, OPT_PASSIN, OPT_SPKAC, - OPT_SPKSECT, OPT_KEYFORM + OPT_SPKSECT, OPT_KEYFORM, OPT_DIGEST, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS spkac_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"spksect", OPT_SPKSECT, 's', + "Specify the name of an SPKAC-dedicated section of configuration"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, {"key", OPT_KEY, '<', "Create SPKAC using private key"}, - {"keyform", OPT_KEYFORM, 'f', "Private key file format - default PEM (PEM, DER, or ENGINE)"}, + {"keyform", OPT_KEYFORM, 'f', "Private key file format (ENGINE, other values ignored)"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, {"challenge", OPT_CHALLENGE, 's', "Challenge string"}, {"spkac", OPT_SPKAC, 's', "Alternative SPKAC name"}, + + OPT_SECTION("Output"), + {"digest", OPT_DIGEST, 's', "Sign new SPKAC with the specified digest (default: MD5)" }, + {"out", OPT_OUT, '>', "Output file"}, {"noout", OPT_NOOUT, '-', "Don't print SPKAC"}, {"pubkey", OPT_PUBKEY, '-', "Output public key"}, {"verify", OPT_VERIFY, '-', "Verify SPKAC signature"}, - {"spksect", OPT_SPKSECT, 's', - "Specify the name of an SPKAC-dedicated section of configuration"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + + OPT_PROV_OPTIONS, {NULL} }; @@ -58,8 +67,10 @@ int spkac_main(int argc, char **argv) char *infile = NULL, *outfile = NULL, *passinarg = NULL, *passin = NULL; char *spkstr = NULL, *prog; const char *spkac = "SPKAC", *spksect = "default"; + const char *digest = "MD5"; + EVP_MD *md = NULL; int i, ret = 1, verify = 0, noout = 0, pubkey = 0; - int keyformat = FORMAT_PEM; + int keyformat = FORMAT_UNDEF; OPTION_CHOICE o; prog = opt_init(argc, argv, spkac_options); @@ -108,11 +119,20 @@ int spkac_main(int argc, char **argv) case OPT_SPKSECT: spksect = opt_arg(); break; + case OPT_DIGEST: + digest = opt_arg(); + break; case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); if (argc != 0) goto opthelp; @@ -123,6 +143,9 @@ int spkac_main(int argc, char **argv) } if (keyfile != NULL) { + if (!opt_md(digest, &md)) + goto end; + pkey = load_key(strcmp(keyfile, "-") ? keyfile : NULL, keyformat, 1, passin, e, "private key"); if (pkey == NULL) @@ -133,8 +156,15 @@ int spkac_main(int argc, char **argv) if (challenge != NULL) ASN1_STRING_set(spki->spkac->challenge, challenge, (int)strlen(challenge)); - NETSCAPE_SPKI_set_pubkey(spki, pkey); - NETSCAPE_SPKI_sign(spki, pkey, EVP_md5()); + if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) { + BIO_printf(bio_err, "Error setting public key\n"); + goto end; + } + i = NETSCAPE_SPKI_sign(spki, pkey, md); + if (i <= 0) { + BIO_printf(bio_err, "Error signing SPKAC\n"); + goto end; + } spkstr = NETSCAPE_SPKI_b64_encode(spki); if (spkstr == NULL) goto end; @@ -192,6 +222,7 @@ int spkac_main(int argc, char **argv) ret = 0; end: + EVP_MD_free(md); NCONF_free(conf); NETSCAPE_SPKI_free(spki); BIO_free_all(out); diff --git a/apps/srp.c b/apps/srp.c index 6c5817387973..a9466f830289 100644 --- a/apps/srp.c +++ b/apps/srp.c @@ -1,8 +1,8 @@ /* - * Copyright 2004-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2004, EdelKey Project. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -11,7 +11,11 @@ * for the EdelKey project. */ +/* SRP is deprecated, so we're going to have to use some deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include <openssl/opensslconf.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -186,31 +190,42 @@ static char *srp_create_user(char *user, char **srp_verifier, } typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SRPVFILE, OPT_ADD, OPT_DELETE, OPT_MODIFY, OPT_LIST, OPT_GN, OPT_USERINFO, - OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, OPT_R_ENUM + OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS srp_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [user...]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, {"verbose", OPT_VERBOSE, '-', "Talk a lot while doing things"}, {"config", OPT_CONFIG, '<', "A config file"}, {"name", OPT_NAME, 's', "The particular srp definition to use"}, - {"srpvfile", OPT_SRPVFILE, '<', "The srp verifier file name"}, - {"add", OPT_ADD, '-', "Add a user and srp verifier"}, - {"modify", OPT_MODIFY, '-', - "Modify the srp verifier of an existing user"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Action"), + {"add", OPT_ADD, '-', "Add a user and SRP verifier"}, + {"modify", OPT_MODIFY, '-', "Modify the SRP verifier of an existing user"}, {"delete", OPT_DELETE, '-', "Delete user from verifier file"}, {"list", OPT_LIST, '-', "List users"}, + + OPT_SECTION("Configuration"), + {"srpvfile", OPT_SRPVFILE, '<', "The srp verifier file name"}, {"gn", OPT_GN, 's', "Set g and N values to be used for new verifier"}, {"userinfo", OPT_USERINFO, 's', "Additional info to be set for user"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, + OPT_R_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"user", 0, 0, "Username(s) to process (optional)"}, {NULL} }; @@ -283,11 +298,20 @@ int srp_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* Optional parameters are usernames. */ argc = opt_num_rest(); argv = opt_rest(); + if (!app_RAND_load()) + goto end; + if (srpvfile != NULL && configfile != NULL) { BIO_printf(bio_err, "-srpvfile and -configfile cannot be specified together.\n"); @@ -320,10 +344,7 @@ int srp_main(int argc, char **argv) if (configfile == NULL) configfile = default_config_file; - if (verbose) - BIO_printf(bio_err, "Using configuration from %s\n", - configfile); - conf = app_load_config(configfile); + conf = app_load_config_verbose(configfile, verbose); if (conf == NULL) goto end; if (configfile != default_config_file && !app_load_modules(conf)) @@ -358,8 +379,10 @@ int srp_main(int argc, char **argv) srpvfile); db = load_index(srpvfile, NULL); - if (db == NULL) + if (db == NULL) { + BIO_printf(bio_err, "Problem with index file: %s (could not load/parse file)\n", srpvfile); goto end; + } /* Lets check some fields */ for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { diff --git a/apps/storeutl.c b/apps/storeutl.c index 644fe28499d6..30c9915de3e8 100644 --- a/apps/storeutl.c +++ b/apps/storeutl.c @@ -1,7 +1,7 @@ /* - * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -19,24 +19,29 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, int expected, int criterion, OSSL_STORE_SEARCH *search, int text, int noout, int recursive, int indent, BIO *out, - const char *prog); + const char *prog, OSSL_LIB_CTX *libctx); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE, OPT_OUT, OPT_PASSIN, + OPT_COMMON, + OPT_ENGINE, OPT_OUT, OPT_PASSIN, OPT_NOOUT, OPT_TEXT, OPT_RECURSIVE, OPT_SEARCHFOR_CERTS, OPT_SEARCHFOR_KEYS, OPT_SEARCHFOR_CRLS, OPT_CRITERION_SUBJECT, OPT_CRITERION_ISSUER, OPT_CRITERION_SERIAL, OPT_CRITERION_FINGERPRINT, OPT_CRITERION_ALIAS, - OPT_MD + OPT_MD, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS storeutl_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [options] uri\nValid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] uri\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"out", OPT_OUT, '>', "Output file - default stdout"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"text", OPT_TEXT, '-', "Print a text form of the objects"}, - {"noout", OPT_NOOUT, '-', "No PEM output, just status"}, + {"", OPT_MD, '-', "Any supported digest"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Search"), {"certs", OPT_SEARCHFOR_CERTS, '-', "Search for certificates only"}, {"keys", OPT_SEARCHFOR_KEYS, '-', "Search for keys only"}, {"crls", OPT_SEARCHFOR_CRLS, '-', "Search for CRLs only"}, @@ -45,11 +50,20 @@ const OPTIONS storeutl_options[] = { {"serial", OPT_CRITERION_SERIAL, 's', "Search by issuer and serial, serial number"}, {"fingerprint", OPT_CRITERION_FINGERPRINT, 's', "Search by public key fingerprint, given in hex"}, {"alias", OPT_CRITERION_ALIAS, 's', "Search by alias"}, - {"", OPT_MD, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif {"r", OPT_RECURSIVE, '-', "Recurse through names"}, + + OPT_SECTION("Input"), + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file - default stdout"}, + {"text", OPT_TEXT, '-', "Print a text form of the objects"}, + {"noout", OPT_NOOUT, '-', "No PEM output, just status"}, + + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"uri", 0, 0, "URI of the store object"}, {NULL} }; @@ -68,9 +82,10 @@ int storeutl_main(int argc, char *argv[]) ASN1_INTEGER *serial = NULL; unsigned char *fingerprint = NULL; size_t fingerprintlen = 0; - char *alias = NULL; + char *alias = NULL, *digestname = NULL; OSSL_STORE_SEARCH *search = NULL; - const EVP_MD *digest = NULL; + EVP_MD *digest = NULL; + OSSL_LIB_CTX *libctx = app_get0_libctx(); while ((o = opt_next()) != OPT_EOF) { switch (o) { @@ -142,16 +157,13 @@ int storeutl_main(int argc, char *argv[]) prog); goto end; } - if ((subject = parse_name(opt_arg(), MBSTRING_UTF8, 1)) == NULL) { - BIO_printf(bio_err, "%s: can't parse subject argument.\n", - prog); + subject = parse_name(opt_arg(), MBSTRING_UTF8, 1, "subject"); + if (subject == NULL) goto end; - } break; case OPT_CRITERION_ISSUER: if (criterion != 0 - || (criterion == OSSL_STORE_SEARCH_BY_ISSUER_SERIAL - && issuer != NULL)) { + && criterion != OSSL_STORE_SEARCH_BY_ISSUER_SERIAL) { BIO_printf(bio_err, "%s: criterion already given.\n", prog); goto end; @@ -162,16 +174,13 @@ int storeutl_main(int argc, char *argv[]) prog); goto end; } - if ((issuer = parse_name(opt_arg(), MBSTRING_UTF8, 1)) == NULL) { - BIO_printf(bio_err, "%s: can't parse issuer argument.\n", - prog); + issuer = parse_name(opt_arg(), MBSTRING_UTF8, 1, "issuer"); + if (issuer == NULL) goto end; - } break; case OPT_CRITERION_SERIAL: if (criterion != 0 - || (criterion == OSSL_STORE_SEARCH_BY_ISSUER_SERIAL - && serial != NULL)) { + && criterion != OSSL_STORE_SEARCH_BY_ISSUER_SERIAL) { BIO_printf(bio_err, "%s: criterion already given.\n", prog); goto end; @@ -237,20 +246,24 @@ int storeutl_main(int argc, char *argv[]) e = setup_engine(opt_arg(), 0); break; case OPT_MD: - if (!opt_md(opt_unknown(), &digest)) - goto opthelp; + digestname = opt_unknown(); + break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* One argument, the URI */ argc = opt_num_rest(); argv = opt_rest(); - - if (argc == 0) { - BIO_printf(bio_err, "%s: No URI given, nothing to do...\n", prog); - goto opthelp; - } - if (argc > 1) { - BIO_printf(bio_err, "%s: Unknown extra parameters after URI\n", prog); + if (argc != 1) goto opthelp; + + if (digestname != NULL) { + if (!opt_md(digestname, &digest)) + goto opthelp; } if (criterion != 0) { @@ -305,9 +318,10 @@ int storeutl_main(int argc, char *argv[]) ret = process(argv[0], get_ui_method(), &pw_cb_data, expected, criterion, search, - text, noout, recursive, 0, out, prog); + text, noout, recursive, 0, out, prog, libctx); end: + EVP_MD_free(digest); OPENSSL_free(fingerprint); OPENSSL_free(alias); ASN1_INTEGER_free(serial); @@ -336,12 +350,13 @@ static int indent_printf(int indent, BIO *bio, const char *format, ...) static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, int expected, int criterion, OSSL_STORE_SEARCH *search, int text, int noout, int recursive, int indent, BIO *out, - const char *prog) + const char *prog, OSSL_LIB_CTX *libctx) { OSSL_STORE_CTX *store_ctx = NULL; int ret = 1, items = 0; - if ((store_ctx = OSSL_STORE_open(uri, uimeth, uidata, NULL, NULL)) + if ((store_ctx = OSSL_STORE_open_ex(uri, libctx, app_get0_propq(), uimeth, uidata, + NULL, NULL, NULL)) == NULL) { BIO_printf(bio_err, "Couldn't open file or uri %s\n", uri); ERR_print_errors(bio_err); @@ -379,18 +394,20 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, info == NULL ? NULL : OSSL_STORE_INFO_type_string(type); if (info == NULL) { - if (OSSL_STORE_eof(store_ctx)) - break; - if (OSSL_STORE_error(store_ctx)) { if (recursive) ERR_clear_error(); else ERR_print_errors(bio_err); + if (OSSL_STORE_eof(store_ctx)) + break; ret++; continue; } + if (OSSL_STORE_eof(store_ctx)) + break; + BIO_printf(bio_err, "ERROR: OSSL_STORE_load() returned NULL without " "eof or error indications\n"); @@ -422,7 +439,8 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, const char *suburi = OSSL_STORE_INFO_get0_NAME(info); ret += process(suburi, uimeth, uidata, expected, criterion, search, - text, noout, recursive, indent + 2, out, prog); + text, noout, recursive, indent + 2, out, prog, + libctx); } break; case OSSL_STORE_INFO_PARAMS: @@ -433,6 +451,13 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, PEM_write_bio_Parameters(out, OSSL_STORE_INFO_get0_PARAMS(info)); break; + case OSSL_STORE_INFO_PUBKEY: + if (text) + EVP_PKEY_print_public(out, OSSL_STORE_INFO_get0_PUBKEY(info), + 0, NULL); + if (!noout) + PEM_write_bio_PUBKEY(out, OSSL_STORE_INFO_get0_PUBKEY(info)); + break; case OSSL_STORE_INFO_PKEY: if (text) EVP_PKEY_print_private(out, OSSL_STORE_INFO_get0_PKEY(info), diff --git a/apps/testdsa.h b/apps/testdsa.h index 3c4b459db117..d80d2cf7f2d2 100644 --- a/apps/testdsa.h +++ b/apps/testdsa.h @@ -1,14 +1,16 @@ /* - * Copyright 1998-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 <openssl/param_build.h> + /* used by speed.c */ -DSA *get_dsa(int); +EVP_PKEY *get_dsa(int); static unsigned char dsa512_priv[] = { 0x65, 0xe5, 0xc7, 0x38, 0x60, 0x24, 0xb5, 0x89, 0xd4, 0x9c, 0xeb, 0x4c, @@ -211,11 +213,14 @@ typedef struct testdsa_st { st.q_l = sizeof(dsa##bits##_q); \ } while (0) -DSA *get_dsa(int dsa_bits) +EVP_PKEY *get_dsa(int dsa_bits) { - DSA *dsa; + EVP_PKEY *pkey = NULL; BIGNUM *priv_key, *pub_key, *p, *q, *g; + EVP_PKEY_CTX *pctx; testdsa dsa_t; + OSSL_PARAM_BLD *tmpl = NULL; + OSSL_PARAM *params = NULL; switch (dsa_bits) { case 512: @@ -231,30 +236,44 @@ DSA *get_dsa(int dsa_bits) return NULL; } - if ((dsa = DSA_new()) == NULL) + if ((pctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL)) == NULL) return NULL; + priv_key = BN_bin2bn(dsa_t.priv, dsa_t.priv_l, NULL); pub_key = BN_bin2bn(dsa_t.pub, dsa_t.pub_l, NULL); p = BN_bin2bn(dsa_t.p, dsa_t.p_l, NULL); q = BN_bin2bn(dsa_t.q, dsa_t.q_l, NULL); g = BN_bin2bn(dsa_t.g, dsa_t.g_l, NULL); - if ((priv_key == NULL) || (pub_key == NULL) || (p == NULL) || (q == NULL) - || (g == NULL)) { + if (priv_key == NULL || pub_key == NULL || p == NULL || q == NULL + || g == NULL) { goto err; } - if (!DSA_set0_pqg(dsa, p, q, g)) - goto err; - - if (!DSA_set0_key(dsa, pub_key, priv_key)) + if ((tmpl = OSSL_PARAM_BLD_new()) == NULL + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, + p) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, + q) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, + g) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, + priv_key) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, + pub_key) + || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) goto err; - return dsa; - err: - DSA_free(dsa); + if (EVP_PKEY_fromdata_init(pctx) <= 0 + || EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_KEYPAIR, + params) <= 0) + pkey = NULL; +err: + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(tmpl); BN_free(priv_key); BN_free(pub_key); BN_free(p); BN_free(q); BN_free(g); - return NULL; + EVP_PKEY_CTX_free(pctx); + return pkey; } diff --git a/apps/testrsa.h b/apps/testrsa.h index 1350ce54e3fb..8c3a967414c6 100644 --- a/apps/testrsa.h +++ b/apps/testrsa.h @@ -1,7 +1,7 @@ /* * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 diff --git a/apps/timeouts.h b/apps/timeouts.h index 7e606cba0b20..002852724763 100644 --- a/apps/timeouts.h +++ b/apps/timeouts.h @@ -1,7 +1,7 @@ /* * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 diff --git a/apps/ts.c b/apps/ts.c index 66a0c810e0c3..57292e187cd2 100644 --- a/apps/ts.c +++ b/apps/ts.c @@ -1,7 +1,7 @@ /* - * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -63,60 +63,68 @@ static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial); /* Verify related functions. */ static int verify_command(const char *data, const char *digest, const char *queryfile, const char *in, int token_in, - const char *CApath, const char *CAfile, const char *untrusted, - X509_VERIFY_PARAM *vpm); + const char *CApath, const char *CAfile, + const char *CAstore, + char *untrusted, X509_VERIFY_PARAM *vpm); static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, const char *queryfile, const char *CApath, const char *CAfile, - const char *untrusted, + const char *CAstore, + char *untrusted, X509_VERIFY_PARAM *vpm); static X509_STORE *create_cert_store(const char *CApath, const char *CAfile, - X509_VERIFY_PARAM *vpm); + const char *CAstore, X509_VERIFY_PARAM *vpm); static int verify_cb(int ok, X509_STORE_CTX *ctx); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_ENGINE, OPT_CONFIG, OPT_SECTION, OPT_QUERY, OPT_DATA, OPT_DIGEST, OPT_TSPOLICY, OPT_NO_NONCE, OPT_CERT, OPT_IN, OPT_TOKEN_IN, OPT_OUT, OPT_TOKEN_OUT, OPT_TEXT, OPT_REPLY, OPT_QUERYFILE, OPT_PASSIN, OPT_INKEY, OPT_SIGNER, - OPT_CHAIN, OPT_VERIFY, OPT_CAPATH, OPT_CAFILE, OPT_UNTRUSTED, - OPT_MD, OPT_V_ENUM, OPT_R_ENUM + OPT_CHAIN, OPT_VERIFY, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE, OPT_UNTRUSTED, + OPT_MD, OPT_V_ENUM, OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS ts_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, {"config", OPT_CONFIG, '<', "Configuration file"}, {"section", OPT_SECTION, 's', "Section to use within config file"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + {"inkey", OPT_INKEY, 's', "File with private key for reply"}, + {"signer", OPT_SIGNER, 's', "Signer certificate file"}, + {"chain", OPT_CHAIN, '<', "File with signer CA chain"}, + {"CAfile", OPT_CAFILE, '<', "File with trusted CA certs"}, + {"CApath", OPT_CAPATH, '/', "Path to trusted CA files"}, + {"CAstore", OPT_CASTORE, ':', "URI to trusted CA store"}, + {"untrusted", OPT_UNTRUSTED, '<', "Extra untrusted certs"}, + {"token_in", OPT_TOKEN_IN, '-', "Input is a PKCS#7 file"}, + {"token_out", OPT_TOKEN_OUT, '-', "Output is a PKCS#7 file"}, + {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, + {"", OPT_MD, '-', "Any supported digest"}, + + OPT_SECTION("Query"), {"query", OPT_QUERY, '-', "Generate a TS query"}, {"data", OPT_DATA, '<', "File to hash"}, {"digest", OPT_DIGEST, 's', "Digest (as a hex string)"}, - OPT_R_OPTIONS, - {"tspolicy", OPT_TSPOLICY, 's', "Policy OID to use"}, - {"no_nonce", OPT_NO_NONCE, '-', "Do not include a nonce"}, + {"queryfile", OPT_QUERYFILE, '<', "File containing a TS query"}, {"cert", OPT_CERT, '-', "Put cert request into query"}, {"in", OPT_IN, '<', "Input file"}, - {"token_in", OPT_TOKEN_IN, '-', "Input is a PKCS#7 file"}, + + OPT_SECTION("Verify"), + {"verify", OPT_VERIFY, '-', "Verify a TS response"}, + {"reply", OPT_REPLY, '-', "Generate a TS reply"}, + {"tspolicy", OPT_TSPOLICY, 's', "Policy OID to use"}, + {"no_nonce", OPT_NO_NONCE, '-', "Do not include a nonce"}, {"out", OPT_OUT, '>', "Output file"}, - {"token_out", OPT_TOKEN_OUT, '-', "Output is a PKCS#7 file"}, {"text", OPT_TEXT, '-', "Output text (not DER)"}, - {"reply", OPT_REPLY, '-', "Generate a TS reply"}, - {"queryfile", OPT_QUERYFILE, '<', "File containing a TS query"}, - {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, - {"inkey", OPT_INKEY, 's', "File with private key for reply"}, - {"signer", OPT_SIGNER, 's', "Signer certificate file"}, - {"chain", OPT_CHAIN, '<', "File with signer CA chain"}, - {"verify", OPT_VERIFY, '-', "Verify a TS response"}, - {"CApath", OPT_CAPATH, '/', "Path to trusted CA files"}, - {"CAfile", OPT_CAFILE, '<', "File with trusted CA certs"}, - {"untrusted", OPT_UNTRUSTED, '<', "File with untrusted certs"}, - {"", OPT_MD, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif - {OPT_HELP_STR, 1, '-', "\nOptions specific to 'ts -verify': \n"}, + + OPT_R_OPTIONS, OPT_V_OPTIONS, - {OPT_HELP_STR, 1, '-', "\n"}, + OPT_PROV_OPTIONS, {NULL} }; @@ -124,41 +132,43 @@ const OPTIONS ts_options[] = { * This command is so complex, special help is needed. */ static char* opt_helplist[] = { + "", "Typical uses:", - "ts -query [-rand file...] [-config file] [-data file]", - " [-digest hexstring] [-tspolicy oid] [-no_nonce] [-cert]", - " [-in file] [-out file] [-text]", - " or", - "ts -reply [-config file] [-section tsa_section]", - " [-queryfile file] [-passin password]", - " [-signer tsa_cert.pem] [-inkey private_key.pem]", - " [-chain certs_file.pem] [-tspolicy oid]", - " [-in file] [-token_in] [-out file] [-token_out]", + " openssl ts -query [-rand file...] [-config file] [-data file]", + " [-digest hexstring] [-tspolicy oid] [-no_nonce] [-cert]", + " [-in file] [-out file] [-text]", + "", + " openssl ts -reply [-config file] [-section tsa_section]", + " [-queryfile file] [-passin password]", + " [-signer tsa_cert.pem] [-inkey private_key.pem]", + " [-chain certs_file.pem] [-tspolicy oid]", + " [-in file] [-token_in] [-out file] [-token_out]", #ifndef OPENSSL_NO_ENGINE - " [-text] [-engine id]", + " [-text] [-engine id]", #else - " [-text]", + " [-text]", #endif - " or", - "ts -verify -CApath dir -CAfile file.pem -untrusted file.pem", - " [-data file] [-digest hexstring]", - " [-queryfile file] -in file [-token_in]", - " [[options specific to 'ts -verify']]", + "", + " openssl ts -verify -CApath dir -CAfile root-cert.pem -CAstore uri", + " -untrusted extra-certs.pem [-data file] [-digest hexstring]", + " [-queryfile request.tsq] -in response.tsr [-token_in] ...", NULL, }; int ts_main(int argc, char **argv) { CONF *conf = NULL; - const char *CAfile = NULL, *untrusted = NULL, *prog; + const char *CAfile = NULL, *prog; + char *untrusted = NULL; const char *configfile = default_config_file, *engine = NULL; - const char *section = NULL; + const char *section = NULL, *digestname = NULL; char **helpp; char *password = NULL; char *data = NULL, *digest = NULL, *policy = NULL; char *in = NULL, *out = NULL, *queryfile = NULL, *passin = NULL; char *inkey = NULL, *signer = NULL, *chain = NULL, *CApath = NULL; - const EVP_MD *md = NULL; + char *CAstore = NULL; + EVP_MD *md = NULL; OPTION_CHOICE o, mode = OPT_ERR; int ret = 1, no_nonce = 0, cert = 0, text = 0; int vpmtouched = 0; @@ -208,6 +218,10 @@ int ts_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_TSPOLICY: policy = opt_arg(); break; @@ -253,6 +267,9 @@ int ts_main(int argc, char **argv) case OPT_CAFILE: CAfile = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_UNTRUSTED: untrusted = opt_arg(); break; @@ -260,8 +277,7 @@ int ts_main(int argc, char **argv) engine = opt_arg(); break; case OPT_MD: - if (!opt_md(opt_unknown(), &md)) - goto opthelp; + digestname = opt_unknown(); break; case OPT_V_CASES: if (!opt_verify(o, vpm)) @@ -270,9 +286,19 @@ int ts_main(int argc, char **argv) break; } } - if (mode == OPT_ERR || opt_num_rest() != 0) + + /* No extra arguments. */ + argc = opt_num_rest(); + if (argc != 0 || mode == OPT_ERR) goto opthelp; + if (!app_RAND_load()) + goto end; + + if (digestname != NULL) { + if (!opt_md(digestname, &md)) + goto opthelp; + } if (mode == OPT_REPLY && passin && !app_passwd(passin, NULL, &password, NULL)) { BIO_printf(bio_err, "Error getting password.\n"); @@ -309,7 +335,7 @@ int ts_main(int argc, char **argv) if ((in == NULL) || !EXACTLY_ONE(queryfile, data, digest)) goto opthelp; ret = !verify_command(data, digest, queryfile, in, token_in, - CApath, CAfile, untrusted, + CApath, CAfile, CAstore, untrusted, vpmtouched ? vpm : NULL); } else { goto opthelp; @@ -317,6 +343,7 @@ int ts_main(int argc, char **argv) end: X509_VERIFY_PARAM_free(vpm); + EVP_MD_free(md); NCONF_free(conf); OPENSSL_free(password); return ret; @@ -423,7 +450,7 @@ static TS_REQ *create_query(BIO *data_bio, const char *digest, const EVP_MD *md, ASN1_OBJECT *policy_obj = NULL; ASN1_INTEGER *nonce_asn1 = NULL; - if (md == NULL && (md = EVP_get_digestbyname("sha1")) == NULL) + if (md == NULL && (md = EVP_get_digestbyname("sha256")) == NULL) goto err; if ((ts_req = TS_REQ_new()) == NULL) goto err; @@ -433,7 +460,7 @@ static TS_REQ *create_query(BIO *data_bio, const char *digest, const EVP_MD *md, goto err; if ((algo = X509_ALGOR_new()) == NULL) goto err; - if ((algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))) == NULL) + if ((algo->algorithm = OBJ_nid2obj(EVP_MD_get_type(md))) == NULL) goto err; if ((algo->parameter = ASN1_TYPE_new()) == NULL) goto err; @@ -482,7 +509,7 @@ static int create_digest(BIO *input, const char *digest, const EVP_MD *md, int rv = 0; EVP_MD_CTX *md_ctx = NULL; - md_value_len = EVP_MD_size(md); + md_value_len = EVP_MD_get_size(md); if (md_value_len < 0) return 0; @@ -502,11 +529,12 @@ static int create_digest(BIO *input, const char *digest, const EVP_MD *md, } if (!EVP_DigestFinal(md_ctx, *md_value, NULL)) goto err; - md_value_len = EVP_MD_size(md); + md_value_len = EVP_MD_get_size(md); } else { long digest_len; + *md_value = OPENSSL_hexstr2buf(digest, &digest_len); - if (!*md_value || md_value_len != digest_len) { + if (*md_value == NULL || md_value_len != digest_len) { OPENSSL_free(*md_value); *md_value = NULL; BIO_printf(bio_err, "bad digest, %d bytes " @@ -817,7 +845,8 @@ static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial) static int verify_command(const char *data, const char *digest, const char *queryfile, const char *in, int token_in, - const char *CApath, const char *CAfile, const char *untrusted, + const char *CApath, const char *CAfile, + const char *CAstore, char *untrusted, X509_VERIFY_PARAM *vpm) { BIO *in_bio = NULL; @@ -837,7 +866,7 @@ static int verify_command(const char *data, const char *digest, const char *quer } if ((verify_ctx = create_verify_ctx(data, digest, queryfile, - CApath, CAfile, untrusted, + CApath, CAfile, CAstore, untrusted, vpm)) == NULL) goto end; @@ -864,10 +893,12 @@ static int verify_command(const char *data, const char *digest, const char *quer static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, const char *queryfile, const char *CApath, const char *CAfile, - const char *untrusted, + const char *CAstore, + char *untrusted, X509_VERIFY_PARAM *vpm) { TS_VERIFY_CTX *ctx = NULL; + STACK_OF(X509) *certs; BIO *input = NULL; TS_REQ *request = NULL; int ret = 0; @@ -912,14 +943,18 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, TS_VERIFY_CTX_add_flags(ctx, f | TS_VFY_SIGNATURE); /* Initialising the X509_STORE object. */ - if (TS_VERIFY_CTX_set_store(ctx, create_cert_store(CApath, CAfile, vpm)) + if (TS_VERIFY_CTX_set_store(ctx, + create_cert_store(CApath, CAfile, CAstore, vpm)) == NULL) goto err; - /* Loading untrusted certificates. */ - if (untrusted - && TS_VERIFY_CTS_set_certs(ctx, TS_CONF_load_certs(untrusted)) == NULL) - goto err; + /* Loading any extra untrusted certificates. */ + if (untrusted != NULL) { + certs = load_certs_multifile(untrusted, NULL, "extra untrusted certs", + vpm); + if (certs == NULL || TS_VERIFY_CTX_set_certs(ctx, certs) == NULL) + goto err; + } ret = 1; err: @@ -933,13 +968,18 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, } static X509_STORE *create_cert_store(const char *CApath, const char *CAfile, - X509_VERIFY_PARAM *vpm) + const char *CAstore, X509_VERIFY_PARAM *vpm) { X509_STORE *cert_ctx = NULL; X509_LOOKUP *lookup = NULL; - int i; + OSSL_LIB_CTX *libctx = app_get0_libctx(); + const char *propq = app_get0_propq(); cert_ctx = X509_STORE_new(); + if (cert_ctx == NULL) { + BIO_printf(bio_err, "memory allocation failure\n"); + return NULL; + } X509_STORE_set_verify_cb(cert_ctx, verify_cb); if (CApath != NULL) { lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); @@ -947,8 +987,7 @@ static X509_STORE *create_cert_store(const char *CApath, const char *CAfile, BIO_printf(bio_err, "memory allocation failure\n"); goto err; } - i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM); - if (!i) { + if (X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM) <= 0) { BIO_printf(bio_err, "Error loading directory %s\n", CApath); goto err; } @@ -960,13 +999,25 @@ static X509_STORE *create_cert_store(const char *CApath, const char *CAfile, BIO_printf(bio_err, "memory allocation failure\n"); goto err; } - i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM); - if (!i) { + if (X509_LOOKUP_load_file_ex(lookup, CAfile, X509_FILETYPE_PEM, libctx, + propq) <= 0) { BIO_printf(bio_err, "Error loading file %s\n", CAfile); goto err; } } + if (CAstore != NULL) { + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_store()); + if (lookup == NULL) { + BIO_printf(bio_err, "memory allocation failure\n"); + goto err; + } + if (X509_LOOKUP_load_store_ex(lookup, CAstore, libctx, propq) <= 0) { + BIO_printf(bio_err, "Error loading store URI %s\n", CAstore); + goto err; + } + } + if (vpm != NULL) X509_STORE_set1_param(cert_ctx, vpm); diff --git a/apps/tsget.in b/apps/tsget.in index bec365e28ce5..3b5f83cf9b57 100644 --- a/apps/tsget.in +++ b/apps/tsget.in @@ -1,8 +1,8 @@ #!{- $config{HASHBANGPERL} -} -# Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2002-2021 The OpenSSL Project Authors. All Rights Reserved. # Copyright (c) 2002 The OpenTSA Project. All rights reserved. # -# Licensed under the OpenSSL license (the "License"). You may not use +# 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 @@ -21,10 +21,10 @@ sub read_body { my $return_data = ""; my $data_len = length ${$state->{data}}; if ($state->{bytes} < $data_len) { - $data_len = $data_len - $state->{bytes}; - $data_len = $maxlength if $data_len > $maxlength; - $return_data = substr ${$state->{data}}, $state->{bytes}, $data_len; - $state->{bytes} += $data_len; + $data_len = $data_len - $state->{bytes}; + $data_len = $maxlength if $data_len > $maxlength; + $return_data = substr ${$state->{data}}, $state->{bytes}, $data_len; + $state->{bytes} += $data_len; } return $return_data; } @@ -47,14 +47,14 @@ sub create_curl { $curl->setopt(CURLOPT_VERBOSE, 1) if $options{d}; $curl->setopt(CURLOPT_FAILONERROR, 1); $curl->setopt(CURLOPT_USERAGENT, - "OpenTSA tsget.pl/openssl-{- $config{version} -}"); + "OpenTSA tsget.pl/openssl-{- $config{full_version} -}"); # Options for POST method. $curl->setopt(CURLOPT_UPLOAD, 1); $curl->setopt(CURLOPT_CUSTOMREQUEST, "POST"); $curl->setopt(CURLOPT_HTTPHEADER, - ["Content-Type: application/timestamp-query", - "Accept: application/timestamp-reply,application/timestamp-response"]); + ["Content-Type: application/timestamp-query", + "Accept: application/timestamp-reply,application/timestamp-response"]); $curl->setopt(CURLOPT_READFUNCTION, \&read_body); $curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[0]); }); @@ -63,8 +63,8 @@ sub create_curl { # SSL related options. $curl->setopt(CURLOPT_SSLKEYTYPE, "PEM"); - $curl->setopt(CURLOPT_SSL_VERIFYPEER, 1); # Verify server's certificate. - $curl->setopt(CURLOPT_SSL_VERIFYHOST, 2); # Check server's CN. + $curl->setopt(CURLOPT_SSL_VERIFYPEER, 1); # Verify server's certificate. + $curl->setopt(CURLOPT_SSL_VERIFYHOST, 2); # Check server's CN. $curl->setopt(CURLOPT_SSLKEY, $options{k}) if defined($options{k}); $curl->setopt(CURLOPT_SSLKEYPASSWD, $options{p}) if defined($options{p}); $curl->setopt(CURLOPT_SSLCERT, $options{c}) if defined($options{c}); @@ -101,15 +101,15 @@ sub get_timestamp { my $error_string; if ($error_code != 0) { my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE); - $error_string = "could not get timestamp"; - $error_string .= ", http code: $http_code" unless $http_code == 0; - $error_string .= ", curl code: $error_code"; - $error_string .= " ($::error_buf)" if defined($::error_buf); + $error_string = "could not get timestamp"; + $error_string .= ", http code: $http_code" unless $http_code == 0; + $error_string .= ", curl code: $error_code"; + $error_string .= " ($::error_buf)" if defined($::error_buf); } else { my $ct = $curl->getinfo(CURLINFO_CONTENT_TYPE); - if (lc($ct) ne "application/timestamp-reply" - && lc($ct) ne "application/timestamp-response") { - $error_string = "unexpected content type returned: $ct"; + if (lc($ct) ne "application/timestamp-reply" + && lc($ct) ne "application/timestamp-response") { + $error_string = "unexpected content type returned: $ct"; } } return ($ts_body, $error_string); @@ -163,15 +163,15 @@ REQUEST: foreach (@ARGV) { # Read request. my $body; if ($input eq "-") { - # Read the request from STDIN; - $body = <STDIN>; + # Read the request from STDIN; + $body = <STDIN>; } else { - # Read the request from file. + # Read the request from file. open INPUT, "<" . $input - or warn("$input: could not open input file: $!\n"), next REQUEST; + or warn("$input: could not open input file: $!\n"), next REQUEST; $body = <INPUT>; close INPUT - or warn("$input: could not close input file: $!\n"), next REQUEST; + or warn("$input: could not close input file: $!\n"), next REQUEST; } # Send request. @@ -179,21 +179,21 @@ REQUEST: foreach (@ARGV) { my ($ts_body, $error) = get_timestamp $curl, \$body; if (defined($error)) { - die "$input: fatal error: $error\n"; + die "$input: fatal error: $error\n"; } STDERR->printflush(", reply received") if $options{v}; # Write response. if ($output eq "-") { - # Write to STDOUT. + # Write to STDOUT. print $ts_body; } else { - # Write to file. + # Write to file. open OUTPUT, ">", $output - or warn("$output: could not open output file: $!\n"), next REQUEST; + or warn("$output: could not open output file: $!\n"), next REQUEST; print OUTPUT $ts_body; close OUTPUT - or warn("$output: could not close output file: $!\n"), next REQUEST; + or warn("$output: could not close output file: $!\n"), next REQUEST; } STDERR->printflush(", $output written.\n") if $options{v}; } diff --git a/apps/verify.c b/apps/verify.c index 1f9385606046..3aae931f69df 100644 --- a/apps/verify.c +++ b/apps/verify.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -21,42 +21,58 @@ static int cb(int ok, X509_STORE_CTX *ctx); static int check(X509_STORE *ctx, const char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, - STACK_OF(X509_CRL) *crls, int show_chain); + STACK_OF(X509_CRL) *crls, int show_chain, + STACK_OF(OPENSSL_STRING) *opts); static int v_verbose = 0, vflags = 0; typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_ENGINE, OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, + OPT_COMMON, + OPT_ENGINE, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE, + OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_UNTRUSTED, OPT_TRUSTED, OPT_CRLFILE, OPT_CRL_DOWNLOAD, OPT_SHOW_CHAIN, - OPT_V_ENUM, OPT_NAMEOPT, - OPT_VERBOSE + OPT_V_ENUM, OPT_NAMEOPT, OPT_VFYOPT, + OPT_VERBOSE, + OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS verify_options[] = { - {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"}, - {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, + {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert...]\n"}, + + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif {"verbose", OPT_VERBOSE, '-', "Print extra information about the operations being performed."}, - {"CApath", OPT_CAPATH, '/', "A directory of trusted certificates"}, + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, + + OPT_SECTION("Certificate chain"), + {"trusted", OPT_TRUSTED, '<', "A file of trusted certificates"}, {"CAfile", OPT_CAFILE, '<', "A file of trusted certificates"}, + {"CApath", OPT_CAPATH, '/', "A directory of files with trusted certificates"}, + {"CAstore", OPT_CASTORE, ':', "URI to a store of trusted certificates"}, {"no-CAfile", OPT_NOCAFILE, '-', - "Do not load the default certificates file"}, + "Do not load the default trusted certificates file"}, {"no-CApath", OPT_NOCAPATH, '-', - "Do not load certificates from the default certificates directory"}, + "Do not load trusted certificates from the default directory"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load trusted certificates from the default certificates store"}, {"untrusted", OPT_UNTRUSTED, '<', "A file of untrusted certificates"}, - {"trusted", OPT_TRUSTED, '<', "A file of trusted certificates"}, {"CRLfile", OPT_CRLFILE, '<', "File containing one or more CRL's (in PEM format) to load"}, {"crl_download", OPT_CRL_DOWNLOAD, '-', - "Attempt to download CRL information for this certificate"}, + "Try downloading CRL information for certificates via their CDP entries"}, {"show_chain", OPT_SHOW_CHAIN, '-', "Display information about the certificate chain"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, + OPT_V_OPTIONS, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, -#endif + {"vfyopt", OPT_VFYOPT, 's', "Verification parameter in n:v form"}, + + OPT_PROV_OPTIONS, + + OPT_PARAMETERS(), + {"cert", 0, 0, "Certificate(s) to verify (optional; stdin used otherwise)"}, {NULL} }; @@ -65,10 +81,11 @@ int verify_main(int argc, char **argv) ENGINE *e = NULL; STACK_OF(X509) *untrusted = NULL, *trusted = NULL; STACK_OF(X509_CRL) *crls = NULL; + STACK_OF(OPENSSL_STRING) *vfyopts = NULL; X509_STORE *store = NULL; X509_VERIFY_PARAM *vpm = NULL; - const char *prog, *CApath = NULL, *CAfile = NULL; - int noCApath = 0, noCAfile = 0; + const char *prog, *CApath = NULL, *CAfile = NULL, *CAstore = NULL; + int noCApath = 0, noCAfile = 0, noCAstore = 0; int vpmtouched = 0, crl_download = 0, show_chain = 0, i = 0, ret = 1; OPTION_CHOICE o; @@ -80,24 +97,25 @@ int verify_main(int argc, char **argv) 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(verify_options); - BIO_printf(bio_err, "Recognized usages:\n"); + BIO_printf(bio_err, "\nRecognized certificate chain purposes:\n"); for (i = 0; i < X509_PURPOSE_get_count(); i++) { - X509_PURPOSE *ptmp; - ptmp = X509_PURPOSE_get0(i); - BIO_printf(bio_err, "\t%-10s\t%s\n", + X509_PURPOSE *ptmp = X509_PURPOSE_get0(i); + + BIO_printf(bio_err, " %-15s %s\n", X509_PURPOSE_get0_sname(ptmp), X509_PURPOSE_get0_name(ptmp)); } - BIO_printf(bio_err, "Recognized verify names:\n"); + BIO_printf(bio_err, "Recognized certificate policy names:\n"); for (i = 0; i < X509_VERIFY_PARAM_get_count(); i++) { - const X509_VERIFY_PARAM *vptmp; - vptmp = X509_VERIFY_PARAM_get0(i); - BIO_printf(bio_err, "\t%-10s\n", + const X509_VERIFY_PARAM *vptmp = X509_VERIFY_PARAM_get0(i); + + BIO_printf(bio_err, " %s\n", X509_VERIFY_PARAM_get0_name(vptmp)); } ret = 0; @@ -113,15 +131,21 @@ int verify_main(int argc, char **argv) case OPT_CAFILE: CAfile = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; case OPT_NOCAPATH: noCApath = 1; break; case OPT_NOCAFILE: noCAfile = 1; break; + case OPT_NOCASTORE: + noCAstore = 1; + break; case OPT_UNTRUSTED: /* Zero or more times */ - if (!load_certs(opt_arg(), &untrusted, FORMAT_PEM, NULL, + if (!load_certs(opt_arg(), 0, &untrusted, NULL, "untrusted certificates")) goto end; break; @@ -129,14 +153,13 @@ int verify_main(int argc, char **argv) /* Zero or more times */ noCAfile = 1; noCApath = 1; - if (!load_certs(opt_arg(), &trusted, FORMAT_PEM, NULL, - "trusted certificates")) + noCAstore = 1; + if (!load_certs(opt_arg(), 0, &trusted, NULL, "trusted certificates")) goto end; break; case OPT_CRLFILE: /* Zero or more times */ - if (!load_crls(opt_arg(), &crls, FORMAT_PEM, NULL, - "other CRLs")) + if (!load_crls(opt_arg(), &crls, NULL, "other CRLs")) goto end; break; case OPT_CRL_DOWNLOAD: @@ -155,21 +178,36 @@ int verify_main(int argc, char **argv) if (!set_nameopt(opt_arg())) goto end; break; + case OPT_VFYOPT: + if (!vfyopts) + vfyopts = sk_OPENSSL_STRING_new_null(); + if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg())) + goto opthelp; + break; case OPT_VERBOSE: v_verbose = 1; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; } } + + /* Extra arguments are certificates to verify. */ argc = opt_num_rest(); argv = opt_rest(); - if (trusted != NULL && (CAfile || CApath)) { + + if (trusted != NULL + && (CAfile != NULL || CApath != NULL || CAstore != NULL)) { BIO_printf(bio_err, - "%s: Cannot use -trusted with -CAfile or -CApath\n", + "%s: Cannot use -trusted with -CAfile, -CApath or -CAstore\n", prog); goto end; } - if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) + if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) == NULL) goto end; X509_STORE_set_verify_cb(store, cb); @@ -183,12 +221,13 @@ int verify_main(int argc, char **argv) ret = 0; if (argc < 1) { - if (check(store, NULL, untrusted, trusted, crls, show_chain) != 1) + if (check(store, NULL, untrusted, trusted, crls, show_chain, + vfyopts) != 1) ret = -1; } else { for (i = 0; i < argc; i++) - if (check(store, argv[i], untrusted, trusted, crls, - show_chain) != 1) + if (check(store, argv[i], untrusted, trusted, crls, show_chain, + vfyopts) != 1) ret = -1; } @@ -198,13 +237,15 @@ int verify_main(int argc, char **argv) sk_X509_pop_free(untrusted, X509_free); sk_X509_pop_free(trusted, X509_free); sk_X509_CRL_pop_free(crls, X509_CRL_free); + sk_OPENSSL_STRING_free(vfyopts); release_engine(e); return (ret < 0 ? 2 : ret); } static int check(X509_STORE *ctx, const char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, - STACK_OF(X509_CRL) *crls, int show_chain) + STACK_OF(X509_CRL) *crls, int show_chain, + STACK_OF(OPENSSL_STRING) *opts) { X509 *x = NULL; int i = 0, ret = 0; @@ -212,22 +253,35 @@ static int check(X509_STORE *ctx, const char *file, STACK_OF(X509) *chain = NULL; int num_untrusted; - x = load_cert(file, FORMAT_PEM, "certificate file"); + x = load_cert(file, FORMAT_UNDEF, "certificate file"); if (x == NULL) goto end; + if (opts != NULL) { + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (x509_ctrl_string(x, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + X509_free(x); + return 0; + } + } + } + csc = X509_STORE_CTX_new(); if (csc == NULL) { - printf("error %s: X.509 store context allocation failed\n", - (file == NULL) ? "stdin" : file); + BIO_printf(bio_err, "error %s: X.509 store context allocation failed\n", + (file == NULL) ? "stdin" : file); goto end; } X509_STORE_set_flags(ctx, vflags); if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) { X509_STORE_CTX_free(csc); - printf("error %s: X.509 store context initialization failed\n", - (file == NULL) ? "stdin" : file); + BIO_printf(bio_err, + "error %s: X.509 store context initialization failed\n", + (file == NULL) ? "stdin" : file); goto end; } if (tchain != NULL) @@ -236,28 +290,30 @@ static int check(X509_STORE *ctx, const char *file, X509_STORE_CTX_set0_crls(csc, crls); i = X509_verify_cert(csc); if (i > 0 && X509_STORE_CTX_get_error(csc) == X509_V_OK) { - printf("%s: OK\n", (file == NULL) ? "stdin" : file); + BIO_printf(bio_out, "%s: OK\n", (file == NULL) ? "stdin" : file); ret = 1; if (show_chain) { int j; chain = X509_STORE_CTX_get1_chain(csc); num_untrusted = X509_STORE_CTX_get_num_untrusted(csc); - printf("Chain:\n"); + BIO_printf(bio_out, "Chain:\n"); for (j = 0; j < sk_X509_num(chain); j++) { X509 *cert = sk_X509_value(chain, j); - printf("depth=%d: ", j); + BIO_printf(bio_out, "depth=%d: ", j); X509_NAME_print_ex_fp(stdout, X509_get_subject_name(cert), 0, get_nameopt()); if (j < num_untrusted) - printf(" (untrusted)"); - printf("\n"); + BIO_printf(bio_out, " (untrusted)"); + BIO_printf(bio_out, "\n"); } sk_X509_pop_free(chain, X509_free); } } else { - printf("error %s: verification failed\n", (file == NULL) ? "stdin" : file); + BIO_printf(bio_err, + "error %s: verification failed\n", + (file == NULL) ? "stdin" : file); } X509_STORE_CTX_free(csc); @@ -298,19 +354,34 @@ static int cb(int ok, X509_STORE_CTX *ctx) policies_print(ctx); /* fall thru */ case X509_V_ERR_CERT_HAS_EXPIRED: - /* Continue even if the leaf is a self signed cert */ + /* Continue even if the leaf is a self-signed cert */ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: /* Continue after extension errors too */ case X509_V_ERR_INVALID_CA: case X509_V_ERR_INVALID_NON_CA: case X509_V_ERR_PATH_LENGTH_EXCEEDED: - case X509_V_ERR_INVALID_PURPOSE: case X509_V_ERR_CRL_HAS_EXPIRED: case X509_V_ERR_CRL_NOT_YET_VALID: case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + /* errors due to strict conformance checking (-x509_strict) */ + case X509_V_ERR_INVALID_PURPOSE: + case X509_V_ERR_PATHLEN_INVALID_FOR_NON_CA: + case X509_V_ERR_PATHLEN_WITHOUT_KU_KEY_CERT_SIGN: + case X509_V_ERR_CA_BCONS_NOT_CRITICAL: + case X509_V_ERR_CA_CERT_MISSING_KEY_USAGE: + case X509_V_ERR_KU_KEY_CERT_SIGN_INVALID_FOR_NON_CA: + case X509_V_ERR_ISSUER_NAME_EMPTY: + case X509_V_ERR_SUBJECT_NAME_EMPTY: + case X509_V_ERR_EMPTY_SUBJECT_SAN_NOT_CRITICAL: + case X509_V_ERR_EMPTY_SUBJECT_ALT_NAME: + case X509_V_ERR_SIGNATURE_ALGORITHM_INCONSISTENCY: + case X509_V_ERR_AUTHORITY_KEY_IDENTIFIER_CRITICAL: + case X509_V_ERR_SUBJECT_KEY_IDENTIFIER_CRITICAL: + case X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER: + case X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER: + case X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3: ok = 1; } - return ok; } diff --git a/apps/version.c b/apps/version.c index 2aca1636152b..cab17a46bf18 100644 --- a/apps/version.c +++ b/apps/version.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -15,56 +15,36 @@ #include <openssl/evp.h> #include <openssl/crypto.h> #include <openssl/bn.h> -#ifndef OPENSSL_NO_MD2 -# include <openssl/md2.h> -#endif -#ifndef OPENSSL_NO_RC4 -# include <openssl/rc4.h> -#endif -#ifndef OPENSSL_NO_DES -# include <openssl/des.h> -#endif -#ifndef OPENSSL_NO_IDEA -# include <openssl/idea.h> -#endif -#ifndef OPENSSL_NO_BF -# include <openssl/blowfish.h> -#endif 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_COMMON, + OPT_B, OPT_D, OPT_E, OPT_M, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R, OPT_C } OPTION_CHOICE; const OPTIONS version_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + + OPT_SECTION("Output"), {"a", OPT_A, '-', "Show all data"}, {"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"}, {"r", OPT_R, '-', "Show random seeding options"}, {"v", OPT_V, '-', "Show library version"}, + {"c", OPT_C, '-', "Show CPU settings info"}, {NULL} }; -#if defined(OPENSSL_RAND_SEED_DEVRANDOM) || defined(OPENSSL_RAND_SEED_EGD) -static void printlist(const char *prefix, const char **dev) -{ - printf("%s (", prefix); - for ( ; *dev != NULL; dev++) - printf(" \"%s\"", *dev); - printf(" )"); -} -#endif - 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, cpuinfo = 0; char *prog; OPTION_CHOICE o; @@ -89,6 +69,9 @@ opthelp: case OPT_E: dirty = engdir = 1; break; + case OPT_M: + dirty = moddir = 1; + break; case OPT_F: dirty = cflags = 1; break; @@ -104,48 +87,35 @@ opthelp: case OPT_V: dirty = version = 1; break; + case OPT_C: + dirty = cpuinfo = 1; + break; case OPT_A: - seed = options = cflags = version = date = platform = dir = engdir + seed = options = cflags = version = date = platform + = dir = engdir = moddir = cpuinfo = 1; break; } } - if (opt_num_rest() != 0) { - BIO_printf(bio_err, "Extra parameters given.\n"); + + /* No extra arguments. */ + argc = opt_num_rest(); + if (argc != 0) goto opthelp; - } + if (!dirty) version = 1; - if (version) { - if (OpenSSL_version_num() == OPENSSL_VERSION_NUMBER) - printf("%s\n", OpenSSL_version(OPENSSL_VERSION)); - else - printf("%s (Library: %s)\n", - OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION)); - } + if (version) + printf("%s (Library: %s)\n", + OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION)); if (date) printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON)); if (platform) printf("%s\n", OpenSSL_version(OPENSSL_PLATFORM)); if (options) { - printf("options: "); - printf("%s ", BN_options()); -#ifndef OPENSSL_NO_MD2 - printf("%s ", MD2_options()); -#endif -#ifndef OPENSSL_NO_RC4 - printf("%s ", RC4_options()); -#endif -#ifndef OPENSSL_NO_DES - printf("%s ", DES_options()); -#endif -#ifndef OPENSSL_NO_IDEA - printf("%s ", IDEA_options()); -#endif -#ifndef OPENSSL_NO_BF - printf("%s ", BF_options()); -#endif + printf("options: "); + printf(" %s", BN_options()); printf("\n"); } if (cflags) @@ -154,41 +124,28 @@ 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 - printf(" rtdsc"); -#endif -#ifdef OPENSSL_RAND_SEED_RDCPU - printf(" rdrand ( rdseed rdrand )"); -#endif -#ifdef OPENSSL_RAND_SEED_LIBRANDOM - printf(" C-library-random"); -#endif -#ifdef OPENSSL_RAND_SEED_GETRANDOM - printf(" getrandom-syscall"); -#endif -#ifdef OPENSSL_RAND_SEED_DEVRANDOM - { - static const char *dev[] = { DEVRANDOM, NULL }; - printlist(" random-device", dev); - } -#endif -#ifdef OPENSSL_RAND_SEED_EGD - { - static const char *dev[] = { DEVRANDOM_EGD, NULL }; - printlist(" EGD", dev); - } -#endif -#ifdef OPENSSL_RAND_SEED_NONE - printf(" none"); -#endif -#ifdef OPENSSL_RAND_SEED_OS - printf(" os-specific"); -#endif - printf("\n"); + const char *src = OPENSSL_info(OPENSSL_INFO_SEED_SOURCE); + printf("Seeding source: %s\n", src ? src : "N/A"); } + if (cpuinfo) + printf("%s\n", OpenSSL_version(OPENSSL_CPU_INFO)); ret = 0; end: return ret; } + + +#if defined(__TANDEM) && defined(OPENSSL_VPROC) +/* + * Define a VPROC function for the openssl program. + * This is used by platform version identification tools. + * Do not inline this procedure or make it static. + */ +# define OPENSSL_VPROC_STRING_(x) x##_OPENSSL +# define OPENSSL_VPROC_STRING(x) OPENSSL_VPROC_STRING_(x) +# define OPENSSL_VPROC_FUNC OPENSSL_VPROC_STRING(OPENSSL_VPROC) +void OPENSSL_VPROC_FUNC(void) {} +#endif diff --git a/apps/x509.c b/apps/x509.c index 8d4bf71a03ee..a919d787457c 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 @@ -21,162 +21,271 @@ #include <openssl/x509v3.h> #include <openssl/objects.h> #include <openssl/pem.h> -#ifndef OPENSSL_NO_RSA -# include <openssl/rsa.h> -#endif +#include <openssl/rsa.h> #ifndef OPENSSL_NO_DSA # include <openssl/dsa.h> #endif #undef POSTFIX #define POSTFIX ".srl" -#define DEF_DAYS 30 +#define DEFAULT_DAYS 30 /* default cert validity period in days */ +#define UNSET_DAYS -2 /* -1 is used for testing expiration checks */ +#define EXT_COPY_UNSET -1 static int callb(int ok, X509_STORE_CTX *ctx); -static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, - const EVP_MD *digest, CONF *conf, const char *section, - int preserve_dates); -static int x509_certify(X509_STORE *ctx, const char *CAfile, const EVP_MD *digest, - X509 *x, X509 *xca, EVP_PKEY *pkey, - STACK_OF(OPENSSL_STRING) *sigopts, const char *serialfile, - int create, int days, int clrext, CONF *conf, - const char *section, ASN1_INTEGER *sno, int reqfile, - int preserve_dates); +static ASN1_INTEGER *x509_load_serial(const char *CAfile, + const char *serialfile, int create); static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt); -static int print_x509v3_exts(BIO *bio, X509 *x, const char *exts); +static int print_x509v3_exts(BIO *bio, X509 *x, const char *ext_names); typedef enum OPTION_choice { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_COMMON, OPT_INFORM, OPT_OUTFORM, OPT_KEYFORM, OPT_REQ, OPT_CAFORM, - OPT_CAKEYFORM, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE, - OPT_EXTENSIONS, OPT_IN, OPT_OUT, OPT_SIGNKEY, OPT_CA, - OPT_CAKEY, OPT_CASERIAL, OPT_SET_SERIAL, OPT_FORCE_PUBKEY, - OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_NAMEOPT, - OPT_C, OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL, + OPT_CAKEYFORM, OPT_VFYOPT, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE, + OPT_EXTENSIONS, OPT_IN, OPT_OUT, OPT_KEY, OPT_SIGNKEY, OPT_CA, OPT_CAKEY, + OPT_CASERIAL, OPT_SET_SERIAL, OPT_NEW, OPT_FORCE_PUBKEY, OPT_SUBJ, + OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_DATEOPT, OPT_NAMEOPT, + OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL, OPT_MODULUS, OPT_PUBKEY, OPT_X509TOREQ, OPT_TEXT, OPT_HASH, OPT_ISSUER_HASH, OPT_SUBJECT, OPT_ISSUER, OPT_FINGERPRINT, OPT_DATES, OPT_PURPOSE, OPT_STARTDATE, OPT_ENDDATE, OPT_CHECKEND, OPT_CHECKHOST, OPT_CHECKEMAIL, OPT_CHECKIP, OPT_NOOUT, OPT_TRUSTOUT, OPT_CLRTRUST, OPT_CLRREJECT, OPT_ALIAS, OPT_CACREATESERIAL, OPT_CLREXT, OPT_OCSPID, - OPT_SUBJECT_HASH_OLD, - OPT_ISSUER_HASH_OLD, + OPT_SUBJECT_HASH_OLD, OPT_ISSUER_HASH_OLD, OPT_COPY_EXTENSIONS, OPT_BADSIG, OPT_MD, OPT_ENGINE, OPT_NOCERT, OPT_PRESERVE_DATES, - OPT_R_ENUM, OPT_EXT + OPT_R_ENUM, OPT_PROV_ENUM, OPT_EXT } OPTION_CHOICE; const OPTIONS x509_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + + {"in", OPT_IN, '<', + "Certificate input, or CSR input file with -req (default stdin)"}, + {"passin", OPT_PASSIN, 's', "Private key and cert file pass-phrase source"}, + {"new", OPT_NEW, '-', "Generate a certificate from scratch"}, + {"x509toreq", OPT_X509TOREQ, '-', + "Output a certification request (rather than a certificate)"}, + {"req", OPT_REQ, '-', "Input is a CSR file (rather than a certificate)"}, + {"copy_extensions", OPT_COPY_EXTENSIONS, 's', + "copy extensions when converting from CSR to x509 or vice versa"}, {"inform", OPT_INFORM, 'f', - "Input format - default PEM (one of DER or PEM)"}, - {"in", OPT_IN, '<', "Input file - default stdin"}, - {"outform", OPT_OUTFORM, 'f', - "Output format - default PEM (one of DER or PEM)"}, + "CSR input file format (DER or PEM) - default PEM"}, + {"vfyopt", OPT_VFYOPT, 's', "CSR verification parameter in n:v form"}, + {"key", OPT_KEY, 's', + "Key for signing, and to include unless using -force_pubkey"}, + {"signkey", OPT_SIGNKEY, 's', + "Same as -key"}, + {"keyform", OPT_KEYFORM, 'E', + "Key input format (ENGINE, other values ignored)"}, {"out", OPT_OUT, '>', "Output file - default stdout"}, - {"keyform", OPT_KEYFORM, 'E', "Private key format - default PEM"}, - {"passin", OPT_PASSIN, 's', "Private key password/pass-phrase source"}, + {"outform", OPT_OUTFORM, 'f', + "Output format (DER or PEM) - default PEM"}, + {"nocert", OPT_NOCERT, '-', + "No cert output (except for requested printing)"}, + {"noout", OPT_NOOUT, '-', "No output (except for requested printing)"}, + + OPT_SECTION("Certificate printing"), + {"text", OPT_TEXT, '-', "Print the certificate in text form"}, + {"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."}, + {"certopt", OPT_CERTOPT, 's', "Various certificate text printing options"}, + {"fingerprint", OPT_FINGERPRINT, '-', "Print the certificate fingerprint"}, + {"alias", OPT_ALIAS, '-', "Print certificate alias"}, {"serial", OPT_SERIAL, '-', "Print serial number value"}, - {"subject_hash", OPT_HASH, '-', "Print subject hash value"}, - {"issuer_hash", OPT_ISSUER_HASH, '-', "Print issuer hash value"}, - {"hash", OPT_HASH, '-', "Synonym for -subject_hash"}, + {"startdate", OPT_STARTDATE, '-', "Print the notBefore field"}, + {"enddate", OPT_ENDDATE, '-', "Print the notAfter field"}, + {"dates", OPT_DATES, '-', "Print both notBefore and notAfter fields"}, {"subject", OPT_SUBJECT, '-', "Print subject DN"}, {"issuer", OPT_ISSUER, '-', "Print issuer DN"}, + {"nameopt", OPT_NAMEOPT, 's', + "Certificate subject/issuer name printing options"}, {"email", OPT_EMAIL, '-', "Print email address(es)"}, - {"startdate", OPT_STARTDATE, '-', "Set notBefore field"}, - {"enddate", OPT_ENDDATE, '-', "Set notAfter field"}, - {"purpose", OPT_PURPOSE, '-', "Print out certificate purposes"}, - {"dates", OPT_DATES, '-', "Both Before and After dates"}, - {"modulus", OPT_MODULUS, '-', "Print the RSA key modulus"}, - {"pubkey", OPT_PUBKEY, '-', "Output the public key"}, - {"fingerprint", OPT_FINGERPRINT, '-', - "Print the certificate fingerprint"}, - {"alias", OPT_ALIAS, '-', "Output certificate alias"}, - {"noout", OPT_NOOUT, '-', "No output, just status"}, - {"nocert", OPT_NOCERT, '-', "No certificate output"}, + {"hash", OPT_HASH, '-', "Synonym for -subject_hash (for backward compat)"}, + {"subject_hash", OPT_HASH, '-', "Print subject hash value"}, +#ifndef OPENSSL_NO_MD5 + {"subject_hash_old", OPT_SUBJECT_HASH_OLD, '-', + "Print old-style (MD5) subject hash value"}, +#endif + {"issuer_hash", OPT_ISSUER_HASH, '-', "Print issuer hash value"}, +#ifndef OPENSSL_NO_MD5 + {"issuer_hash_old", OPT_ISSUER_HASH_OLD, '-', + "Print old-style (MD5) issuer hash value"}, +#endif + {"ext", OPT_EXT, 's', + "Restrict which X.509 extensions to print and/or copy"}, {"ocspid", OPT_OCSPID, '-', "Print OCSP hash values for the subject name and public key"}, {"ocsp_uri", OPT_OCSP_URI, '-', "Print OCSP Responder URL(s)"}, - {"trustout", OPT_TRUSTOUT, '-', "Output a trusted certificate"}, - {"clrtrust", OPT_CLRTRUST, '-', "Clear all trusted purposes"}, - {"clrext", OPT_CLREXT, '-', "Clear all certificate extensions"}, - {"addtrust", OPT_ADDTRUST, 's', "Trust certificate for a given purpose"}, - {"addreject", OPT_ADDREJECT, 's', - "Reject certificate for a given purpose"}, - {"setalias", OPT_SETALIAS, 's', "Set certificate alias"}, - {"days", OPT_DAYS, 'n', - "How long till expiry of a signed certificate - def 30 days"}, + {"purpose", OPT_PURPOSE, '-', "Print out certificate purposes"}, + {"pubkey", OPT_PUBKEY, '-', "Print the public key in PEM format"}, + {"modulus", OPT_MODULUS, '-', "Print the RSA key modulus"}, + + OPT_SECTION("Certificate checking"), {"checkend", OPT_CHECKEND, 'M', - "Check whether the cert expires in the next arg seconds"}, - {OPT_MORE_STR, 1, 1, "Exit 1 if so, 0 if not"}, - {"signkey", OPT_SIGNKEY, 's', "Self sign cert with arg"}, - {"x509toreq", OPT_X509TOREQ, '-', - "Output a certification request object"}, - {"req", OPT_REQ, '-', "Input is a certificate request, sign and output"}, - {"CA", OPT_CA, '<', "Set the CA certificate, must be PEM format"}, - {"CAkey", OPT_CAKEY, 's', - "The CA key, must be PEM format; if not in CAfile"}, - {"CAcreateserial", OPT_CACREATESERIAL, '-', - "Create serial number file if it does not exist"}, - {"CAserial", OPT_CASERIAL, 's', "Serial file"}, - {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"}, - {"text", OPT_TEXT, '-', "Print the certificate in text form"}, - {"ext", OPT_EXT, 's', "Print various X509V3 extensions"}, - {"C", OPT_C, '-', "Print out C code forms"}, - {"extfile", OPT_EXTFILE, '<', "File with X509V3 extensions to add"}, - OPT_R_OPTIONS, - {"extensions", OPT_EXTENSIONS, 's', "Section from config file to use"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, - {"certopt", OPT_CERTOPT, 's', "Various certificate text options"}, + "Check whether cert expires in the next arg seconds"}, + {OPT_MORE_STR, 1, 1, "Exit 1 (failure) if so, 0 if not"}, {"checkhost", OPT_CHECKHOST, 's', "Check certificate matches host"}, {"checkemail", OPT_CHECKEMAIL, 's', "Check certificate matches email"}, {"checkip", OPT_CHECKIP, 's', "Check certificate matches ipaddr"}, - {"CAform", OPT_CAFORM, 'F', "CA format - default PEM"}, - {"CAkeyform", OPT_CAKEYFORM, 'E', "CA key format - default PEM"}, - {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, - {"force_pubkey", OPT_FORCE_PUBKEY, '<', "Force the Key to put inside certificate"}, - {"next_serial", OPT_NEXT_SERIAL, '-', "Increment current certificate serial number"}, + + OPT_SECTION("Certificate output"), + {"set_serial", OPT_SET_SERIAL, 's', + "Serial number to use, overrides -CAserial"}, + {"next_serial", OPT_NEXT_SERIAL, '-', + "Increment current certificate serial number"}, + {"days", OPT_DAYS, 'n', + "Number of days until newly generated certificate expires - default 30"}, + {"preserve_dates", OPT_PRESERVE_DATES, '-', + "Preserve existing validity dates"}, + {"subj", OPT_SUBJ, 's', "Set or override certificate subject (and issuer)"}, + {"force_pubkey", OPT_FORCE_PUBKEY, '<', + "Place the given key in new certificate"}, + {"clrext", OPT_CLREXT, '-', + "Do not take over any extensions from the source certificate or request"}, + {"extfile", OPT_EXTFILE, '<', "Config file with X509V3 extensions to add"}, + {"extensions", OPT_EXTENSIONS, 's', + "Section of extfile to use - default: unnamed section"}, + {"sigopt", OPT_SIGOPT, 's', "Signature parameter, in n:v form"}, + {"badsig", OPT_BADSIG, '-', + "Corrupt last byte of certificate signature (for test)"}, + {"", OPT_MD, '-', "Any supported digest, used for signing and printing"}, + + OPT_SECTION("Micro-CA"), + {"CA", OPT_CA, '<', + "Use the given CA certificate, conflicts with -key"}, + {"CAform", OPT_CAFORM, 'F', "CA cert format (PEM/DER/P12); has no effect"}, + {"CAkey", OPT_CAKEY, 's', "The corresponding CA key; default is -CA arg"}, + {"CAkeyform", OPT_CAKEYFORM, 'E', + "CA key format (ENGINE, other values ignored)"}, + {"CAserial", OPT_CASERIAL, 's', + "File that keeps track of CA-generated serial number"}, + {"CAcreateserial", OPT_CACREATESERIAL, '-', + "Create CA serial number file if it does not exist"}, + + OPT_SECTION("Certificate trust output"), + {"trustout", OPT_TRUSTOUT, '-', "Mark certificate PEM output as trusted"}, + {"setalias", OPT_SETALIAS, 's', "Set certificate alias (nickname)"}, + {"clrtrust", OPT_CLRTRUST, '-', "Clear all trusted purposes"}, + {"addtrust", OPT_ADDTRUST, 's', "Trust certificate for a given purpose"}, {"clrreject", OPT_CLRREJECT, '-', "Clears all the prohibited or rejected uses of the certificate"}, - {"badsig", OPT_BADSIG, '-', "Corrupt last byte of certificate signature (for test)"}, - {"", OPT_MD, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_MD5 - {"subject_hash_old", OPT_SUBJECT_HASH_OLD, '-', - "Print old-style (MD5) subject hash value"}, - {"issuer_hash_old", OPT_ISSUER_HASH_OLD, '-', - "Print old-style (MD5) issuer hash value"}, -#endif + {"addreject", OPT_ADDREJECT, 's', + "Reject certificate for a given purpose"}, + + OPT_R_OPTIONS, #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif - {"preserve_dates", OPT_PRESERVE_DATES, '-', "preserve existing dates when signing"}, + OPT_PROV_OPTIONS, {NULL} }; +static void warn_copying(ASN1_OBJECT *excluded, const char *names) +{ + const char *sn = OBJ_nid2sn(OBJ_obj2nid(excluded)); + + if (names != NULL && strstr(names, sn) != NULL) + BIO_printf(bio_err, + "Warning: -ext should not specify copying %s extension to CSR; ignoring this\n", + sn); +} + +static X509_REQ *x509_to_req(X509 *cert, int ext_copy, const char *names) +{ + const STACK_OF(X509_EXTENSION) *cert_exts = X509_get0_extensions(cert); + int i, n = sk_X509_EXTENSION_num(cert_exts /* may be NULL */); + ASN1_OBJECT *skid = OBJ_nid2obj(NID_subject_key_identifier); + ASN1_OBJECT *akid = OBJ_nid2obj(NID_authority_key_identifier); + STACK_OF(X509_EXTENSION) *exts; + X509_REQ *req = X509_to_X509_REQ(cert, NULL, NULL); + + if (req == NULL) + return NULL; + + /* + * Filter out SKID and AKID extensions, which make no sense in a CSR. + * If names is not NULL, copy only those extensions listed there. + */ + warn_copying(skid, names); + warn_copying(akid, names); + if ((exts = sk_X509_EXTENSION_new_reserve(NULL, n)) == NULL) + goto err; + for (i = 0; i < n; i++) { + X509_EXTENSION *ex = sk_X509_EXTENSION_value(cert_exts, i); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + + if (OBJ_cmp(obj, skid) != 0 && OBJ_cmp(obj, akid) != 0 + && !sk_X509_EXTENSION_push(exts, ex)) + goto err; + } + + if (sk_X509_EXTENSION_num(exts) > 0) { + if (ext_copy != EXT_COPY_UNSET && ext_copy != EXT_COPY_NONE + && !X509_REQ_add_extensions(req, exts)) { + BIO_printf(bio_err, "Error copying extensions from certificate\n"); + goto err; + } + } + sk_X509_EXTENSION_free(exts); + return req; + + err: + sk_X509_EXTENSION_free(exts); + X509_REQ_free(req); + return NULL; +} + +static int self_signed(X509_STORE *ctx, X509 *cert) +{ + X509_STORE_CTX *xsc = X509_STORE_CTX_new(); + int ret = 0; + + if (xsc == NULL || !X509_STORE_CTX_init(xsc, ctx, cert, NULL)) { + BIO_printf(bio_err, "Error initialising X509 store\n"); + } else { + X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_CHECK_SS_SIGNATURE); + ret = X509_verify_cert(xsc) > 0; + } + X509_STORE_CTX_free(xsc); + return ret; +} + int x509_main(int argc, char **argv) { ASN1_INTEGER *sno = NULL; ASN1_OBJECT *objtmp = NULL; BIO *out = NULL; CONF *extconf = NULL; - EVP_PKEY *Upkey = NULL, *CApkey = NULL, *fkey = NULL; + int ext_copy = EXT_COPY_UNSET; + X509V3_CTX ext_ctx; + EVP_PKEY *privkey = NULL, *CAkey = NULL, *pubkey = NULL; + EVP_PKEY *pkey; + int newcert = 0; + char *subj = NULL, *digest = NULL; + X509_NAME *fsubj = NULL; + const unsigned long chtype = MBSTRING_ASC; + const int multirdn = 1; STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL; - STACK_OF(OPENSSL_STRING) *sigopts = NULL; - X509 *x = NULL, *xca = NULL; + STACK_OF(OPENSSL_STRING) *sigopts = NULL, *vfyopts = NULL; + X509 *x = NULL, *xca = NULL, *issuer_cert; X509_REQ *req = NULL, *rq = NULL; X509_STORE *ctx = NULL; - const EVP_MD *digest = NULL; - char *CAkeyfile = NULL, *CAserial = NULL, *fkeyfile = NULL, *alias = NULL; - char *checkhost = NULL, *checkemail = NULL, *checkip = NULL, *exts = NULL; + char *CAkeyfile = NULL, *CAserial = NULL, *pubkeyfile = NULL, *alias = NULL; + char *checkhost = NULL, *checkemail = NULL, *checkip = NULL; + char *ext_names = NULL; char *extsect = NULL, *extfile = NULL, *passin = NULL, *passinarg = NULL; - char *infile = NULL, *outfile = NULL, *keyfile = NULL, *CAfile = NULL; + char *infile = NULL, *outfile = NULL, *privkeyfile = NULL, *CAfile = NULL; char *prog; - int x509req = 0, days = DEF_DAYS, modulus = 0, pubkey = 0, pprint = 0; - int C = 0, CAformat = FORMAT_PEM, CAkeyformat = FORMAT_PEM; + int days = UNSET_DAYS; /* not explicitly set */ + int x509toreq = 0, modulus = 0, print_pubkey = 0, pprint = 0; + int CAformat = FORMAT_UNDEF, CAkeyformat = FORMAT_UNDEF; + unsigned long dateopt = ASN1_DTFLGS_RFC822; int fingerprint = 0, reqfile = 0, checkend = 0; - int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM; + int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyformat = FORMAT_UNDEF; int next_serial = 0, subject_hash = 0, issuer_hash = 0, ocspid = 0; - int noout = 0, sign_flag = 0, CA_flag = 0, CA_createserial = 0, email = 0; + int noout = 0, CA_createserial = 0, email = 0; int ocsp_uri = 0, trustout = 0, clrtrust = 0, clrreject = 0, aliasout = 0; - int ret = 1, i, num = 0, badsig = 0, clrext = 0, nocert = 0; + int ret = 1, i, j, num = 0, badsig = 0, clrext = 0, nocert = 0; int text = 0, serial = 0, subject = 0, issuer = 0, startdate = 0, ext = 0; int enddate = 0; time_t checkoffset = 0; @@ -206,7 +315,7 @@ int x509_main(int argc, char **argv) ret = 0; goto end; case OPT_INFORM: - if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) goto opthelp; break; case OPT_IN: @@ -217,15 +326,15 @@ int x509_main(int argc, char **argv) goto opthelp; break; case OPT_KEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PDE, &keyformat)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyformat)) goto opthelp; break; case OPT_CAFORM: - if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &CAformat)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &CAformat)) goto opthelp; break; case OPT_CAKEYFORM: - if (!opt_format(opt_arg(), OPT_FMT_PDE, &CAkeyformat)) + if (!opt_format(opt_arg(), OPT_FMT_ANY, &CAkeyformat)) goto opthelp; break; case OPT_OUT: @@ -235,16 +344,40 @@ int x509_main(int argc, char **argv) reqfile = 1; break; + case OPT_DATEOPT: + if (!set_dateopt(&dateopt, opt_arg())) { + BIO_printf(bio_err, + "Invalid date format: %s\n", opt_arg()); + goto end; + } + break; + case OPT_COPY_EXTENSIONS: + if (!set_ext_copy(&ext_copy, opt_arg())) { + BIO_printf(bio_err, + "Invalid extension copy option: %s\n", opt_arg()); + goto end; + } + break; + case OPT_SIGOPT: if (!sigopts) sigopts = sk_OPENSSL_STRING_new_null(); if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) goto opthelp; break; - case OPT_DAYS: - if (preserve_dates) + case OPT_VFYOPT: + if (!vfyopts) + vfyopts = sk_OPENSSL_STRING_new_null(); + if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg())) goto opthelp; + break; + case OPT_DAYS: days = atoi(opt_arg()); + if (days < -1) { + BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n", + prog); + goto end; + } break; case OPT_PASSIN: passinarg = opt_arg(); @@ -256,16 +389,19 @@ int x509_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_EXTENSIONS: extsect = opt_arg(); break; + case OPT_KEY: case OPT_SIGNKEY: - keyfile = opt_arg(); - sign_flag = ++num; + privkeyfile = opt_arg(); break; case OPT_CA: CAfile = opt_arg(); - CA_flag = ++num; break; case OPT_CAKEY: CAkeyfile = opt_arg(); @@ -281,34 +417,35 @@ int x509_main(int argc, char **argv) if ((sno = s2i_ASN1_INTEGER(NULL, opt_arg())) == NULL) goto opthelp; break; + case OPT_NEW: + newcert = 1; + break; case OPT_FORCE_PUBKEY: - fkeyfile = opt_arg(); + pubkeyfile = opt_arg(); + break; + case OPT_SUBJ: + subj = opt_arg(); break; case OPT_ADDTRUST: + if (trust == NULL && (trust = sk_ASN1_OBJECT_new_null()) == NULL) + goto end; if ((objtmp = OBJ_txt2obj(opt_arg(), 0)) == NULL) { - BIO_printf(bio_err, - "%s: Invalid trust object value %s\n", + BIO_printf(bio_err, "%s: Invalid trust object value %s\n", prog, opt_arg()); goto opthelp; } - if (trust == NULL && (trust = sk_ASN1_OBJECT_new_null()) == NULL) - goto end; sk_ASN1_OBJECT_push(trust, objtmp); - objtmp = NULL; trustout = 1; break; case OPT_ADDREJECT: + if (reject == NULL && (reject = sk_ASN1_OBJECT_new_null()) == NULL) + goto end; if ((objtmp = OBJ_txt2obj(opt_arg(), 0)) == NULL) { - BIO_printf(bio_err, - "%s: Invalid reject object value %s\n", + BIO_printf(bio_err, "%s: Invalid reject object value %s\n", prog, opt_arg()); goto opthelp; } - if (reject == NULL - && (reject = sk_ASN1_OBJECT_new_null()) == NULL) - goto end; sk_ASN1_OBJECT_push(reject, objtmp); - objtmp = NULL; trustout = 1; break; case OPT_SETALIAS: @@ -326,9 +463,6 @@ int x509_main(int argc, char **argv) case OPT_ENGINE: e = setup_engine(opt_arg(), 0); break; - case OPT_C: - C = ++num; - break; case OPT_EMAIL: email = ++num; break; @@ -345,10 +479,10 @@ int x509_main(int argc, char **argv) modulus = ++num; break; case OPT_PUBKEY: - pubkey = ++num; + print_pubkey = ++num; break; case OPT_X509TOREQ: - x509req = ++num; + x509toreq = 1; break; case OPT_TEXT: text = ++num; @@ -382,7 +516,7 @@ int x509_main(int argc, char **argv) break; case OPT_EXT: ext = ++num; - exts = opt_arg(); + ext_names = opt_arg(); break; case OPT_NOCERT: nocert = 1; @@ -430,12 +564,12 @@ int x509_main(int argc, char **argv) case OPT_CHECKEND: checkend = 1; { - intmax_t temp = 0; - if (!opt_imax(opt_arg(), &temp)) + ossl_intmax_t temp = 0; + if (!opt_intmax(opt_arg(), &temp)) goto opthelp; checkoffset = (time_t)temp; - if ((intmax_t)checkoffset != temp) { - BIO_printf(bio_err, "%s: checkend time out of range %s\n", + if ((ossl_intmax_t)checkoffset != temp) { + BIO_printf(bio_err, "%s: Checkend time out of range %s\n", prog, opt_arg()); goto opthelp; } @@ -451,48 +585,103 @@ int x509_main(int argc, char **argv) checkip = opt_arg(); break; case OPT_PRESERVE_DATES: - if (days != DEF_DAYS) - goto opthelp; preserve_dates = 1; break; case OPT_MD: - if (!opt_md(opt_unknown(), &digest)) - goto opthelp; + digest = opt_unknown(); + break; } } + + /* No extra arguments. */ argc = opt_num_rest(); - argv = opt_rest(); - if (argc != 0) { - BIO_printf(bio_err, "%s: Unknown parameter %s\n", prog, argv[0]); + if (argc != 0) goto opthelp; + + if (!app_RAND_load()) + goto end; + + if (preserve_dates && days != UNSET_DAYS) { + BIO_printf(bio_err, "Cannot use -preserve_dates with -days option\n"); + goto end; } + if (days == UNSET_DAYS) + days = DEFAULT_DAYS; if (!app_passwd(passinarg, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } - if (!X509_STORE_set_default_paths(ctx)) { - ERR_print_errors(bio_err); + if (!X509_STORE_set_default_paths_ex(ctx, app_get0_libctx(), + app_get0_propq())) + goto end; + + if (newcert && infile != NULL) { + BIO_printf(bio_err, "The -in option cannot be used with -new\n"); + goto end; + } + if (newcert && reqfile) { + BIO_printf(bio_err, + "The -req option cannot be used with -new\n"); goto end; } + if (privkeyfile != NULL) { + privkey = load_key(privkeyfile, keyformat, 0, passin, e, "private key"); + if (privkey == NULL) + goto end; + } + if (pubkeyfile != NULL) { + if ((pubkey = load_pubkey(pubkeyfile, keyformat, 0, NULL, e, + "explicitly set public key")) == NULL) + goto end; + } - if (fkeyfile != NULL) { - fkey = load_pubkey(fkeyfile, keyformat, 0, NULL, e, "Forced key"); - if (fkey == NULL) + if (newcert) { + if (subj == NULL) { + BIO_printf(bio_err, + "The -new option requires a subject to be set using -subj\n"); goto end; + } + if (privkeyfile == NULL && pubkeyfile == NULL) { + BIO_printf(bio_err, + "The -new option requires using the -key or -force_pubkey option\n"); + goto end; + } } + if (subj != NULL + && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL) + goto end; - if ((CAkeyfile == NULL) && (CA_flag) && (CAformat == FORMAT_PEM)) { + if (CAkeyfile == NULL) CAkeyfile = CAfile; - } else if ((CA_flag) && (CAkeyfile == NULL)) { - BIO_printf(bio_err, - "need to specify a CAkey if using the CA command\n"); - goto end; + if (CAfile != NULL) { + if (privkeyfile != NULL) { + BIO_printf(bio_err, "Cannot use both -key/-signkey and -CA option\n"); + goto end; + } + } else { +#define WARN_NO_CA(opt) BIO_printf(bio_err, \ + "Warning: ignoring " opt " option since -CA option is not given\n"); + if (CAkeyfile != NULL) + WARN_NO_CA("-CAkey"); + if (CAkeyformat != FORMAT_UNDEF) + WARN_NO_CA("-CAkeyform"); + if (CAformat != FORMAT_UNDEF) + WARN_NO_CA("-CAform"); + if (CAserial != NULL) + WARN_NO_CA("-CAserial"); + if (CA_createserial) + WARN_NO_CA("-CAcreateserial"); } - if (extfile != NULL) { + if (extfile == NULL) { + if (extsect != NULL) + BIO_printf(bio_err, + "Warning: ignoring -extensions option without -extfile\n"); + } else { X509V3_CTX ctx2; + if ((extconf = app_load_config(extfile)) == NULL) goto end; if (extsect == NULL) { @@ -506,92 +695,79 @@ int x509_main(int argc, char **argv) X509V3_set_nconf(&ctx2, extconf); if (!X509V3_EXT_add_nconf(extconf, &ctx2, extsect, NULL)) { BIO_printf(bio_err, - "Error Loading extension section %s\n", extsect); - ERR_print_errors(bio_err); + "Error checking extension section %s\n", extsect); goto end; } } if (reqfile) { - EVP_PKEY *pkey; - BIO *in; - - if (!sign_flag && !CA_flag) { - BIO_printf(bio_err, "We need a private key to sign with\n"); + req = load_csr(infile, informat, "certificate request input"); + if (req == NULL) goto end; - } - in = bio_open_default(infile, 'r', informat); - if (in == NULL) - goto end; - req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); - BIO_free(in); - - if (req == NULL) { - ERR_print_errors(bio_err); - goto end; - } if ((pkey = X509_REQ_get0_pubkey(req)) == NULL) { - BIO_printf(bio_err, "error unpacking public key\n"); + BIO_printf(bio_err, "Error unpacking public key from CSR\n"); goto end; } - i = X509_REQ_verify(req, pkey); - if (i < 0) { - BIO_printf(bio_err, "Signature verification error\n"); - ERR_print_errors(bio_err); + i = do_X509_REQ_verify(req, pkey, vfyopts); + if (i <= 0) { + BIO_printf(bio_err, i < 0 + ? "Error while verifying certificate request self-signature\n" + : "Certificate request self-signature did not match the contents\n"); goto end; } - if (i == 0) { + BIO_printf(bio_err, "Certificate request self-signature ok\n"); + + print_name(bio_err, "subject=", X509_REQ_get_subject_name(req)); + } else if (!x509toreq && ext_copy != EXT_COPY_UNSET) { + BIO_printf(bio_err, "Warning: ignoring -copy_extensions since neither -x509toreq nor -req is given\n"); + } + + if (reqfile || newcert) { + if (preserve_dates) BIO_printf(bio_err, - "Signature did not match the certificate request\n"); + "Warning: ignoring -preserve_dates option with -req or -new\n"); + preserve_dates = 0; + if (privkeyfile == NULL && CAkeyfile == NULL) { + BIO_printf(bio_err, + "We need a private key to sign with, use -key or -CAkey or -CA with private key\n"); goto end; - } else { - BIO_printf(bio_err, "Signature ok\n"); } - - print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), - get_nameopt()); - - if ((x = X509_new()) == NULL) + if ((x = X509_new_ex(app_get0_libctx(), app_get0_propq())) == NULL) goto end; - - if (sno == NULL) { + if (CAfile == NULL && sno == NULL) { sno = ASN1_INTEGER_new(); if (sno == NULL || !rand_serial(NULL, sno)) goto end; - if (!X509_set_serialNumber(x, sno)) - goto end; - ASN1_INTEGER_free(sno); - sno = NULL; - } else if (!X509_set_serialNumber(x, sno)) { - goto end; } - - if (!X509_set_issuer_name(x, X509_REQ_get_subject_name(req))) - goto end; - if (!X509_set_subject_name(x, X509_REQ_get_subject_name(req))) - goto end; - if (!set_cert_times(x, NULL, NULL, days)) - goto end; - - if (fkey != NULL) { - X509_set_pubkey(x, fkey); - } else { - pkey = X509_REQ_get0_pubkey(req); - X509_set_pubkey(x, pkey); + if (req != NULL && ext_copy != EXT_COPY_UNSET) { + if (clrext && ext_copy != EXT_COPY_NONE) { + BIO_printf(bio_err, "Must not use -clrext together with -copy_extensions\n"); + goto end; + } else if (!copy_extensions(x, req, ext_copy)) { + BIO_printf(bio_err, "Error copying extensions from request\n"); + goto end; + } } } else { - x = load_cert(infile, informat, "Certificate"); + x = load_cert_pass(infile, informat, 1, passin, "certificate"); + if (x == NULL) + goto end; } - - if (x == NULL) + if ((fsubj != NULL || req != NULL) + && !X509_set_subject_name(x, fsubj != NULL ? fsubj : + X509_REQ_get_subject_name(req))) goto end; - if (CA_flag) { - xca = load_cert(CAfile, CAformat, "CA Certificate"); + if ((pubkey != NULL || privkey != NULL || req != NULL) + && !X509_set_pubkey(x, pubkey != NULL ? pubkey : + privkey != NULL ? privkey : + X509_REQ_get0_pubkey(req))) + goto end; + + if (CAfile != NULL) { + xca = load_cert_pass(CAfile, CAformat, 1, passin, "CA certificate"); if (xca == NULL) goto end; - if (reqfile && !X509_set_issuer_name(x, X509_get_subject_name(xca))) - goto end; } out = bio_open_default(outfile, 'w', outformat); @@ -610,21 +786,120 @@ int x509_main(int argc, char **argv) X509_reject_clear(x); if (trust != NULL) { - for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) { - objtmp = sk_ASN1_OBJECT_value(trust, i); - X509_add1_trust_object(x, objtmp); - } - objtmp = NULL; + for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) + X509_add1_trust_object(x, sk_ASN1_OBJECT_value(trust, i)); } if (reject != NULL) { - for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) { - objtmp = sk_ASN1_OBJECT_value(reject, i); - X509_add1_reject_object(x, objtmp); + for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) + X509_add1_reject_object(x, sk_ASN1_OBJECT_value(reject, i)); + } + + if (clrext && ext_names != NULL) + BIO_printf(bio_err, "Warning: Ignoring -ext since -clrext is given\n"); + for (i = X509_get_ext_count(x) - 1; i >= 0; i--) { + X509_EXTENSION *ex = X509_get_ext(x, i); + const char *sn = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ex))); + + if (clrext || (ext_names != NULL && strstr(ext_names, sn) == NULL)) + X509_EXTENSION_free(X509_delete_ext(x, i)); + } + + issuer_cert = x; + if (CAfile != NULL) { + issuer_cert = xca; + if (sno == NULL) + sno = x509_load_serial(CAfile, CAserial, CA_createserial); + if (sno == NULL) + goto end; + if (!x509toreq && !reqfile && !newcert && !self_signed(ctx, x)) + goto end; + } + + if (sno != NULL && !X509_set_serialNumber(x, sno)) + goto end; + + if (reqfile || newcert || privkey != NULL || CAfile != NULL) { + if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) + goto end; + if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert))) + goto end; + } + + X509V3_set_ctx(&ext_ctx, issuer_cert, x, NULL, NULL, X509V3_CTX_REPLACE); + /* prepare fallback for AKID, but only if issuer cert equals subject cert */ + if (CAfile == NULL) { + if (!X509V3_set_issuer_pkey(&ext_ctx, privkey)) + goto end; + } + if (extconf != NULL && !x509toreq) { + X509V3_set_nconf(&ext_ctx, extconf); + if (!X509V3_EXT_add_nconf(extconf, &ext_ctx, extsect, x)) { + BIO_printf(bio_err, + "Error adding extensions from section %s\n", extsect); + goto end; } - objtmp = NULL; } + /* At this point the contents of the certificate x have been finished. */ + + pkey = X509_get0_pubkey(x); + if ((print_pubkey != 0 || modulus != 0) && pkey == NULL) { + BIO_printf(bio_err, "Error getting public key\n"); + goto end; + } + + if (x509toreq) { /* also works in conjunction with -req */ + if (privkey == NULL) { + BIO_printf(bio_err, "Must specify request signing key using -key\n"); + goto end; + } + if (clrext && ext_copy != EXT_COPY_NONE) { + BIO_printf(bio_err, "Must not use -clrext together with -copy_extensions\n"); + goto end; + } + if ((rq = x509_to_req(x, ext_copy, ext_names)) == NULL) + goto end; + if (extconf != NULL) { + X509V3_set_nconf(&ext_ctx, extconf); + if (!X509V3_EXT_REQ_add_nconf(extconf, &ext_ctx, extsect, rq)) { + BIO_printf(bio_err, + "Error adding request extensions from section %s\n", extsect); + goto end; + } + } + if (!do_X509_REQ_sign(rq, privkey, digest, sigopts)) + goto end; + if (!noout) { + if (outformat == FORMAT_ASN1) { + X509_REQ_print_ex(out, rq, get_nameopt(), X509_FLAG_COMPAT); + i = i2d_X509_bio(out, x); + } else { + i = PEM_write_bio_X509_REQ(out, rq); + } + if (!i) { + BIO_printf(bio_err, + "Unable to write certificate request\n"); + goto end; + } + } + noout = 1; + } else if (privkey != NULL) { + if (!do_X509_sign(x, privkey, digest, sigopts, &ext_ctx)) + goto end; + } else if (CAfile != NULL) { + if ((CAkey = load_key(CAkeyfile, CAkeyformat, + 0, passin, e, "CA private key")) == NULL) + goto end; + if (!X509_check_private_key(xca, CAkey)) { + BIO_printf(bio_err, + "CA certificate and CA private key do not match\n"); + goto end; + } + + if (!do_X509_sign(x, CAkey, digest, sigopts, &ext_ctx)) + goto end; + } if (badsig) { const ASN1_BIT_STRING *signature; @@ -632,236 +907,133 @@ int x509_main(int argc, char **argv) corrupt_signature(signature); } - if (num) { - for (i = 1; i <= num; i++) { - if (issuer == i) { - print_name(out, "issuer=", X509_get_issuer_name(x), get_nameopt()); - } else if (subject == i) { - print_name(out, "subject=", - X509_get_subject_name(x), get_nameopt()); - } else if (serial == i) { - BIO_printf(out, "serial="); - i2a_ASN1_INTEGER(out, X509_get_serialNumber(x)); - BIO_printf(out, "\n"); - } else if (next_serial == i) { - ASN1_INTEGER *ser = X509_get_serialNumber(x); - BIGNUM *bnser = ASN1_INTEGER_to_BN(ser, NULL); - - if (!bnser) - goto end; - if (!BN_add_word(bnser, 1)) - goto end; - ser = BN_to_ASN1_INTEGER(bnser, NULL); - if (!ser) - goto end; + /* Process print options in the given order, as indicated by index i */ + for (i = 1; i <= num; i++) { + if (i == issuer) { + print_name(out, "issuer=", X509_get_issuer_name(x)); + } else if (i == subject) { + print_name(out, "subject=", X509_get_subject_name(x)); + } else if (i == serial) { + BIO_printf(out, "serial="); + i2a_ASN1_INTEGER(out, X509_get0_serialNumber(x)); + BIO_printf(out, "\n"); + } else if (i == next_serial) { + ASN1_INTEGER *ser; + BIGNUM *bnser = ASN1_INTEGER_to_BN(X509_get0_serialNumber(x), NULL); + + if (bnser == NULL) + goto end; + if (!BN_add_word(bnser, 1) + || (ser = BN_to_ASN1_INTEGER(bnser, NULL)) == NULL) { BN_free(bnser); - i2a_ASN1_INTEGER(out, ser); - ASN1_INTEGER_free(ser); - BIO_puts(out, "\n"); - } else if ((email == i) || (ocsp_uri == i)) { - int j; - STACK_OF(OPENSSL_STRING) *emlst; - if (email == i) - emlst = X509_get1_email(x); - else - emlst = X509_get1_ocsp(x); - for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++) - BIO_printf(out, "%s\n", - sk_OPENSSL_STRING_value(emlst, j)); - X509_email_free(emlst); - } else if (aliasout == i) { - unsigned char *alstr; - alstr = X509_alias_get0(x, NULL); - if (alstr) - BIO_printf(out, "%s\n", alstr); - else - BIO_puts(out, "<No Alias>\n"); - } else if (subject_hash == i) { - BIO_printf(out, "%08lx\n", X509_subject_name_hash(x)); + goto end; } + BN_free(bnser); + i2a_ASN1_INTEGER(out, ser); + ASN1_INTEGER_free(ser); + BIO_puts(out, "\n"); + } else if (i == email || i == ocsp_uri) { + STACK_OF(OPENSSL_STRING) *emlst = + i == email ? X509_get1_email(x) : X509_get1_ocsp(x); + + for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++) + BIO_printf(out, "%s\n", sk_OPENSSL_STRING_value(emlst, j)); + X509_email_free(emlst); + } else if (i == aliasout) { + unsigned char *alstr = X509_alias_get0(x, NULL); + + if (alstr) + BIO_printf(out, "%s\n", alstr); + else + BIO_puts(out, "<No Alias>\n"); + } else if (i == subject_hash) { + BIO_printf(out, "%08lx\n", X509_subject_name_hash(x)); #ifndef OPENSSL_NO_MD5 - else if (subject_hash_old == i) { - BIO_printf(out, "%08lx\n", X509_subject_name_hash_old(x)); - } + } else if (i == subject_hash_old) { + BIO_printf(out, "%08lx\n", X509_subject_name_hash_old(x)); #endif - else if (issuer_hash == i) { - BIO_printf(out, "%08lx\n", X509_issuer_name_hash(x)); - } + } else if (i == issuer_hash) { + BIO_printf(out, "%08lx\n", X509_issuer_name_hash(x)); #ifndef OPENSSL_NO_MD5 - else if (issuer_hash_old == i) { - BIO_printf(out, "%08lx\n", X509_issuer_name_hash_old(x)); - } + } else if (i == issuer_hash_old) { + BIO_printf(out, "%08lx\n", X509_issuer_name_hash_old(x)); #endif - else if (pprint == i) { - X509_PURPOSE *ptmp; - int j; - BIO_printf(out, "Certificate purposes:\n"); - for (j = 0; j < X509_PURPOSE_get_count(); j++) { - ptmp = X509_PURPOSE_get0(j); - purpose_print(out, x, ptmp); - } - } else if (modulus == i) { - EVP_PKEY *pkey; - - pkey = X509_get0_pubkey(x); - if (pkey == NULL) { - BIO_printf(bio_err, "Modulus=unavailable\n"); - ERR_print_errors(bio_err); - goto end; - } - BIO_printf(out, "Modulus="); -#ifndef OPENSSL_NO_RSA - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) { - const BIGNUM *n; - RSA_get0_key(EVP_PKEY_get0_RSA(pkey), &n, NULL, NULL); - BN_print(out, n); - } else -#endif -#ifndef OPENSSL_NO_DSA - if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA) { - const BIGNUM *dsapub = NULL; - DSA_get0_key(EVP_PKEY_get0_DSA(pkey), &dsapub, NULL); - BN_print(out, dsapub); - } else -#endif - { - BIO_printf(out, "Wrong Algorithm type"); - } - BIO_printf(out, "\n"); - } else if (pubkey == i) { - EVP_PKEY *pkey; - - pkey = X509_get0_pubkey(x); - if (pkey == NULL) { - BIO_printf(bio_err, "Error getting public key\n"); - ERR_print_errors(bio_err); - goto end; - } - PEM_write_bio_PUBKEY(out, pkey); - } else if (C == i) { - unsigned char *d; - char *m; - int len; - - print_name(out, "/*\n" - " * Subject: ", X509_get_subject_name(x), get_nameopt()); - print_name(out, " * Issuer: ", X509_get_issuer_name(x), get_nameopt()); - BIO_puts(out, " */\n"); - - len = i2d_X509(x, NULL); - m = app_malloc(len, "x509 name buffer"); - d = (unsigned char *)m; - len = i2d_X509_NAME(X509_get_subject_name(x), &d); - print_array(out, "the_subject_name", len, (unsigned char *)m); - d = (unsigned char *)m; - len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &d); - print_array(out, "the_public_key", len, (unsigned char *)m); - d = (unsigned char *)m; - len = i2d_X509(x, &d); - print_array(out, "the_certificate", len, (unsigned char *)m); - OPENSSL_free(m); - } else if (text == i) { - X509_print_ex(out, x, get_nameopt(), certflag); - } else if (startdate == i) { - BIO_puts(out, "notBefore="); - ASN1_TIME_print(out, X509_get0_notBefore(x)); - BIO_puts(out, "\n"); - } else if (enddate == i) { - BIO_puts(out, "notAfter="); - ASN1_TIME_print(out, X509_get0_notAfter(x)); - BIO_puts(out, "\n"); - } else if (fingerprint == i) { - int j; - unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; - const EVP_MD *fdig = digest; - - if (fdig == NULL) - fdig = EVP_sha1(); - - if (!X509_digest(x, fdig, md, &n)) { - BIO_printf(bio_err, "out of memory\n"); - goto end; - } - BIO_printf(out, "%s Fingerprint=", - OBJ_nid2sn(EVP_MD_type(fdig))); - for (j = 0; j < (int)n; j++) { - BIO_printf(out, "%02X%c", md[j], (j + 1 == (int)n) - ? '\n' : ':'); - } + } else if (i == pprint) { + BIO_printf(out, "Certificate purposes:\n"); + for (j = 0; j < X509_PURPOSE_get_count(); j++) + purpose_print(out, x, X509_PURPOSE_get0(j)); + } else if (i == modulus) { + BIO_printf(out, "Modulus="); + if (EVP_PKEY_is_a(pkey, "RSA") || EVP_PKEY_is_a(pkey, "RSA-PSS")) { + BIGNUM *n = NULL; + + /* Every RSA key has an 'n' */ + EVP_PKEY_get_bn_param(pkey, "n", &n); + BN_print(out, n); + BN_free(n); + } else if (EVP_PKEY_is_a(pkey, "DSA")) { + BIGNUM *dsapub = NULL; + + /* Every DSA key has a 'pub' */ + EVP_PKEY_get_bn_param(pkey, "pub", &dsapub); + BN_print(out, dsapub); + BN_free(dsapub); + } else { + BIO_printf(out, "No modulus for this public key type"); } - - /* should be in the library */ - else if ((sign_flag == i) && (x509req == 0)) { - BIO_printf(bio_err, "Getting Private key\n"); - if (Upkey == NULL) { - Upkey = load_key(keyfile, keyformat, 0, - passin, e, "Private key"); - if (Upkey == NULL) - goto end; - } - - if (!sign(x, Upkey, days, clrext, digest, extconf, extsect, preserve_dates)) - goto end; - } else if (CA_flag == i) { - BIO_printf(bio_err, "Getting CA Private Key\n"); - if (CAkeyfile != NULL) { - CApkey = load_key(CAkeyfile, CAkeyformat, - 0, passin, e, "CA Private Key"); - if (CApkey == NULL) - goto end; - } - - if (!x509_certify(ctx, CAfile, digest, x, xca, - CApkey, sigopts, - CAserial, CA_createserial, days, clrext, - extconf, extsect, sno, reqfile, preserve_dates)) - goto end; - } else if (x509req == i) { - EVP_PKEY *pk; - - BIO_printf(bio_err, "Getting request Private Key\n"); - if (keyfile == NULL) { - BIO_printf(bio_err, "no request key file specified\n"); - goto end; - } else { - pk = load_key(keyfile, keyformat, 0, - passin, e, "request key"); - if (pk == NULL) - goto end; - } - - BIO_printf(bio_err, "Generating certificate request\n"); - - rq = X509_to_X509_REQ(x, pk, digest); - EVP_PKEY_free(pk); - if (rq == NULL) { - ERR_print_errors(bio_err); - goto end; - } - if (!noout) { - X509_REQ_print_ex(out, rq, get_nameopt(), X509_FLAG_COMPAT); - PEM_write_bio_X509_REQ(out, rq); - } - noout = 1; - } else if (ocspid == i) { - X509_ocspid_print(out, x); - } else if (ext == i) { - print_x509v3_exts(out, x, exts); + BIO_printf(out, "\n"); + } else if (i == print_pubkey) { + PEM_write_bio_PUBKEY(out, pkey); + } else if (i == text) { + X509_print_ex(out, x, get_nameopt(), certflag); + } else if (i == startdate) { + BIO_puts(out, "notBefore="); + ASN1_TIME_print_ex(out, X509_get0_notBefore(x), dateopt); + BIO_puts(out, "\n"); + } else if (i == enddate) { + BIO_puts(out, "notAfter="); + ASN1_TIME_print_ex(out, X509_get0_notAfter(x), dateopt); + BIO_puts(out, "\n"); + } else if (i == fingerprint) { + unsigned int n; + unsigned char md[EVP_MAX_MD_SIZE]; + const char *fdigname = digest; + EVP_MD *fdig; + int digres; + + if (fdigname == NULL) + fdigname = "SHA1"; + + if ((fdig = EVP_MD_fetch(app_get0_libctx(), fdigname, + app_get0_propq())) == NULL) { + BIO_printf(bio_err, "Unknown digest\n"); + goto end; + } + digres = X509_digest(x, fdig, md, &n); + EVP_MD_free(fdig); + if (!digres) { + BIO_printf(bio_err, "Out of memory\n"); + goto end; } + + BIO_printf(out, "%s Fingerprint=", fdigname); + for (j = 0; j < (int)n; j++) + BIO_printf(out, "%02X%c", md[j], (j + 1 == (int)n) ? '\n' : ':'); + } else if (i == ocspid) { + X509_ocspid_print(out, x); + } else if (i == ext) { + print_x509v3_exts(out, x, ext_names); } } if (checkend) { time_t tcheck = time(NULL) + checkoffset; - if (X509_cmp_time(X509_get0_notAfter(x), &tcheck) < 0) { + ret = X509_cmp_time(X509_get0_notAfter(x), &tcheck) < 0; + if (ret) BIO_printf(out, "Certificate will expire\n"); - ret = 1; - } else { + else BIO_printf(out, "Certificate will not expire\n"); - ret = 0; - } goto end; } @@ -880,33 +1052,36 @@ int x509_main(int argc, char **argv) else i = PEM_write_bio_X509(out, x); } else { - BIO_printf(bio_err, "bad output format specified for outfile\n"); + BIO_printf(bio_err, "Bad output format specified for outfile\n"); goto end; } if (!i) { - BIO_printf(bio_err, "unable to write certificate\n"); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Unable to write certificate\n"); goto end; } ret = 0; + end: + if (ret != 0) + ERR_print_errors(bio_err); NCONF_free(extconf); BIO_free_all(out); X509_STORE_free(ctx); + X509_NAME_free(fsubj); X509_REQ_free(req); X509_free(x); X509_free(xca); - EVP_PKEY_free(Upkey); - EVP_PKEY_free(CApkey); - EVP_PKEY_free(fkey); + EVP_PKEY_free(privkey); + EVP_PKEY_free(CAkey); + EVP_PKEY_free(pubkey); sk_OPENSSL_STRING_free(sigopts); + sk_OPENSSL_STRING_free(vfyopts); X509_REQ_free(rq); ASN1_INTEGER_free(sno); sk_ASN1_OBJECT_pop_free(trust, ASN1_OBJECT_free); sk_ASN1_OBJECT_pop_free(reject, ASN1_OBJECT_free); - ASN1_OBJECT_free(objtmp); release_engine(e); - OPENSSL_free(passin); + clear_free(passin); return ret; } @@ -934,7 +1109,7 @@ static ASN1_INTEGER *x509_load_serial(const char *CAfile, goto end; if (!BN_add_word(serial, 1)) { - BIO_printf(bio_err, "add_word failure\n"); + BIO_printf(bio_err, "Serial number increment failure\n"); goto end; } @@ -949,92 +1124,14 @@ static ASN1_INTEGER *x509_load_serial(const char *CAfile, return bs; } -static int x509_certify(X509_STORE *ctx, const char *CAfile, const EVP_MD *digest, - X509 *x, X509 *xca, EVP_PKEY *pkey, - STACK_OF(OPENSSL_STRING) *sigopts, - const char *serialfile, int create, - int days, int clrext, CONF *conf, const char *section, - ASN1_INTEGER *sno, int reqfile, int preserve_dates) -{ - int ret = 0; - ASN1_INTEGER *bs = NULL; - X509_STORE_CTX *xsc = NULL; - EVP_PKEY *upkey; - - upkey = X509_get0_pubkey(xca); - if (upkey == NULL) { - BIO_printf(bio_err, "Error obtaining CA X509 public key\n"); - goto end; - } - EVP_PKEY_copy_parameters(upkey, pkey); - - xsc = X509_STORE_CTX_new(); - if (xsc == NULL || !X509_STORE_CTX_init(xsc, ctx, x, NULL)) { - BIO_printf(bio_err, "Error initialising X509 store\n"); - goto end; - } - if (sno) - bs = sno; - else if ((bs = x509_load_serial(CAfile, serialfile, create)) == NULL) - goto end; - - /* - * NOTE: this certificate can/should be self signed, unless it was a - * certificate request in which case it is not. - */ - X509_STORE_CTX_set_cert(xsc, x); - X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_CHECK_SS_SIGNATURE); - if (!reqfile && X509_verify_cert(xsc) <= 0) - goto end; - - if (!X509_check_private_key(xca, pkey)) { - BIO_printf(bio_err, - "CA certificate and CA private key do not match\n"); - goto end; - } - - if (!X509_set_issuer_name(x, X509_get_subject_name(xca))) - goto end; - if (!X509_set_serialNumber(x, bs)) - goto end; - - if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) - goto end; - - if (clrext) { - while (X509_get_ext_count(x) > 0) - X509_delete_ext(x, 0); - } - - if (conf != NULL) { - X509V3_CTX ctx2; - X509_set_version(x, 2); /* version 3 certificate */ - X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0); - X509V3_set_nconf(&ctx2, conf); - if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x)) - goto end; - } - - if (!do_X509_sign(x, pkey, digest, sigopts)) - goto end; - ret = 1; - end: - X509_STORE_CTX_free(xsc); - if (!ret) - ERR_print_errors(bio_err); - if (!sno) - ASN1_INTEGER_free(bs); - return ret; -} - static int callb(int ok, X509_STORE_CTX *ctx) { int err; X509 *err_cert; /* - * it is ok to use a self signed certificate This case will catch both - * the initial ok == 0 and the final ok == 1 calls to this function + * It is ok to use a self-signed certificate. This case will catch both + * the initial ok == 0 and the final ok == 1 calls to this function. */ err = X509_STORE_CTX_get_error(ctx); if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) @@ -1047,51 +1144,19 @@ static int callb(int ok, X509_STORE_CTX *ctx) */ if (ok) { BIO_printf(bio_err, - "error with certificate to be certified - should be self signed\n"); + "Error with certificate to be certified - should be self-signed\n"); return 0; } else { err_cert = X509_STORE_CTX_get_current_cert(ctx); - print_name(bio_err, NULL, X509_get_subject_name(err_cert), 0); + print_name(bio_err, "subject=", X509_get_subject_name(err_cert)); BIO_printf(bio_err, - "error with certificate - error %d at depth %d\n%s\n", err, + "Error with certificate - error %d at depth %d\n%s\n", err, X509_STORE_CTX_get_error_depth(ctx), X509_verify_cert_error_string(err)); return 1; } } -/* self sign */ -static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, - const EVP_MD *digest, CONF *conf, const char *section, - int preserve_dates) -{ - - if (!X509_set_issuer_name(x, X509_get_subject_name(x))) - goto err; - if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) - goto err; - if (!X509_set_pubkey(x, pkey)) - goto err; - if (clrext) { - while (X509_get_ext_count(x) > 0) - X509_delete_ext(x, 0); - } - if (conf != NULL) { - X509V3_CTX ctx; - X509_set_version(x, 2); /* version 3 certificate */ - X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0); - X509V3_set_nconf(&ctx, conf); - if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) - goto err; - } - if (!X509_sign(x, pkey, digest)) - goto err; - return 1; - err: - ERR_print_errors(bio_err); - return 0; -} - static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt) { int id, i, idret; @@ -1150,7 +1215,7 @@ static int print_x509v3_exts(BIO *bio, X509 *x, const char *ext_names) exts = X509_get0_extensions(x); if ((num = sk_X509_EXTENSION_num(exts)) <= 0) { - BIO_printf(bio, "No extensions in certificate\n"); + BIO_printf(bio_err, "No extensions in certificate\n"); ret = 1; goto end; } |