diff --git a/src/wp_aes_block.c b/src/wp_aes_block.c index 44469659..f6157ad7 100644 --- a/src/wp_aes_block.c +++ b/src/wp_aes_block.c @@ -693,7 +693,9 @@ static int wp_aes_block_cipher(wp_AesBlockCtx* ctx, unsigned char* out, if (ok && (outSize < inLen)) { ok = 0; } - if (ok && !wp_aes_block_doit(ctx, out, in, inLen)) { + /* NULL in, NULL out, 0 len is OK */ + if (ok && (out != NULL && in != NULL && inLen != 0) && + !wp_aes_block_doit(ctx, out, in, inLen)) { ok = 0; } if (ok) { diff --git a/src/wp_aes_stream.c b/src/wp_aes_stream.c index 66284ec7..4dc840ce 100644 --- a/src/wp_aes_stream.c +++ b/src/wp_aes_stream.c @@ -477,7 +477,9 @@ static int wp_aes_stream_cipher(wp_AesStreamCtx* ctx, unsigned char* out, if (ok && (outSize < inLen)) { ok = 0; } - if (ok && (!wp_aes_stream_doit(ctx, out, in, inLen))) { + /* NULL in, NULL out, 0 len is OK */ + if (ok && (in != NULL && out != NULL && inLen != 0) && + (!wp_aes_stream_doit(ctx, out, in, inLen))) { ok = 0; } diff --git a/test/test_cipher.c b/test/test_cipher.c index 485d0690..6888ce4b 100644 --- a/test/test_cipher.c +++ b/test/test_cipher.c @@ -344,6 +344,92 @@ static int test_stream_enc_dec(void *data, const char *cipher, int keyLen, return err; } +static int test_cipher_null_zero_ex(void *data, const char *cipher, int keyLen, + int ivLen) +{ + int err = 0; + unsigned char msg[16] = "Test pattern"; + unsigned char key[32]; + unsigned char iv[16]; + unsigned char enc[sizeof(msg) + 16]; + EVP_CIPHER *ocipher; + EVP_CIPHER *wcipher; + EVP_CIPHER_CTX *ctx; + + (void)data; + + ocipher = EVP_CIPHER_fetch(osslLibCtx, cipher, ""); + wcipher = EVP_CIPHER_fetch(wpLibCtx, cipher, ""); + + if (RAND_bytes(key, keyLen) != 1) { + err = 1; + } + if (err == 0) { + if (RAND_bytes(iv, ivLen) != 1) { + err = 1; + } + } + + /* Test that a final call with NULL/NULL/0 yields the correct return + * value, flow mimics that of libssh2 */ + err = (ctx = EVP_CIPHER_CTX_new()) == NULL; + if (err == 0) { + err = EVP_CipherInit(ctx, ocipher, key, iv, 1) != 1; + } + if (err == 0) { + err = EVP_Cipher(ctx, enc, msg, sizeof(msg)) <= 0; + } + /* Return is 0, not negative value for NULL/NULL/0 input */ + if (err == 0) { + err = EVP_Cipher(ctx, NULL, NULL, 0) != 0; + } + EVP_CIPHER_CTX_free(ctx); + + err = (ctx = EVP_CIPHER_CTX_new()) == NULL; + if (err == 0) { + err = EVP_CipherInit(ctx, wcipher, key, iv, 1) != 1; + } + if (err == 0) { + err = EVP_Cipher(ctx, enc, msg, sizeof(msg)) <= 0; + } + /* Return is 0, not negative value for NULL/NULL/0 input */ + if (err == 0) { + err = EVP_Cipher(ctx, NULL, NULL, 0) != 0; + } + EVP_CIPHER_CTX_free(ctx); + + EVP_CIPHER_free(wcipher); + EVP_CIPHER_free(ocipher); + + return err; +} + +int test_cipher_null_zero(void *data) +{ + int err = 0; + +#ifdef WP_HAVE_AESECB + err = test_cipher_null_zero_ex(data, "AES-256-ECB", 32, 16); +#endif +#ifdef WP_HAVE_AESCBC + if (err == 0) { + err = test_cipher_null_zero_ex(data, "AES-256-CBC", 32, 16); + } +#endif +#ifdef WP_HAVE_AESCTR + if (err == 0) { + err = test_cipher_null_zero_ex(data, "AES-256-CTR", 32, 16); + } +#endif +#ifdef WP_HAVE_AESCFB + if (err == 0) { + err = test_cipher_null_zero_ex(data, "AES-256-CFB", 32, 16); + } +#endif + + return err; +} + #endif /* WP_HAVE_DES3CBC || WP_HAVE_AESCBC */ /******************************************************************************/ diff --git a/test/unit.c b/test/unit.c index bfe8020a..2de35d82 100644 --- a/test/unit.c +++ b/test/unit.c @@ -129,6 +129,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_aes192_cfb_stream, NULL), TEST_DECL(test_aes256_cfb_stream, NULL), #endif + TEST_DECL(test_cipher_null_zero, NULL), #ifdef WP_HAVE_AESGCM TEST_DECL(test_aes128_gcm, NULL), TEST_DECL(test_aes192_gcm, NULL), diff --git a/test/unit.h b/test/unit.h index 6f297cfa..7a3d8661 100644 --- a/test/unit.h +++ b/test/unit.h @@ -174,6 +174,8 @@ int test_aes256_cfb_stream(void *data); #endif +int test_cipher_null_zero(void *data); + #ifdef WP_HAVE_AESGCM int test_aes128_gcm(void *data);