diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/CA.pl.in | 260 | ||||
-rw-r--r-- | apps/cmp.c | 4 | ||||
-rw-r--r-- | apps/cms.c | 2 | ||||
-rw-r--r-- | apps/lib/apps.c | 5 | ||||
-rw-r--r-- | apps/lib/http_server.c | 4 | ||||
-rw-r--r-- | apps/ocsp.c | 6 | ||||
-rw-r--r-- | apps/pkeyutl.c | 3 | ||||
-rw-r--r-- | apps/s_time.c | 6 | ||||
-rw-r--r-- | apps/storeutl.c | 6 |
9 files changed, 225 insertions, 71 deletions
diff --git a/apps/CA.pl.in b/apps/CA.pl.in index f029470005d9..0bad37d46955 100644 --- a/apps/CA.pl.in +++ b/apps/CA.pl.in @@ -1,5 +1,5 @@ #!{- $config{HASHBANGPERL} -} -# Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2000-2025 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 @@ -19,14 +19,17 @@ my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); my $openssl = $ENV{'OPENSSL'} // "openssl"; $ENV{'OPENSSL'} = $openssl; +my @openssl = split_val($openssl); + my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // ""; +my @OPENSSL_CONFIG = split_val($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"; +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 values for various configuration settings. my $CATOP = "./demoCA"; @@ -34,8 +37,10 @@ my $CAKEY = "cakey.pem"; my $CAREQ = "careq.pem"; my $CACERT = "cacert.pem"; my $CACRL = "crl.pem"; -my $DAYS = "-days 365"; -my $CADAYS = "-days 1095"; # 3 years +my @DAYS = qw(-days 365); +my @CADAYS = qw(-days 1095); # 3 years +my @EXTENSIONS = qw(-extensions v3_ca); +my @POLICY = qw(-policy policy_anything); my $NEWKEY = "newkey.pem"; my $NEWREQ = "newreq.pem"; my $NEWCERT = "newcert.pem"; @@ -43,31 +48,177 @@ my $NEWP12 = "newcert.p12"; # Commandline parsing my %EXTRA; -my $WHAT = shift @ARGV || ""; +my $WHAT = shift @ARGV // ""; @ARGV = parse_extra(@ARGV); my $RET = 0; +sub split_val { + return split_val_win32(@_) if ($^O eq 'MSWin32'); + my ($val) = @_; + my (@ret, @frag); + + # Skip leading whitespace + $val =~ m{\A[ \t]*}ogc; + + # Unix shell-compatible split + # + # Handles backslash escapes outside quotes and + # in double-quoted strings. Parameter and + # command-substitution is silently ignored. + # Bare newlines outside quotes and (trailing) backslashes are disallowed. + + while (1) { + last if (pos($val) == length($val)); + + # The first char is never a SPACE or TAB. Possible matches are: + # 1. Ordinary string fragment + # 2. Single-quoted string + # 3. Double-quoted string + # 4. Backslash escape + # 5. Bare backlash or newline (rejected) + # + if ($val =~ m{\G([^'" \t\n\\]+)}ogc) { + # Ordinary string + push @frag, $1; + } elsif ($val =~ m{\G'([^']*)'}ogc) { + # Single-quoted string + push @frag, $1; + } elsif ($val =~ m{\G"}ogc) { + # Double-quoted string + push @frag, ""; + while (1) { + last if ($val =~ m{\G"}ogc); + if ($val =~ m{\G([^"\\]+)}ogcs) { + # literals + push @frag, $1; + } elsif ($val =~ m{\G.(["\`\$\\])}ogc) { + # backslash-escaped special + push @frag, $1; + } elsif ($val =~ m{\G.(.)}ogcs) { + # backslashed non-special + push @frag, "\\$1" unless $1 eq "\n"; + } else { + die sprintf("Malformed quoted string: %s\n", $val); + } + } + } elsif ($val =~ m{\G\\(.)}ogc) { + # Backslash is unconditional escape outside quoted strings + push @frag, $1 unless $1 eq "\n"; + } else { + die sprintf("Bare backslash or newline in: '%s'\n", $val); + } + # Done if at SPACE, TAB or end, otherwise continue current fragment + # + next unless ($val =~ m{\G(?:[ \t]+|\z)}ogcs); + push @ret, join("", splice(@frag)) if (@frag > 0); + } + # Handle final fragment + push @ret, join("", splice(@frag)) if (@frag > 0); + return @ret; +} + +sub split_val_win32 { + my ($val) = @_; + my (@ret, @frag); + + # Skip leading whitespace + $val =~ m{\A[ \t]*}ogc; + + # Windows-compatible split + # See: "Parsing C++ command-line arguments" in: + # https://learn.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-170 + # + # Backslashes are special only when followed by a double-quote + # Pairs of double-quotes make a single double-quote. + # Closing double-quotes may be omitted. + + while (1) { + last if (pos($val) == length($val)); + + # The first char is never a SPACE or TAB. + # 1. Ordinary string fragment + # 2. Double-quoted string + # 3. Backslashes preceding a double-quote + # 4. Literal backslashes + # 5. Bare newline (rejected) + # + if ($val =~ m{\G([^" \t\n\\]+)}ogc) { + # Ordinary string + push @frag, $1; + } elsif ($val =~ m{\G"}ogc) { + # Double-quoted string + push @frag, ""; + while (1) { + if ($val =~ m{\G("+)}ogc) { + # Two double-quotes make one literal double-quote + my $l = length($1); + push @frag, q{"} x int($l/2) if ($l > 1); + next if ($l % 2 == 0); + last; + } + if ($val =~ m{\G([^"\\]+)}ogc) { + push @frag, $1; + } elsif ($val =~ m{\G((?>[\\]+))(?=")}ogc) { + # Backslashes before a double-quote are escapes + my $l = length($1); + push @frag, q{\\} x int($l / 2); + if ($l % 2 == 1) { + ++pos($val); + push @frag, q{"}; + } + } elsif ($val =~ m{\G((?:(?>[\\]+)[^"\\]+)+)}ogc) { + # Backslashes not before a double-quote are not special + push @frag, $1; + } else { + # Tolerate missing closing double-quote + last; + } + } + } elsif ($val =~ m{\G((?>[\\]+))(?=")}ogc) { + my $l = length($1); + push @frag, q{\\} x int($l / 2); + if ($l % 2 == 1) { + ++pos($val); + push @frag, q{"}; + } + } elsif ($val =~ m{\G([\\]+)}ogc) { + # Backslashes not before a double-quote are not special + push @frag, $1; + } else { + die sprintf("Bare newline in: '%s'\n", $val); + } + # Done if at SPACE, TAB or end, otherwise continue current fragment + # + next unless ($val =~ m{\G(?:[ \t]+|\z)}ogcs); + push @ret, join("", splice(@frag)) if (@frag > 0); + } + # Handle final fragment + push @ret, join("", splice(@frag)) if (@frag); + return @ret; +} + # Split out "-extra-CMD value", and return new |@ARGV|. Fill in # |EXTRA{CMD}| with list of values. sub parse_extra { + my @args; foreach ( @OPENSSL_CMDS ) { - $EXTRA{$_} = ''; + $EXTRA{$_} = []; } - - my @result; - while ( scalar(@_) > 0 ) { - my $arg = shift; - if ( $arg !~ m/-extra-([a-z0-9]+)/ ) { - push @result, $arg; + while (@_) { + my $arg = shift(@_); + if ( $arg !~ m{^-extra-(\w+)$} ) { + push @args, split_val($arg); next; } - $arg =~ s/-extra-//; - die("Unknown \"-${arg}-extra\" option, exiting") - unless scalar grep { $arg eq $_ } @OPENSSL_CMDS; - $EXTRA{$arg} .= " " . shift; + $arg = $1; + die "Unknown \"-extra-${arg}\" option, exiting\n" + unless grep { $arg eq $_ } @OPENSSL_CMDS; + die "Missing \"-extra-${arg}\" option value, exiting\n" + unless (@_ > 0); + push @{$EXTRA{$arg}}, split_val(shift(@_)); } - return @result; + return @args; } @@ -110,9 +261,9 @@ sub copy_pemfile # Wrapper around system; useful for debugging. Returns just the exit status sub run { - my $cmd = shift; - print "====\n$cmd\n" if $verbose; - my $status = system($cmd); + my ($cmd, @args) = @_; + print "====\n$cmd @args\n" if $verbose; + my $status = system {$cmd} $cmd, @args; print "==> $status\n====\n" if $verbose; return $status >> 8; } @@ -131,17 +282,15 @@ EOF if ($WHAT eq '-newcert' ) { # create a certificate - $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS" - . " $EXTRA{req}"); + $RET = run(@REQ, qw(-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" - . " $EXTRA{req}"); + $RET = run(@REQ, qw(-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 - $RET = run("$REQ -new $1 -keyout $NEWKEY -out $NEWREQ $DAYS $EXTRA{req}"); + $RET = run(@REQ, "-new", (defined $1 ? ($1,) : ()), "-keyout", $NEWKEY, "-out", $NEWREQ, @{$EXTRA{req}}); print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; } elsif ($WHAT eq '-newca' ) { # create the directory hierarchy @@ -174,48 +323,45 @@ if ($WHAT eq '-newcert' ) { copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); } else { print "Making CA certificate ...\n"; - $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" - . " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0; + $RET = run(@REQ, qw(-new -keyout), "${CATOP}/private/$CAKEY", + "-out", "${CATOP}/$CAREQ", @{$EXTRA{req}}); + $RET = run(@CA, qw(-create_serial -out), "${CATOP}/$CACERT", @CADAYS, + qw(-batch -keyfile), "${CATOP}/private/$CAKEY", "-selfsign", + @EXTENSIONS, "-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" - . " -export -name \"$cname\" $EXTRA{pkcs12}"); - print "PKCS #12 file is in $NEWP12\n" if $RET == 0; + $RET = run(@PKCS12, "-in", $NEWCERT, "-inkey", $NEWKEY, + "-certfile", "${CATOP}/$CACERT", "-out", $NEWP12, + qw(-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 -infiles $NEWREQ $EXTRA{ca}"); + $RET = run(@CA, @POLICY, "-infiles", $NEWREQ, @{$EXTRA{ca}}); } elsif ($WHAT eq '-sign' ) { - $RET = run("$CA -policy policy_anything -out $NEWCERT" - . " -infiles $NEWREQ $EXTRA{ca}"); + $RET = run(@CA, @POLICY, "-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 -infiles $NEWREQ $EXTRA{ca}"); + $RET = run(@CA, @POLICY, "-out", $NEWCERT, @EXTENSIONS, + "-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" - . "-infiles tmp.pem $EXTRA{ca}") if $RET == 0; + $RET = run(@X509, qw(-x509toreq -in), $NEWREQ, "-signkey", $NEWREQ, + qw(-out tmp.pem), @{$EXTRA{x509}}); + $RET = run(@CA, @POLICY, "-out", $NEWCERT, + qw(-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 ); 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}"); + my $status = run(@VERIFY, "-CAfile", "${CATOP}/$CACERT", $file, @{$EXTRA{verify}}); $RET = $status if $status != 0; } } elsif ($WHAT eq '-crl' ) { - $RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL $EXTRA{ca}"); + $RET = run(@CA, qw(-gencrl -out), "${CATOP}/crl/$CACRL", @{$EXTRA{ca}}); print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0; } elsif ($WHAT eq '-revoke' ) { my $cname = $ARGV[0]; @@ -223,10 +369,10 @@ if ($WHAT eq '-newcert' ) { print "Certificate filename is required; reason optional.\n"; exit 1; } - my $reason = $ARGV[1]; - $reason = " -crl_reason $reason" - if defined $reason && crl_reason_ok($reason); - $RET = run("$CA -revoke \"$cname\"" . $reason . $EXTRA{ca}); + my @reason; + @reason = ("-crl_reason", $ARGV[1]) + if defined $ARGV[1] && crl_reason_ok($ARGV[1]); + $RET = run(@CA, "-revoke", $cname, @reason, @{$EXTRA{ca}}); } else { print STDERR "Unknown arg \"$WHAT\"\n"; print STDERR "Use -help for help.\n"; diff --git a/apps/cmp.c b/apps/cmp.c index c479b1549660..cb65277e6ad9 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -878,7 +878,7 @@ static int set_name(const char *str, OSSL_CMP_CTX *ctx, const char *desc) { if (str != NULL) { - X509_NAME *n = parse_name(str, MBSTRING_ASC, 1, desc); + X509_NAME *n = parse_name(str, MBSTRING_UTF8, 1, desc); if (n == NULL) return 0; diff --git a/apps/cms.c b/apps/cms.c index dce227ef2db5..185396ca7b38 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -983,7 +983,7 @@ int cms_main(int argc, char **argv) goto end; pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); - if (kparam != NULL) { + if (pctx != NULL && kparam != NULL) { if (!cms_set_pkey_param(pctx, kparam->param)) goto end; } diff --git a/apps/lib/apps.c b/apps/lib/apps.c index a632b0cff2bf..b4c4148c2ec9 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 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 @@ -1688,6 +1688,9 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) } retdb->dbfname = OPENSSL_strdup(dbfile); + if (retdb->dbfname == NULL) + goto err; + #ifndef OPENSSL_NO_POSIX_IO retdb->dbst = dbst; #endif diff --git a/apps/lib/http_server.c b/apps/lib/http_server.c index 33ae886d4a1c..d2bfa432d966 100644 --- a/apps/lib/http_server.c +++ b/apps/lib/http_server.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 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 @@ -222,7 +222,7 @@ BIO *http_server_init_bio(const char *prog, const char *port) int asock; char name[40]; - snprintf(name, sizeof(name), "[::]:%s", port); /* port may be "0" */ + BIO_snprintf(name, sizeof(name), "[::]:%s", port); /* port may be "0" */ bufbio = BIO_new(BIO_f_buffer()); if (bufbio == NULL) goto err; diff --git a/apps/ocsp.c b/apps/ocsp.c index fb3105da5526..26340805c2b3 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -1,5 +1,5 @@ /* - * Copyright 2001-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2001-2025 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 @@ -1049,6 +1049,10 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req } bs = OCSP_BASICRESP_new(); + if (bs == NULL) { + *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, bs); + goto end; + } thisupd = X509_gmtime_adj(NULL, 0); if (ndays != -1) nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL); diff --git a/apps/pkeyutl.c b/apps/pkeyutl.c index 5e5047137632..caf3f639eae5 100644 --- a/apps/pkeyutl.c +++ b/apps/pkeyutl.c @@ -1,5 +1,5 @@ /* - * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2025 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 @@ -371,6 +371,7 @@ int pkeyutl_main(int argc, char **argv) if (EVP_PKEY_CTX_ctrl_str(ctx, opt, passwd) <= 0) { BIO_printf(bio_err, "%s: Can't set parameter \"%s\":\n", prog, opt); + OPENSSL_free(passwd); goto end; } OPENSSL_free(passwd); diff --git a/apps/s_time.c b/apps/s_time.c index 1a58e19de53f..b77619156261 100644 --- a/apps/s_time.c +++ b/apps/s_time.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 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 @@ -325,8 +325,10 @@ int s_time_main(int argc, char **argv) */ next: - if (!(perform & 2)) + if (!(perform & 2)) { + ret = 0; goto end; + } printf("\n\nNow timing with session id reuse.\n"); /* Get an SSL object so we can reuse the session id */ diff --git a/apps/storeutl.c b/apps/storeutl.c index 30c9915de3e8..96b943bf6dd1 100644 --- a/apps/storeutl.c +++ b/apps/storeutl.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2025 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 @@ -198,9 +198,7 @@ int storeutl_main(int argc, char *argv[]) } break; case OPT_CRITERION_FINGERPRINT: - if (criterion != 0 - || (criterion == OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT - && fingerprint != NULL)) { + if (criterion != 0) { BIO_printf(bio_err, "%s: criterion already given.\n", prog); goto end; |