summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <ueno@gnu.org>2020-08-13 18:17:08 +0200
committerDaiki Ueno <ueno@gnu.org>2020-09-03 09:57:13 +0200
commitf936f4fb802f745259f765d69bea05a81fd8ef23 (patch)
tree0fa5a448ac49444f3342c182696461a8efcba12e
parent219904d20f0f20d92fce76eee8f6797e73d0c459 (diff)
downloadgnutls-f936f4fb802f745259f765d69bea05a81fd8ef23.tar.gz
gnutls_aead_cipher_decrypt: check output buffer size before writing
While the documentation of gnutls_aead_cipher_decrypt indicates that the inout argument ptext_len initially holds the size that sufficiently fits the expected output size, there was no runtime check on that. This makes the interface robuster against misuses. Signed-off-by: Daiki Ueno <ueno@gnu.org>
-rw-r--r--lib/nettle/cipher.c8
-rw-r--r--tests/slow/cipher-api-test.c83
2 files changed, 91 insertions, 0 deletions
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
index 93afca243b..5e3a06a744 100644
--- a/lib/nettle/cipher.c
+++ b/lib/nettle/cipher.c
@@ -1174,6 +1174,10 @@ wrap_nettle_cipher_aead_decrypt(void *_ctx,
ctx->cipher->auth(ctx->ctx_ptr, auth_size, auth);
encr_size -= tag_size;
+
+ if (unlikely(plain_size < encr_size))
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
ctx->cipher->decrypt(ctx, encr_size, plain, encr);
ctx->cipher->tag(ctx->ctx_ptr, tag_size, tag);
@@ -1183,6 +1187,10 @@ wrap_nettle_cipher_aead_decrypt(void *_ctx,
} else {
/* CCM-style cipher */
encr_size -= tag_size;
+
+ if (unlikely(plain_size < encr_size))
+ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
ret = ctx->cipher->aead_decrypt(ctx,
nonce_size, nonce,
auth_size, auth,
diff --git a/tests/slow/cipher-api-test.c b/tests/slow/cipher-api-test.c
index 17872b7a43..a8e4bbf90a 100644
--- a/tests/slow/cipher-api-test.c
+++ b/tests/slow/cipher-api-test.c
@@ -198,6 +198,70 @@ static void test_aead_cipher2(int algo)
return;
}
+/* Test whether an invalid call to gnutls_aead_cipher_decrypt() is caught */
+static void test_aead_cipher3(int algo)
+{
+ int ret;
+ gnutls_aead_cipher_hd_t ch;
+ uint8_t key16[64];
+ uint8_t iv16[32];
+ uint8_t auth[32];
+ uint8_t ctext[128+32];
+ size_t ctext_len;
+ uint8_t ptext[128];
+ size_t ptext_len;
+ gnutls_datum_t key, iv;
+
+ key.data = key16;
+ key.size = gnutls_cipher_get_key_size(algo);
+ assert(key.size <= sizeof(key16));
+
+ iv.data = iv16;
+ iv.size = gnutls_cipher_get_iv_size(algo);
+ assert(iv.size <= sizeof(iv16));
+
+ memset(iv.data, 0xff, iv.size);
+ memset(key.data, 0xfe, key.size);
+ memset(ptext, 0xfa, sizeof(ptext));
+ memset(ctext, 0xfa, sizeof(ctext));
+ memset(auth, 0xfb, sizeof(auth));
+
+ gnutls_global_set_log_function(tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level(4711);
+
+ ret = global_init();
+ if (ret < 0) {
+ fail("Cannot initialize library\n"); /*errcode 1 */
+ }
+
+ ret =
+ gnutls_aead_cipher_init(&ch, algo, &key);
+ if (ret < 0)
+ fail("gnutls_aead_cipher_init failed\n"); /*errcode 1 */
+
+ ctext_len = sizeof(ctext)-1;
+ ret = gnutls_aead_cipher_encrypt(ch, iv.data, iv.size, auth, sizeof(auth),
+ gnutls_cipher_get_tag_size(algo),
+ ptext, sizeof(ptext)-1,
+ ctext, &ctext_len);
+ if (ret < 0)
+ fail("could not encrypt data\n");
+
+ ptext_len = 0;
+ ret = gnutls_aead_cipher_decrypt(ch, iv.data, iv.size, auth, sizeof(auth),
+ gnutls_cipher_get_tag_size(algo),
+ ctext, sizeof(ctext)-1,
+ ptext, &ptext_len);
+ if (ret >= 0)
+ fail("succeeded in decrypting data onto a short buffer\n");
+
+ gnutls_aead_cipher_deinit(ch);
+
+ gnutls_global_deinit();
+ return;
+}
+
static void check_status(int status)
{
if (WEXITSTATUS(status) != 0 ||
@@ -261,6 +325,25 @@ void start(const char *name, int algo, unsigned aead)
test_aead_cipher2(algo);
exit(0);
}
+
+ /* check test_aead_cipher3 */
+
+ child = fork();
+ if (child < 0) {
+ perror("fork");
+ fail("fork");
+ return;
+ }
+
+ if (child) {
+ int status;
+ /* parent */
+ wait(&status);
+ check_status(status);
+ } else {
+ test_aead_cipher3(algo);
+ exit(0);
+ }
}
void doit(void)