]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
genpkey: Avoid leaving empty file if encryption passphrase does not match
authorshridhar kalavagunta <coolshrid@hotmail.com>
Thu, 28 Nov 2024 17:30:50 +0000 (11:30 -0600)
committerTomas Mraz <tomas@openssl.org>
Wed, 15 Jan 2025 12:26:41 +0000 (13:26 +0100)
Fixes #25440

Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26081)

apps/genpkey.c
apps/include/apps.h
apps/lib/apps.c

index 9a4cf622ce3fe750c840f039ca9af9cd630f02c7..53e5def6f9fad904adfc435d8077fb8313047d00 100644 (file)
@@ -106,7 +106,7 @@ cleanup:
 int genpkey_main(int argc, char **argv)
 {
     CONF *conf = NULL;
-    BIO *in = NULL, *out = NULL, *outpubkey = NULL;
+    BIO *mem_out = NULL, *mem_outpubkey = NULL;
     ENGINE *e = NULL;
     EVP_PKEY *pkey = NULL;
     EVP_PKEY_CTX *ctx = NULL;
@@ -237,14 +237,16 @@ int genpkey_main(int argc, char **argv)
         goto end;
     }
 
-    out = bio_open_owner(outfile, outformat, private);
-    if (out == NULL)
+    mem_out = BIO_new(BIO_s_mem());
+    if (mem_out == NULL)
         goto end;
+    BIO_set_mem_eof_return(mem_out, 0);
 
     if (outpubkeyfile != NULL) {
-        outpubkey = bio_open_owner(outpubkeyfile, outformat, private);
-        if (outpubkey == NULL)
+        mem_outpubkey = BIO_new(BIO_s_mem());
+        if (mem_outpubkey == NULL)
             goto end;
+        BIO_set_mem_eof_return(mem_outpubkey, 0);
     }
 
     if (verbose)
@@ -257,17 +259,17 @@ int genpkey_main(int argc, char **argv)
         goto end;
 
     if (do_param) {
-        rv = PEM_write_bio_Parameters(out, pkey);
+        rv = PEM_write_bio_Parameters(mem_out, pkey);
     } else if (outformat == FORMAT_PEM) {
         assert(private);
-        rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
-        if (rv > 0 && outpubkey != NULL)
-           rv = PEM_write_bio_PUBKEY(outpubkey, pkey);
+        rv = PEM_write_bio_PrivateKey(mem_out, pkey, cipher, NULL, 0, NULL, pass);
+        if (rv > 0 && mem_outpubkey != NULL)
+            rv = PEM_write_bio_PUBKEY(mem_outpubkey, pkey);
     } else if (outformat == FORMAT_ASN1) {
         assert(private);
-        rv = i2d_PrivateKey_bio(out, pkey);
-        if (rv > 0 && outpubkey != NULL)
-           rv = i2d_PUBKEY_bio(outpubkey, pkey);
+        rv = i2d_PrivateKey_bio(mem_out, pkey);
+        if (rv > 0 && mem_outpubkey != NULL)
+            rv = i2d_PUBKEY_bio(mem_outpubkey, pkey);
     } else {
         BIO_printf(bio_err, "Bad format specified for key\n");
         goto end;
@@ -282,9 +284,9 @@ int genpkey_main(int argc, char **argv)
 
     if (text) {
         if (do_param)
-            rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
+            rv = EVP_PKEY_print_params(mem_out, pkey, 0, NULL);
         else
-            rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
+            rv = EVP_PKEY_print_private(mem_out, pkey, 0, NULL);
 
         if (rv <= 0) {
             BIO_puts(bio_err, "Error printing key\n");
@@ -294,14 +296,25 @@ int genpkey_main(int argc, char **argv)
 
  end:
     sk_OPENSSL_STRING_free(keyopt);
-    if (ret != 0)
+    if (ret != 0) {
         ERR_print_errors(bio_err);
+    } else {
+        if (mem_outpubkey != NULL) {
+            rv = mem_bio_to_file(mem_outpubkey, outpubkeyfile, outformat, private);
+            if (!rv)
+                BIO_printf(bio_err, "Error writing to outpubkey: '%s'. Error: %s\n", outpubkeyfile, strerror(errno));
+        }
+        if (mem_out != NULL) {
+            rv = mem_bio_to_file(mem_out, outfile, outformat, private);
+            if (!rv)
+                BIO_printf(bio_err, "Error writing to outfile: '%s'. Error: %s\n", outpubkeyfile, strerror(errno));
+        }
+    }
     EVP_PKEY_free(pkey);
     EVP_PKEY_CTX_free(ctx);
     EVP_CIPHER_free(cipher);
-    BIO_free_all(out);
-    BIO_free_all(outpubkey);
-    BIO_free(in);
+    BIO_free_all(mem_out);
+    BIO_free_all(mem_outpubkey);
     release_engine(e);
     OPENSSL_free(pass);
     NCONF_free(conf);
index 62b5cf9a0132ad8c0c0e8488625f734ebda1e453..2e1d06ebdf648603154170391a5278940ba08dfb 100644 (file)
@@ -63,6 +63,7 @@ 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);
+int mem_bio_to_file(BIO *in, const char *filename, int format, int private);
 char *app_conf_try_string(const CONF *cnf, const char *group, const char *name);
 int app_conf_try_number(const CONF *conf, const char *group, const char *name,
                         long *result);
index 59cc6e18e0e47c09b25d8577880cea0adfa18de3..3bc64659457e5641defd5ccac0f8085dbb7d69d1 100644 (file)
@@ -3225,6 +3225,32 @@ BIO *bio_open_default_quiet(const char *filename, char mode, int format)
     return bio_open_default_(filename, mode, format, 1);
 }
 
+int mem_bio_to_file(BIO *in, const char *filename, int format, int private)
+{
+    int rv = 0, ret = 0;
+    BIO *out = NULL;
+    BUF_MEM *mem_buffer = NULL;
+
+    rv = BIO_get_mem_ptr(in, &mem_buffer);
+    if (rv <= 0) {
+        BIO_puts(bio_err, "Error reading mem buffer\n");
+        goto end;
+    }
+    out = bio_open_owner(filename, format, private);
+    if (out == NULL)
+        goto end;
+    rv = BIO_write(out, mem_buffer->data, mem_buffer->length);
+    if (rv < 0 || (size_t)rv != mem_buffer->length)
+        BIO_printf(bio_err, "Error writing to output file: '%s'\n", filename);
+    else
+        ret = 1;
+end:
+    if (!ret)
+        ERR_print_errors(bio_err);
+    BIO_free_all(out);
+    return ret;
+}
+
 void wait_for_async(SSL *s)
 {
     /* On Windows select only works for sockets, so we simply don't wait  */