From abec6c7de2def7da5f50c3e978c26e4d575bd950 Mon Sep 17 00:00:00 2001 From: Denys <168341471+desvxx@users.noreply.github.com> Date: Tue, 17 Sep 2024 00:04:00 +0300 Subject: [PATCH] Allow zero-length input in rnp_input_from_memory() (#2246) * Allow zero-length input in rnp_input_from_memory() * Split empty buf and null buf checks into separate tests --- src/lib/rnp.cpp | 8 +++-- src/tests/ffi-enc.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index ad8cdd9b42..3782a7b9af 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -2053,11 +2053,15 @@ FFI_GUARD rnp_result_t rnp_input_from_memory(rnp_input_t *input, const uint8_t buf[], size_t buf_len, bool do_copy) try { - if (!input || !buf) { + if (!input) { + return RNP_ERROR_NULL_POINTER; + } + if (!buf && buf_len) { return RNP_ERROR_NULL_POINTER; } if (!buf_len) { - return RNP_ERROR_SHORT_BUFFER; + // prevent malloc(0) + do_copy = false; } *input = new rnp_input_st(); uint8_t *data = (uint8_t *) buf; diff --git a/src/tests/ffi-enc.cpp b/src/tests/ffi-enc.cpp index 0ee1b28517..c7308dbef4 100644 --- a/src/tests/ffi-enc.cpp +++ b/src/tests/ffi-enc.cpp @@ -381,7 +381,8 @@ TEST_F(rnp_tests, test_ffi_encrypt_set_cipher) assert_rnp_failure( rnp_input_from_memory(NULL, (const uint8_t *) plaintext, strlen(plaintext), false)); assert_rnp_failure(rnp_input_from_memory(&input, NULL, strlen(plaintext), false)); - assert_rnp_failure(rnp_input_from_memory(&input, (const uint8_t *) plaintext, 0, false)); + assert_rnp_success(rnp_input_from_memory(&input, (const uint8_t *) plaintext, 0, false)); + assert_rnp_success(rnp_input_destroy(input)); assert_rnp_success( rnp_input_from_memory(&input, (const uint8_t *) plaintext, strlen(plaintext), false)); rnp_output_t output = NULL; @@ -512,6 +513,79 @@ TEST_F(rnp_tests, test_ffi_encrypt_set_cipher) rnp_ffi_destroy(ffi); } +TEST_F(rnp_tests, test_ffi_encrypt_empty_buffer) +{ + /* setup FFI */ + rnp_ffi_t ffi = NULL; + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + /* create input + output */ + rnp_input_t input = NULL; + const char *plaintext = ""; + assert_rnp_success( + rnp_input_from_memory(&input, (const uint8_t *) plaintext, strlen(plaintext), false)); + rnp_output_t output = NULL; + assert_rnp_success(rnp_output_to_path(&output, "encrypted")); + /* create encrypt operation */ + rnp_op_encrypt_t op = NULL; + assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output)); + assert_rnp_success(rnp_op_encrypt_add_password(op, "password1", NULL, 0, "AES192")); + /* execute the operation */ + assert_rnp_success(rnp_op_encrypt_execute(op)); + assert_true(rnp_file_exists("encrypted")); + /* cleanup */ + assert_rnp_success(rnp_input_destroy(input)); + assert_rnp_success(rnp_output_destroy(output)); + assert_rnp_success(rnp_op_encrypt_destroy(op)); + /* decrypt with password1 */ + assert_rnp_success(rnp_input_from_path(&input, "encrypted")); + assert_rnp_success(rnp_output_to_path(&output, "decrypted")); + assert_rnp_success( + rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password1")); + rnp_input_destroy(input); + rnp_output_destroy(output); + assert_string_equal(file_to_str("decrypted").c_str(), plaintext); + unlink("decrypted"); + unlink("encrypted"); + + rnp_ffi_destroy(ffi); +} + +TEST_F(rnp_tests, test_ffi_encrypt_null_buffer) +{ + /* setup FFI */ + rnp_ffi_t ffi = NULL; + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + /* create input + output */ + rnp_input_t input = NULL; + assert_rnp_failure(rnp_input_from_memory(&input, NULL, 10 /*not zero value*/, false)); + assert_rnp_success(rnp_input_from_memory(&input, NULL, 0, false)); + rnp_output_t output = NULL; + assert_rnp_success(rnp_output_to_path(&output, "encrypted")); + /* create encrypt operation */ + rnp_op_encrypt_t op = NULL; + assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output)); + assert_rnp_success(rnp_op_encrypt_add_password(op, "password1", NULL, 0, "AES192")); + /* execute the operation */ + assert_rnp_success(rnp_op_encrypt_execute(op)); + assert_true(rnp_file_exists("encrypted")); + /* cleanup */ + assert_rnp_success(rnp_input_destroy(input)); + assert_rnp_success(rnp_output_destroy(output)); + assert_rnp_success(rnp_op_encrypt_destroy(op)); + /* decrypt with password1 */ + assert_rnp_success(rnp_input_from_path(&input, "encrypted")); + assert_rnp_success(rnp_output_to_path(&output, "decrypted")); + assert_rnp_success( + rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password1")); + rnp_input_destroy(input); + rnp_output_destroy(output); + assert_string_equal(file_to_str("decrypted").c_str(), ""); + unlink("decrypted"); + unlink("encrypted"); + + rnp_ffi_destroy(ffi); +} + TEST_F(rnp_tests, test_ffi_encrypt_pk) { rnp_ffi_t ffi = NULL;