diff --git a/wolfssl-gnutls-wrapper/src/cipher.c b/wolfssl-gnutls-wrapper/src/cipher.c index d980667..761f791 100644 --- a/wolfssl-gnutls-wrapper/src/cipher.c +++ b/wolfssl-gnutls-wrapper/src/cipher.c @@ -1,6 +1,8 @@ #include #include "gnutls_compat.h" #include "logging.h" +#include +#include #include "mac.h" #include @@ -112,8 +114,6 @@ struct wolfssl_cipher_ctx { size_t data_size; /** Tag has been set. */ unsigned int tag_set:1; - /** Tag has been set from external source. */ - unsigned int tag_set_ext:1; }; /** Array of supported ciphers. */ @@ -654,7 +654,6 @@ int wolfssl_cipher_setiv(void *_ctx, const void *iv, size_t iv_size) /* IV stored and used in encrypt/decrypt/tag. */ /* No tag set, auth data or plaintext now we have a new IV. */ ctx->tag_set = 0; - ctx->tag_set_ext = 0; ctx->auth_data_size = 0; ctx->data_size = 0; break; @@ -1042,31 +1041,28 @@ int wolfssl_cipher_decrypt(void *_ctx, const void *src, size_t src_size, unsigned char *aad = ctx->auth_data_heap ? ctx->auth_data_heap : ctx->auth_data_static; - /* If caller hasn't set tag then we are creating it. */ - if (!ctx->tag_set_ext) { - /* Encrypt the ciphertext to get the plaintext. - * Tag will have been created on plaintext which is of no use. - */ - ret = wc_AesGcmEncrypt(&ctx->cipher.aes_ctx, decr, ctx->data, - ctx->data_size, ctx->iv, ctx->iv_size, - ctx->tag, ctx->tag_size, aad, ctx->auth_data_size); - if (ret != 0) { - WGW_WOLFSSL_ERROR("wc_AesGcmEncrypt", ret); - gnutls_free(decr); - return GNUTLS_E_ENCRYPTION_FAILED; - } - /* Encrypt the plaintext to create the tag. */ - ret = wc_AesGcmEncrypt(&ctx->cipher.aes_ctx, decr, decr, - ctx->data_size, ctx->iv, ctx->iv_size, - ctx->tag, ctx->tag_size, aad, ctx->auth_data_size); - if (ret != 0) { - WGW_WOLFSSL_ERROR("wc_AesGcmEncrypt", ret); - gnutls_free(decr); - return GNUTLS_E_ENCRYPTION_FAILED; - } - /* A tag is now available. */ - ctx->tag_set = 1; + /* Encrypt the ciphertext to get the plaintext. + * Tag will have been created on plaintext which is of no use. + */ + ret = wc_AesGcmEncrypt(&ctx->cipher.aes_ctx, decr, ctx->data, + ctx->data_size, ctx->iv, ctx->iv_size, + ctx->tag, ctx->tag_size, aad, ctx->auth_data_size); + if (ret != 0) { + WGW_WOLFSSL_ERROR("wc_AesGcmEncrypt", ret); + gnutls_free(decr); + return GNUTLS_E_ENCRYPTION_FAILED; } + /* Encrypt the plaintext to create the tag. */ + ret = wc_AesGcmEncrypt(&ctx->cipher.aes_ctx, decr, decr, + ctx->data_size, ctx->iv, ctx->iv_size, + ctx->tag, ctx->tag_size, aad, ctx->auth_data_size); + if (ret != 0) { + WGW_WOLFSSL_ERROR("wc_AesGcmEncrypt", ret); + gnutls_free(decr); + return GNUTLS_E_ENCRYPTION_FAILED; + } + /* A tag is now available. */ + ctx->tag_set = 1; /* Do decryption with cipehtext, IV, authentication data and tag. */ ret = wc_AesGcmDecrypt(&ctx->cipher.aes_ctx, decr, ctx->data, ctx->data_size, ctx->iv, ctx->iv_size, @@ -1132,68 +1128,59 @@ void wolfssl_cipher_tag(void *_ctx, void *tag, size_t tag_size) WGW_LOG("tag_size %zu", tag_size); struct wolfssl_cipher_ctx *ctx = _ctx; + int ret = -1; + /* The tag is output only: gnutls compares it with the received tag after + * a decrypt, so it must always be written. When it cannot be computed it + * is filled with random bytes, which no received tag will match. */ if (!ctx->initialized) { WGW_LOG("cipher context not initialized"); - return; - } - - /* Make sure copied tag size is no larger than that generated. */ - if (tag_size > ctx->tag_size) { - tag_size = ctx->tag_size; - } - - /* Check if tag available. */ - if (ctx->tag_set) { - if (ctx->mode == GCM) { - XMEMCPY(tag, ctx->tag, tag_size); - /* Authentication data used - reset count. */ - ctx->auth_data_size = 0; - /* Dispose of cached data. */ - gnutls_free(ctx->data); - ctx->data = NULL; - ctx->data_size = 0; - WGW_LOG("tag returned successfully"); - } else { - WGW_LOG("AES mode not supported: %d", ctx->mode); + } else if (ctx->mode != GCM) { + WGW_LOG("AES mode not supported: %d", ctx->mode); + } else { + /* Make sure copied tag size is no larger than that generated. */ + if (tag_size > ctx->tag_size) { + tag_size = ctx->tag_size; } - } else if (ctx->enc) { - int ret = -1; - - /* Encrypting and no tag set means we don't have plaintext. */ - if (ctx->mode == GCM) { - WGW_LOG("wc_AesGcmEncrypt"); + if (ctx->tag_set) { + /* Tag of the data encrypted or decrypted. */ + ret = 0; + } else { unsigned char *aad = ctx->auth_data_heap ? ctx->auth_data_heap : ctx->auth_data_static; - /* Do authentication with no plaintext. */ + /* No data: the tag is over the authentication data alone, the + * same for encryption and decryption. */ + WGW_LOG("wc_AesGcmEncrypt"); ret = wc_AesGcmEncrypt(&ctx->cipher.aes_ctx, NULL, NULL, 0, ctx->iv, ctx->iv_size, ctx->tag, ctx->tag_size, aad, ctx->auth_data_size); if (ret != 0) { WGW_WOLFSSL_ERROR("wc_AesGcmEncrypt", ret); } else { - /* Copy out tag. */ ctx->tag_set = 1; - XMEMCPY(tag, ctx->tag, tag_size); - WGW_LOG("tag stored successfully"); } - /* Authentication data used - reset count. */ - ctx->auth_data_size = 0; - /* Dispose of cached plaintext. */ - gnutls_free(ctx->data); - ctx->data = NULL; - ctx->data_size = 0; - } else { - WGW_LOG("AES mode not supported: %d", ctx->mode); } - } else { - /* Decrypting and we need to set tag for decrypt operation. */ - XMEMCPY(ctx->tag, tag, tag_size); - ctx->tag_set = 1; - ctx->tag_set_ext = 1; - WGW_LOG("tag provided successfully"); + /* The tag ends this message: a handle reused without a new IV must + * not return it again. */ + ctx->tag_set = 0; + /* Authentication data used - reset count. */ + ctx->auth_data_size = 0; + /* Dispose of cached data. */ + gnutls_free(ctx->data); + ctx->data = NULL; + ctx->data_size = 0; + } + + if (ret == 0) { + XMEMCPY(tag, ctx->tag, tag_size); + WGW_LOG("tag returned successfully"); + } else if ((gnutls_rnd(GNUTLS_RND_NONCE, tag, tag_size) != 0) && + (getrandom(tag, tag_size, 0) != (ssize_t)tag_size)) { + /* No random tag possible: never return one a sender could match. */ + WGW_ERROR("no random bytes for the tag"); + abort(); } } @@ -1632,8 +1619,6 @@ int wolfssl_cipher_aead_decrypt(void *_ctx, const void *nonce, return GNUTLS_E_SHORT_MEMORY_BUFFER; } - ctx->enc = 0; - /* Encrypted size includes tag. */ encr_size -= tag_size; diff --git a/wolfssl-gnutls-wrapper/src/pk.c b/wolfssl-gnutls-wrapper/src/pk.c index bb0090b..7e228ef 100644 --- a/wolfssl-gnutls-wrapper/src/pk.c +++ b/wolfssl-gnutls-wrapper/src/pk.c @@ -886,6 +886,37 @@ static int wolfssl_pk_encrypt(gnutls_pk_algorithm_t algo, return ret; } +/** + * Finish an RSA decrypt2 (caller-sized output buffer). + * + * The caller's buffer is written only when the decrypted length equals its + * size, by a constant-time masked select; on any failure (padding or length) + * it is left unchanged. TLS RSA key exchange prefills it with a random + * premaster and ignores the error, so a failure must not change it. + * + * @param [in, out] plaintext Caller's buffer and its size. + * @param [in] scratch Decrypted data, at least plaintext->size bytes. + * @param [in] ret Result of the wolfCrypt decryption. + * @return 0 on success. + * @return GNUTLS_E_DECRYPTION_FAILED otherwise. + */ +static int rsa_decrypt2_select(gnutls_datum_t *plaintext, + const unsigned char *scratch, int ret) +{ + unsigned int diff = (unsigned int)ret ^ plaintext->size; + /* All ones when ret equals the size, else zero. */ + unsigned int ok = ((diff | (0U - diff)) >> (sizeof(diff) * 8 - 1)) - 1U; + unsigned char mask = (unsigned char)ok; + unsigned int i; + + for (i = 0; i < plaintext->size; i++) { + plaintext->data[i] = (unsigned char)((scratch[i] & mask) | + (plaintext->data[i] & (unsigned char)~mask)); + } + + return ok ? 0 : GNUTLS_E_DECRYPTION_FAILED; +} + /** * Decrypt ciphertext using RSA PKCS#1 v1.5 with private key. * @@ -909,6 +940,7 @@ static int wolfssl_pk_decrypt_rsa(gnutls_datum_t *plaintext, unsigned char out[1024]; unsigned char *plain; word32 plain_size; + word32 scratch_size = 0; WGW_FUNC_ENTER(); @@ -950,13 +982,24 @@ static int wolfssl_pk_decrypt_rsa(gnutls_datum_t *plaintext, wc_FreeRsaKey(&rsa); return GNUTLS_E_MEMORY_ERROR; } - } - /* Set plain to valid buffer. */ - if ((!alloc_plaintext) && - (plaintext->size < (unsigned int)wc_RsaEncryptSize(&rsa))) { - plain = out; - } else { plain = plaintext->data; + } else { + /* decrypt2: never decrypt into the caller's buffer (see + * rsa_decrypt2_select()); scratch holds the key size and the + * caller's size. */ + scratch_size = plain_size > plaintext->size ? plain_size : + plaintext->size; + if (scratch_size <= sizeof(out)) { + plain = out; + } else { + plain = gnutls_malloc(scratch_size); + if (plain == NULL) { + WGW_ERROR("Allocating memory for plaintext"); + wc_FreeRsaKey(&rsa); + return GNUTLS_E_MEMORY_ERROR; + } + } + XMEMSET(plain, 0, scratch_size); } PRIVATE_KEY_UNLOCK(); @@ -969,29 +1012,26 @@ static int wolfssl_pk_decrypt_rsa(gnutls_datum_t *plaintext, /* No longer need RSA key. */ wc_FreeRsaKey(&rsa); + + if (!alloc_plaintext) { + ret = rsa_decrypt2_select(plaintext, plain, ret); + gnutls_memset(plain, 0, scratch_size); + if (plain != out) { + gnutls_free(plain); + } + return ret; + } + if (ret < 0) { WGW_WOLFSSL_ERROR("wc_RsaPrivateDecrypt", ret); - if (alloc_plaintext) { - /* Dispose of allocated buffer for plaintext. */ - gnutls_free(plaintext->data); - /* Ensure output datum is empty on error. */ - plaintext->data = NULL; - plaintext->size = 0; - } + /* Dispose of allocated buffer for plaintext. */ + gnutls_free(plaintext->data); + /* Ensure output datum is empty on error. */ + plaintext->data = NULL; + plaintext->size = 0; return GNUTLS_E_DECRYPTION_FAILED; } - /* Check if returning through another buffer. */ - if (plain != plaintext->data) { - /* Ensure the output buffer is big enough. */ - if ((unsigned int)ret > plaintext->size) { - WGW_ERROR("Decrypted data too big for plaintext buffer: %d > %d", - ret, plaintext->size); - return GNUTLS_E_DECRYPTION_FAILED; - } - /* Copy the decrypted data into output buffer. */ - XMEMCPY(plaintext->data, plain, ret); - } /* Set the actual size into output datum. */ plaintext->size = ret; @@ -1021,6 +1061,7 @@ static int wolfssl_pk_decrypt_rsa_oaep(gnutls_datum_t *plaintext, unsigned char out[1024]; unsigned char *plain; word32 plain_size; + word32 scratch_size = 0; WGW_FUNC_ENTER(); @@ -1064,13 +1105,24 @@ static int wolfssl_pk_decrypt_rsa_oaep(gnutls_datum_t *plaintext, wc_FreeRsaKey(&rsa); return GNUTLS_E_MEMORY_ERROR; } - } - /* Set plain to valid buffer. */ - if ((!alloc_plaintext) && - (plaintext->size < (unsigned int)wc_RsaEncryptSize(&rsa))) { - plain = out; - } else { plain = plaintext->data; + } else { + /* decrypt2: never decrypt into the caller's buffer (see + * rsa_decrypt2_select()); scratch holds the key size and the + * caller's size. */ + scratch_size = plain_size > plaintext->size ? plain_size : + plaintext->size; + if (scratch_size <= sizeof(out)) { + plain = out; + } else { + plain = gnutls_malloc(scratch_size); + if (plain == NULL) { + WGW_ERROR("Allocating memory for plaintext"); + wc_FreeRsaKey(&rsa); + return GNUTLS_E_MEMORY_ERROR; + } + } + XMEMSET(plain, 0, scratch_size); } PRIVATE_KEY_UNLOCK(); @@ -1084,29 +1136,26 @@ static int wolfssl_pk_decrypt_rsa_oaep(gnutls_datum_t *plaintext, /* No longer need RSA key. */ wc_FreeRsaKey(&rsa); + + if (!alloc_plaintext) { + ret = rsa_decrypt2_select(plaintext, plain, ret); + gnutls_memset(plain, 0, scratch_size); + if (plain != out) { + gnutls_free(plain); + } + return ret; + } + if (ret < 0) { WGW_WOLFSSL_ERROR("wc_RsaPublicDecrypt_ex", ret); - if (alloc_plaintext) { - /* Dispose of allocated buffer for plaintext. */ - gnutls_free(plaintext->data); - /* Ensure output datum is empty on error. */ - plaintext->data = NULL; - plaintext->size = 0; - } + /* Dispose of allocated buffer for plaintext. */ + gnutls_free(plaintext->data); + /* Ensure output datum is empty on error. */ + plaintext->data = NULL; + plaintext->size = 0; return GNUTLS_E_DECRYPTION_FAILED; } - /* Check if returning through another buffer. */ - if (plain != plaintext->data) { - /* Ensure the output buffer is big enough. */ - if ((unsigned int)ret > plaintext->size) { - WGW_ERROR("Decrypted data too big for plaintext buffer: %d > %d", - ret, plaintext->size); - return GNUTLS_E_DECRYPTION_FAILED; - } - /* Copy the decrypted data into output buffer. */ - XMEMCPY(plaintext->data, plain, ret); - } /* Set the actual size into output datum. */ plaintext->size = ret; diff --git a/wolfssl-gnutls-wrapper/tests/Makefile b/wolfssl-gnutls-wrapper/tests/Makefile index f7fe39d..4085680 100644 --- a/wolfssl-gnutls-wrapper/tests/Makefile +++ b/wolfssl-gnutls-wrapper/tests/Makefile @@ -1,4 +1,4 @@ -TESTS = test_hash test_shake test_aescbc test_aescfb8 test_aesgcm test_aesccm test_aesxts test_hmac test_cmac test_gmac test_rnd test_rnd_fork test_tls_prf test_hkdf test_pbkdf2 test_ecdsa_sign_and_verify test_ecdh_encrypt_and_decrypt test_eddsa_sign_and_verify test_rsa_sign_and_verify test_rsa_encrypt_and_decrypt test_dh_encrypt_and_decrypt test_pk_import_export test_long_hash test_fips test_aessiv +TESTS = test_hash test_shake test_aescbc test_aescfb8 test_aesgcm test_aesccm test_aesxts test_hmac test_cmac test_gmac test_rnd test_rnd_fork test_tls_prf test_hkdf test_pbkdf2 test_ecdsa_sign_and_verify test_ecdh_encrypt_and_decrypt test_eddsa_sign_and_verify test_rsa_sign_and_verify test_rsa_encrypt_and_decrypt test_dh_encrypt_and_decrypt test_pk_import_export test_long_hash test_fips test_aessiv test_aesgcm_tag_state test_rsa_decrypt2_length PKGCONF ?= pkg-config UNAME_S := $(shell uname -s) diff --git a/wolfssl-gnutls-wrapper/tests/test_aesgcm_tag_state.c b/wolfssl-gnutls-wrapper/tests/test_aesgcm_tag_state.c new file mode 100644 index 0000000..b34b956 --- /dev/null +++ b/wolfssl-gnutls-wrapper/tests/test_aesgcm_tag_state.c @@ -0,0 +1,101 @@ +/* AES-GCM tag after a one-shot decrypt on the same AEAD handle. + * + * GnuTLS calls the provider's tag callback to obtain the tag it compares with + * the received one. If a one-shot gnutls_aead_cipher_decrypt() leaves the + * handle in a state where the callback takes the tag as input, a following + * gnutls_aead_cipher_decryptv2() with no ciphertext accepts any tag over any + * AAD. + * + * Expected values from pyca/cryptography AESGCM: key 0^16, nonce 01 00^11, + * AAD 'A' x 20; plaintext 'M' x 32, and the empty plaintext. + */ +#include +#include +#include +#include +#include "test_util.h" + +static const unsigned char ct_tag[48] = { + 0x47, 0x60, 0x91, 0xab, 0x06, 0x70, 0x21, 0x40, 0xb7, 0x78, 0x73, 0x0e, + 0x6b, 0x7a, 0x2c, 0x15, 0x7b, 0x67, 0x6e, 0xfc, 0x7a, 0xad, 0x73, 0x27, + 0xe5, 0x86, 0x1c, 0x69, 0x27, 0x63, 0xc0, 0x66, 0x7e, 0x46, 0x77, 0x35, + 0xc6, 0x67, 0x19, 0x2e, 0xc6, 0x94, 0xff, 0xa4, 0x74, 0x3e, 0xc6, 0x96 +}; +static const unsigned char aad_tag[16] = { + 0x0e, 0xea, 0x6f, 0x5e, 0xa5, 0x99, 0xa4, 0x4a, 0xd5, 0xa3, 0x94, 0xfe, + 0xec, 0x67, 0x9d, 0xb9 +}; + +int main(void) +{ + unsigned char key_data[16] = { 0 }, nonce[12] = { 1 }, aad[20], msg[32]; + unsigned char out[48], pt[48], tag[16], zero[16] = { 0 }; + unsigned char evil[] = "attacker header"; + gnutls_datum_t key = { key_data, sizeof(key_data) }; + gnutls_aead_cipher_hd_t h; + giovec_t a = { aad, sizeof(aad) }, e = { evil, sizeof(evil) - 1 }; + size_t len, tag_len; + int ret; + + printf("Testing AES-GCM tags after a one-shot decrypt...\n"); + + memset(aad, 'A', sizeof(aad)); + memset(msg, 'M', sizeof(msg)); + if ((ret = gnutls_global_init()) != 0 || + (ret = gnutls_aead_cipher_init(&h, GNUTLS_CIPHER_AES_128_GCM, &key)) != 0) { + print_gnutls_error("initializing", ret); + return 1; + } + + len = sizeof(out); + ret = gnutls_aead_cipher_encrypt(h, nonce, sizeof(nonce), aad, sizeof(aad), + 16, msg, sizeof(msg), out, &len); + if (ret != 0 || compare_sz("AES-GCM encrypt", out, len, ct_tag, + sizeof(ct_tag)) != 0) { + return 1; + } + + /* One-shot decrypt, then a forged empty message on the same handle. */ + len = sizeof(pt); + ret = gnutls_aead_cipher_decrypt(h, nonce, sizeof(nonce), aad, sizeof(aad), + 16, ct_tag, sizeof(ct_tag), pt, &len); + if (ret != 0) { + print_gnutls_error("one-shot decrypt", ret); + return 1; + } + ret = gnutls_aead_cipher_decryptv2(h, nonce, sizeof(nonce), &e, 1, NULL, 0, + zero, sizeof(zero)); + if (ret == 0) { + printf("FAILURE - forged tag accepted after a one-shot decrypt\n"); + return 1; + } + + /* The correct tag over the AAD alone must still verify. */ + len = sizeof(pt); + gnutls_aead_cipher_decrypt(h, nonce, sizeof(nonce), aad, sizeof(aad), 16, + ct_tag, sizeof(ct_tag), pt, &len); + ret = gnutls_aead_cipher_decryptv2(h, nonce, sizeof(nonce), &a, 1, NULL, 0, + (void *)aad_tag, sizeof(aad_tag)); + if (ret != 0) { + print_gnutls_error("correct tag after a one-shot decrypt", ret); + return 1; + } + + /* An empty encryption after a decrypt returns the tag over the AAD. */ + len = sizeof(pt); + gnutls_aead_cipher_decrypt(h, nonce, sizeof(nonce), aad, sizeof(aad), 16, + ct_tag, sizeof(ct_tag), pt, &len); + memset(tag, 0xaa, sizeof(tag)); + tag_len = sizeof(tag); + ret = gnutls_aead_cipher_encryptv2(h, nonce, sizeof(nonce), &a, 1, NULL, 0, + tag, &tag_len); + if (ret != 0 || compare_sz("AES-GCM tag of the AAD alone", tag, tag_len, + aad_tag, sizeof(aad_tag)) != 0) { + return 1; + } + + gnutls_aead_cipher_deinit(h); + gnutls_global_deinit(); + printf("\nAll AES-GCM tag tests completed successfully!\n"); + return 0; +} diff --git a/wolfssl-gnutls-wrapper/tests/test_rsa_decrypt2_length.c b/wolfssl-gnutls-wrapper/tests/test_rsa_decrypt2_length.c new file mode 100644 index 0000000..907e4d0 --- /dev/null +++ b/wolfssl-gnutls-wrapper/tests/test_rsa_decrypt2_length.c @@ -0,0 +1,103 @@ +/* gnutls_privkey_decrypt_data2() gives the exact plaintext size. A message of + * any other length, or a ciphertext that does not decrypt, must fail and leave + * the caller's buffer unchanged: TLS RSA key exchange prefills it with a + * random premaster and ignores the error. + */ +#include +#include +#include +#include +#include "test_util.h" + +#define BUF_LEN 48 + +/* How the ciphertext is damaged before decryption. */ +#define CT_INTACT 0 +#define CT_CORRUPT 1 +#define CT_TRUNCATE 2 + +static int decrypt_len(gnutls_privkey_t priv, gnutls_pubkey_t pub, + size_t msg_len, int damage, int expect_ok) +{ + unsigned char msg[64], buf[BUF_LEN], prefill[BUF_LEN]; + gnutls_datum_t m = { msg, msg_len }, c = { NULL, 0 }; + size_t i; + int ret; + + memset(msg, 'P', sizeof(msg)); + ret = gnutls_pubkey_encrypt_data(pub, 0, &m, &c); + if (ret != 0) { + print_gnutls_error("encrypting", ret); + return 1; + } + if (damage == CT_CORRUPT) { + c.data[c.size / 2] ^= 0x01; + } else if (damage == CT_TRUNCATE) { + c.size--; + } + + for (i = 0; i < sizeof(prefill); i++) { + prefill[i] = (unsigned char)(0xa0 + i); + } + memcpy(buf, prefill, sizeof(buf)); + ret = gnutls_privkey_decrypt_data2(priv, 0, &c, buf, sizeof(buf)); + gnutls_free(c.data); + printf("message %zu bytes%s into %d-byte buffer: %s\n", msg_len, + damage == CT_CORRUPT ? " (corrupted)" : + damage == CT_TRUNCATE ? " (truncated)" : "", BUF_LEN, + ret == 0 ? "decrypted" : gnutls_strerror(ret)); + + if (expect_ok) { + if (ret != 0) { + printf("FAILURE - exact-length message did not decrypt\n"); + return 1; + } + if (memcmp(buf, msg, sizeof(buf)) != 0) { + printf("FAILURE - decrypted data does not match\n"); + return 1; + } + return 0; + } + if (ret >= 0) { + printf("FAILURE - reported as decrypted\n"); + return 1; + } + if (memcmp(buf, prefill, sizeof(buf)) != 0) { + printf("FAILURE - output buffer changed on failure\n"); + return 1; + } + return 0; +} + +int main(void) +{ + gnutls_privkey_t priv; + gnutls_pubkey_t pub; + int ret; + + printf("Testing RSA decrypt_data2 with a mismatched length...\n"); + + if ((ret = gnutls_global_init()) != 0 || + (ret = gnutls_privkey_init(&priv)) != 0 || + (ret = gnutls_privkey_generate(priv, GNUTLS_PK_RSA, 2048, 0)) != 0 || + (ret = gnutls_pubkey_init(&pub)) != 0 || + (ret = gnutls_pubkey_import_privkey(pub, priv, 0, 0)) != 0) { + print_gnutls_error("setting up the key", ret); + return 1; + } + + if (decrypt_len(priv, pub, BUF_LEN, CT_INTACT, 1) != 0 || + decrypt_len(priv, pub, 16, CT_INTACT, 0) != 0 || + decrypt_len(priv, pub, 47, CT_INTACT, 0) != 0 || + decrypt_len(priv, pub, 64, CT_INTACT, 0) != 0 || + decrypt_len(priv, pub, BUF_LEN, CT_CORRUPT, 0) != 0 || + decrypt_len(priv, pub, BUF_LEN, CT_TRUNCATE, 0) != 0) { + return 1; + } + + gnutls_pubkey_deinit(pub); + gnutls_privkey_deinit(priv); + gnutls_global_deinit(); + printf("\nAll RSA decrypt_data2 tests completed successfully!\n"); + return 0; +}