Fix invalid malloc failures in PEM_write_bio_PKCS8PrivateKey()
authorDarshan Sen <raisinten@gmail.com>
Fri, 14 Jan 2022 10:52:41 +0000 (16:22 +0530)
committerTomas Mraz <tomas@openssl.org>
Wed, 26 Jan 2022 16:15:52 +0000 (17:15 +0100)
When `PEM_write_bio_PKCS8PrivateKey()` was passed an empty passphrase
string, `OPENSSL_memdup()` was incorrectly getting used for 0 bytes size
allocation, which resulted in malloc failures.

Fixes: https://github.com/openssl/openssl/issues/17506
Signed-off-by: Darshan Sen <raisinten@gmail.com>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/17507)

CHANGES.md
crypto/passphrase.c
crypto/ui/ui_util.c
test/evp_pkey_provided_test.c

index 7ddc41a0e73804391015ef3edf8b6718de6f1e84..c4922be0321a454c7003d1bc96c6d08346c1f676 100644 (file)
@@ -24,6 +24,11 @@ OpenSSL 3.1
 
 ### Changes between 3.0 and 3.1 [xx XXX xxxx]
 
+ * Fixed PEM_write_bio_PKCS8PrivateKey() to make it possible to use empty
+   passphrase strings.
+
+   *Darshan Sen*
+
  * RNDR and RNDRRS support in provider functions to provide
    random number generation for Arm CPUs (aarch64).
 
index cb1bc66958235252f484ce5786d2a77a60726395..830872953ab20d124098c253e019bf83698f59b8 100644 (file)
@@ -41,7 +41,8 @@ int ossl_pw_set_passphrase(struct ossl_passphrase_data_st *data,
     ossl_pw_clear_passphrase_data(data);
     data->type = is_expl_passphrase;
     data->_.expl_passphrase.passphrase_copy =
-        OPENSSL_memdup(passphrase, passphrase_len);
+        passphrase_len != 0 ? OPENSSL_memdup(passphrase, passphrase_len)
+                            : OPENSSL_malloc(1);
     if (data->_.expl_passphrase.passphrase_copy == NULL) {
         ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
         return 0;
index 58769d68a3ae4ee83f5bbe14c05970c509c3ba4e..871472cd32680204ff63f4002ad445ef842c7892 100644 (file)
@@ -114,7 +114,7 @@ static int ui_read(UI *ui, UI_STRING *uis)
 
             if (len >= 0)
                 result[len] = '\0';
-            if (len <= 0)
+            if (len < 0)
                 return len;
             if (UI_set_result_ex(ui, uis, result, len) >= 0)
                 return 1;
index cf4d8e1294a29090cec1cc366fed408ecca4c888..b4b53f67fc067538a380841b42b4a75449160dfe 100644 (file)
@@ -128,6 +128,16 @@ static int compare_with_file(const char *alg, int type, BIO *membio)
     return ret;
 }
 
+static int pass_cb(char *buf, int size, int rwflag, void *u)
+{
+    return 0;
+}
+
+static int pass_cb_error(char *buf, int size, int rwflag, void *u)
+{
+    return -1;
+}
+
 static int test_print_key_using_pem(const char *alg, const EVP_PKEY *pk)
 {
     BIO *membio = BIO_new(BIO_s_mem());
@@ -140,6 +150,21 @@ static int test_print_key_using_pem(const char *alg, const EVP_PKEY *pk)
         !TEST_true(PEM_write_bio_PrivateKey(bio_out, pk, EVP_aes_256_cbc(),
                                             (unsigned char *)"pass", 4,
                                             NULL, NULL))
+        /* Output zero-length passphrase encrypted private key in PEM form */
+        || !TEST_true(PEM_write_bio_PKCS8PrivateKey(bio_out, pk,
+                                                    EVP_aes_256_cbc(),
+                                                    (const char *)~0, 0,
+                                                    NULL, NULL))
+        || !TEST_true(PEM_write_bio_PKCS8PrivateKey(bio_out, pk,
+                                                    EVP_aes_256_cbc(),
+                                                    NULL, 0, NULL, ""))
+        || !TEST_true(PEM_write_bio_PKCS8PrivateKey(bio_out, pk,
+                                                    EVP_aes_256_cbc(),
+                                                    NULL, 0, pass_cb, NULL))
+        || !TEST_false(PEM_write_bio_PKCS8PrivateKey(bio_out, pk,
+                                                     EVP_aes_256_cbc(),
+                                                     NULL, 0, pass_cb_error,
+                                                     NULL))
         /* Private key in text form */
         || !TEST_int_gt(EVP_PKEY_print_private(membio, pk, 0, NULL), 0)
         || !TEST_true(compare_with_file(alg, PRIV_TEXT, membio))