From: Dr. David von Oheimb Date: Fri, 27 Sep 2024 05:58:33 +0000 (+0200) Subject: APPS/pkcs8: fix case where infile and outfile are the same X-Git-Tag: openssl-3.5.0-alpha1~1056 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5c4a8aecca691506824326f43be06ad36216c11;p=thirdparty%2Fopenssl.git APPS/pkcs8: fix case where infile and outfile are the same Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/25552) --- diff --git a/apps/pkcs8.c b/apps/pkcs8.c index 7b5e79966ba..22978afb909 100644 --- a/apps/pkcs8.c +++ b/apps/pkcs8.c @@ -227,9 +227,6 @@ int pkcs8_main(int argc, char **argv) informat == FORMAT_UNDEF ? FORMAT_PEM : informat); if (in == NULL) goto end; - out = bio_open_owner(outfile, outformat, private); - if (out == NULL) - goto end; if (topk8) { pkey = load_key(infile, informat, 1, passin, e, "key"); @@ -240,6 +237,8 @@ int pkcs8_main(int argc, char **argv) ERR_print_errors(bio_err); goto end; } + if ((out = bio_open_owner(outfile, outformat, private)) == NULL) + goto end; if (nocrypt) { assert(private); if (outformat == FORMAT_PEM) { @@ -361,6 +360,9 @@ int pkcs8_main(int argc, char **argv) } assert(private); + out = bio_open_owner(outfile, outformat, private); + if (out == NULL) + goto end; if (outformat == FORMAT_PEM) { if (traditional) PEM_write_bio_PrivateKey_traditional(out, pkey, NULL, NULL, 0, diff --git a/doc/man1/openssl-pkcs8.pod.in b/doc/man1/openssl-pkcs8.pod.in index 08c3272a70a..db089d6777d 100644 --- a/doc/man1/openssl-pkcs8.pod.in +++ b/doc/man1/openssl-pkcs8.pod.in @@ -79,9 +79,9 @@ key is written. =item B<-in> I -This specifies the input filename to read a key from or standard input if this +This specifies the input file to read a key from or standard input if this option is not specified. If the key is encrypted a pass phrase will be -prompted for. +prompted for unless B<-passin> is given. =item B<-passin> I, B<-passout> I @@ -91,10 +91,14 @@ see L. =item B<-out> I -This specifies the output filename to write a key to or standard output by -default. If any encryption options are set then a pass phrase will be -prompted for. The output filename should B be the same as the input -filename. +This specifies the output file to write a key to or standard output by default. +The output filename can be the same as the input filename, +which leads to replacing the file contents. +Note that file I/O is not atomic. The output file is truncated and then written. + +If any encryption options are set and B<-passout> is not given +then a pass phrase will be prompted for. +When password input is interrupted, the output file is not touched. =item B<-iter> I diff --git a/test/recipes/25-test_pkcs8.t b/test/recipes/25-test_pkcs8.t index 93cb7629bf9..a0f86447448 100644 --- a/test/recipes/25-test_pkcs8.t +++ b/test/recipes/25-test_pkcs8.t @@ -10,15 +10,29 @@ use strict; use warnings; use OpenSSL::Test::Utils; -use File::Compare qw(compare_text); +use File::Copy; +use File::Compare qw(compare_text compare); use OpenSSL::Test qw/:DEFAULT srctop_file ok_nofips is_nofips/; setup("test_pkcs8"); -plan tests => 15; +plan tests => 18; + +my $pc5_key = srctop_file('test', 'certs', 'pc5-key.pem'); + +my $inout = 'inout.pem'; +copy($pc5_key, $inout); +ok(run(app(['openssl', 'pkcs8', '-topk8', '-in', $inout, + '-out', $inout, '-passout', 'pass:password'])), + "identical infile and outfile, to PKCS#8"); +ok(run(app(['openssl', 'pkcs8', '-in', $inout, + '-out', $inout, '-passin', 'pass:password'])), + "identical infile and outfile, from PKCS#8"); +is(compare($pc5_key, $inout), 0, + "Same file contents after converting forth and back"); ok(run(app(([ 'openssl', 'pkcs8', '-topk8', - '-in', srctop_file('test', 'certs', 'pc5-key.pem'), + '-in', $pc5_key, '-out', 'pbkdf2_default_saltlen.pem', '-passout', 'pass:password']))), "Convert a private key to PKCS5 v2.0 format using PBKDF2 with the default saltlen"); @@ -35,7 +49,7 @@ SKIP: { if disabled("scrypt"); ok(run(app(([ 'openssl', 'pkcs8', '-topk8', - '-in', srctop_file('test', 'certs', 'pc5-key.pem'), + '-in', $pc5_key, '-scrypt', '-out', 'scrypt_default_saltlen.pem', '-passout', 'pass:password']))), @@ -49,7 +63,7 @@ SKIP: { "Check the default size of the SCRYPT PARAM 'salt length' = 16"); ok(run(app(([ 'openssl', 'pkcs8', '-topk8', - '-in', srctop_file('test', 'certs', 'pc5-key.pem'), + '-in', $pc5_key, '-scrypt', '-saltlen', '8', '-out', 'scrypt_64bit_saltlen.pem', @@ -69,7 +83,7 @@ SKIP: { if disabled('legacy') || disabled("des"); ok(run(app(([ 'openssl', 'pkcs8', '-topk8', - '-in', srctop_file('test', 'certs', 'pc5-key.pem'), + '-in', $pc5_key, '-v1', "PBE-MD5-DES", '-provider', 'legacy', '-provider', 'default', @@ -83,7 +97,7 @@ SKIP: { "Check the default size of the PBE PARAM 'salt length' = 8"); ok(run(app(([ 'openssl', 'pkcs8', '-topk8', - '-in', srctop_file('test', 'certs', 'pc5-key.pem'), + '-in', $pc5_key, '-v1', "PBE-MD5-DES", '-saltlen', '16', '-provider', 'legacy', @@ -100,7 +114,7 @@ SKIP: { ok(run(app(([ 'openssl', 'pkcs8', '-topk8', - '-in', srctop_file('test', 'certs', 'pc5-key.pem'), + '-in', $pc5_key, '-saltlen', '8', '-out', 'pbkdf2_64bit_saltlen.pem', '-passout', 'pass:password']))),