diff --git a/include/wolfprovider/wp_wolfprov.h b/include/wolfprovider/wp_wolfprov.h index 172dacd5..405077f7 100644 --- a/include/wolfprovider/wp_wolfprov.h +++ b/include/wolfprovider/wp_wolfprov.h @@ -30,4 +30,8 @@ int wolfssl_prov_bio_up_ref(OSSL_CORE_BIO *bio); /* Prototype of public function that initializes the wolfSSL provider. */ OSSL_provider_init_fn wolfssl_provider_init; +/* AES-GCM context parameter (int) on non-streaming builds: 1 opts in to one + * complete payload per operation, with the tag set first when decrypting. */ +#define WP_PARAM_GCM_SINGLE_UPDATE "wolfprov-gcm-single-update" + #endif /* WP_WOLFPROV_H */ diff --git a/src/wp_aes_aead.c b/src/wp_aes_aead.c index f4f9018d..ea1acb58 100644 --- a/src/wp_aes_aead.c +++ b/src/wp_aes_aead.c @@ -27,6 +27,7 @@ #include #include +#include #include @@ -112,6 +113,12 @@ typedef struct wp_AeadCtx { size_t bufSize; /* Original IV */ unsigned char origIv[AES_BLOCK_SIZE]; + /** Caller opted in to one complete payload per operation. */ + unsigned int singleUpdate:1; + /** Single-update payload has been processed. */ + unsigned int singleDone:1; + /** Expected tag set for single-update decryption. */ + unsigned int singleTagSet:1; #endif } wp_AeadCtx; @@ -413,10 +420,24 @@ static int wp_aead_get_ctx_params(wp_AeadCtx* ctx, OSSL_PARAM params[]) WOLFPROV_ENTER(WP_LOG_COMP_AES, "wp_aead_get_ctx_params"); - p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); - if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->ivLen)) { +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + p = OSSL_PARAM_locate(params, WP_PARAM_GCM_SINGLE_UPDATE); + if ((p != NULL) && ((ctx->mode != EVP_CIPH_GCM_MODE) || + (!OSSL_PARAM_set_int(p, ctx->singleUpdate)))) { + ok = 0; + } + if (ok && ctx->singleUpdate && (OSSL_PARAM_locate(params, + OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN) != NULL)) { ok = 0; } +#endif + + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->ivLen)) { + ok = 0; + } + } if (ok) { p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keyLen)) { @@ -540,6 +561,9 @@ static int wp_aead_set_param_tag(wp_AeadCtx* ctx, if (ok) { ctx->tagLen = sz; } +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + ctx->singleTagSet = ok && (p->data != NULL); +#endif WOLFPROV_LEAVE(WP_LOG_COMP_AES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); return ok; @@ -685,6 +709,40 @@ static int wp_aead_set_param_tls1_iv_rand(wp_AeadCtx* ctx, #endif } +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) +/** + * Set the single-update opt-in from the parameters. + * + * @param [in, out] ctx AEAD context object. + * @param [in] params Array of parameters and values. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_aead_set_param_single_update(wp_AeadCtx* ctx, + const OSSL_PARAM params[]) +{ + int ok = 1; + int enabled = 0; + + WOLFPROV_ENTER(WP_LOG_COMP_AES, "wp_aead_set_param_single_update"); + + if ((ctx->mode != EVP_CIPH_GCM_MODE) || + (!OSSL_PARAM_get_int(params, &enabled)) || + ((enabled != 0) && (enabled != 1)) || (ctx->inLen != 0) || + ctx->singleDone || ctx->authErr || + (ctx->tlsAadLen != UNINITIALISED_SIZET) || ctx->ivGen || + (ctx->ivState != IV_STATE_BUFFERED)) { + ok = 0; + } + if (ok) { + ctx->singleUpdate = enabled; + } + + WOLFPROV_LEAVE(WP_LOG_COMP_AES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} +#endif + /** * Set the AEAD context parameters. * @@ -696,17 +754,42 @@ static int wp_aead_set_param_tls1_iv_rand(wp_AeadCtx* ctx, static int wp_aead_set_ctx_params(wp_AeadCtx* ctx, const OSSL_PARAM params[]) { int ok = 1; +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + /* With the opt-in, fail on the first rejected parameter. */ + int singleParams = ctx->singleUpdate || (params != NULL && + OSSL_PARAM_locate_const(params, WP_PARAM_GCM_SINGLE_UPDATE) != NULL); +#endif WOLFPROV_ENTER(WP_LOG_COMP_AES, "wp_aead_set_ctx_params"); while ((params != NULL) && (params->key != NULL)) { +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + if (ctx->singleUpdate && + (XSTRCMP(params->key, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD) == 0 || + XSTRCMP(params->key, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED) == 0 || + XSTRCMP(params->key, OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV) == 0)) { + ok = 0; + break; + } +#endif /* params->key is a NUL-terminated provider parameter name. Use * XSTRCMP so we never read past the end of the caller's key when * it is shorter than the target constant (e.g. "tlsivinv" vs * "tlsivfixed"). */ if (XSTRCMP(params->key, OSSL_CIPHER_PARAM_AEAD_TAG) == 0) { +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + if (ctx->singleUpdate && (ctx->singleDone || ctx->authErr)) { + ok = 0; + break; + } +#endif ok = wp_aead_set_param_tag(ctx, params); } +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + else if (XSTRCMP(params->key, WP_PARAM_GCM_SINGLE_UPDATE) == 0) { + ok = wp_aead_set_param_single_update(ctx, params); + } +#endif else if (XSTRCMP(params->key, OSSL_CIPHER_PARAM_AEAD_IVLEN) == 0) { ok = wp_aead_set_param_iv_len(ctx, params); } @@ -723,6 +806,11 @@ static int wp_aead_set_ctx_params(wp_AeadCtx* ctx, const OSSL_PARAM params[]) ok = wp_aead_set_param_tls1_iv_rand(ctx, params); } +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + if (!ok && singleParams) { + break; + } +#endif params++; } @@ -826,7 +914,7 @@ static int wp_aead_get_params(OSSL_PARAM params[], unsigned int md, /** * Return an array of supported gettable parameters for the AEAD context. * - * @param [in] ctx AEAD context object. Unused. + * @param [in] ctx AEAD context object. * @param [in] provCtx Provider context object. Unused. * @return Array of parameters with data type. */ @@ -837,6 +925,9 @@ static const OSSL_PARAM *wp_aead_gettable_ctx_params(wp_AeadCtx* ctx, * Supported gettable parameters for AEAD context. */ static const OSSL_PARAM wp_aead_supported_gettable_ctx_params[] = { +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + OSSL_PARAM_int(WP_PARAM_GCM_SINGLE_UPDATE, NULL), +#endif OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), @@ -850,15 +941,23 @@ static const OSSL_PARAM *wp_aead_gettable_ctx_params(wp_AeadCtx* ctx, #endif OSSL_PARAM_END }; + const OSSL_PARAM* ret = wp_aead_supported_gettable_ctx_params; + (void)ctx; (void)provCtx; - return wp_aead_supported_gettable_ctx_params; +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + /* The first descriptor requires a GCM context. */ + if ((ctx == NULL) || (ctx->mode != EVP_CIPH_GCM_MODE)) { + ret++; + } +#endif + return ret; } /** * Return an array of supported settable parameters for the AEAD context. * - * @param [in] ctx AEAD context object. Unused. + * @param [in] ctx AEAD context object. * @param [in] provCtx Provider context object. Unused. * @return Array of parameters with data type. */ @@ -869,6 +968,9 @@ static const OSSL_PARAM *wp_aead_settable_ctx_params(wp_AeadCtx* ctx, * Supported settable parameters for AEAD context. */ static const OSSL_PARAM wp_aead_supported_settable_ctx_params[] = { +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + OSSL_PARAM_int(WP_PARAM_GCM_SINGLE_UPDATE, NULL), +#endif OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL), OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0), @@ -879,9 +981,17 @@ static const OSSL_PARAM *wp_aead_settable_ctx_params(wp_AeadCtx* ctx, #endif OSSL_PARAM_END }; + const OSSL_PARAM* ret = wp_aead_supported_settable_ctx_params; + (void)ctx; (void)provCtx; - return wp_aead_supported_settable_ctx_params; +#if defined(WP_HAVE_AESGCM) && !defined(WOLFSSL_AESGCM_STREAM) + /* The first descriptor requires a GCM context. */ + if ((ctx == NULL) || (ctx->mode != EVP_CIPH_GCM_MODE)) { + ret++; + } +#endif + return ret; } #if defined(WP_HAVE_AESGCM) || defined(WP_HAVE_AESCCM) @@ -908,6 +1018,9 @@ static void wp_aead_reset_op_state(wp_AeadCtx* ctx) } ctx->inLen = 0; ctx->bufSize = 0; + ctx->singleUpdate = 0; + ctx->singleDone = 0; + ctx->singleTagSet = 0; #endif } #endif @@ -1566,6 +1679,88 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out, #else +/** + * Encrypt/decrypt a complete AES-GCM payload in one call. + * + * Decryption requires the expected tag before the payload. + * + * @param [in, out] ctx AEAD context object. + * @param [out] out Buffer to hold encrypted/decrypted data. + * @param [out] outLen Length of data in output buffer. + * @param [in] outSize Size of output buffer in bytes. + * @param [in] in Data to be encrypted/decrypted. + * @param [in] inLen Length of data to be encrypted/decrypted. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_aesgcm_single_update(wp_AeadCtx *ctx, unsigned char *out, + size_t *outLen, size_t outSize, const unsigned char *in, size_t inLen) +{ + int ok = 1; + int rc = 0; + byte empty = 0; + + WOLFPROV_ENTER(WP_LOG_COMP_AES, "wp_aesgcm_single_update"); + + *outLen = 0; + if (ctx->singleDone || ctx->authErr || (!ctx->keySet) || + (ctx->ivState != IV_STATE_BUFFERED) || (!WP_FITS_WORD32(inLen)) || + (!WP_FITS_WORD32(ctx->aadLen)) || (outSize < inLen) || + ((inLen != 0) && ((in == NULL) || (out == NULL))) || + ((!ctx->enc) && (!ctx->singleTagSet))) { + ok = 0; + } + if (ok) { + if (ctx->tagLen == UNINITIALISED_SIZET) { + ctx->tagLen = EVP_GCM_TLS_TAG_LEN; + } + ctx->singleDone = 1; + XMEMCPY(ctx->origIv, ctx->iv, ctx->ivLen); + ctx->ivState = IV_STATE_COPIED; + rc = wc_AesGcmSetExtIV(&ctx->aes, ctx->origIv, (word32)ctx->ivLen); + if (rc != 0) { + WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesGcmSetExtIV", rc); + ok = 0; + } + } + if (ok && ctx->enc) { + ctx->ivSet = 1; + rc = wc_AesGcmEncrypt_ex(&ctx->aes, (out != NULL) ? out : &empty, + (in != NULL) ? in : &empty, (word32)inLen, ctx->origIv, + (word32)ctx->ivLen, ctx->buf, (word32)ctx->tagLen, + ctx->aad, (word32)ctx->aadLen); + if (rc != 0) { + WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesGcmEncrypt_ex", rc); + ok = 0; + } + ctx->tagAvail = ok; + } + else if (ok) { + rc = wc_AesGcmDecrypt(&ctx->aes, (out != NULL) ? out : &empty, + (in != NULL) ? in : &empty, (word32)inLen, ctx->origIv, + (word32)ctx->ivLen, ctx->buf, (word32)ctx->tagLen, + ctx->aad, (word32)ctx->aadLen); + if (rc != 0) { + WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesGcmDecrypt", rc); + ok = 0; + } + } + + if (ok) { + *outLen = inLen; + } + else { + if ((rc != 0) && (out != NULL) && (inLen != 0)) { + OPENSSL_cleanse(out, inLen); + } + ctx->authErr = 1; + ctx->ivState = IV_STATE_FINISHED; + } + + WOLFPROV_LEAVE(WP_LOG_COMP_AES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + /** * Encrypt/decrypt the data using AES-GCM. * @@ -1724,6 +1919,7 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out, { int ok = 1; int process = 0; + int single = 0; size_t curLen = 0; WOLFPROV_ENTER(WP_LOG_COMP_AES, "wp_aesgcm_stream_update"); @@ -1739,6 +1935,10 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out, if (ctx->ivState == IV_STATE_FINISHED) { ok = 0; } + else if (ctx->singleUpdate && ctx->singleDone && inLen != 0) { + ctx->authErr = 1; + ok = 0; + } else if ((out == NULL) && (in == NULL)) { /* Nothing to do. */ oLen = (word32)inLen; @@ -1754,22 +1954,36 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out, ok = 0; } else if (inLen > 0) { - curLen = ctx->inLen; - if (!wp_aead_cache_in(ctx, in, inLen)) { - ok = 0; + if (ctx->singleUpdate) { + single = 1; } else { - process = 1; + curLen = ctx->inLen; + if (!wp_aead_cache_in(ctx, in, inLen)) { + ok = 0; + } + else { + process = 1; + } } } + if (single) { + ok = wp_aesgcm_single_update(ctx, out, outLen, outSize, in, + inLen); + } /* If there is data to process, do it now */ - if (process) { + else if (process) { ok = wp_aesgcm_encdec(ctx, out, outLen, curLen, 0); } else { *outLen = oLen; } + if (!ok && ctx->singleUpdate) { + *outLen = 0; + ctx->authErr = 1; + ctx->ivState = IV_STATE_FINISHED; + } } WOLFPROV_LEAVE(WP_LOG_COMP_AES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); @@ -1794,12 +2008,31 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out, WOLFPROV_ENTER(WP_LOG_COMP_AES, "wp_aesgcm_stream_final"); + /* authErr can bypass the single-update Final branch. */ + if (ctx->singleUpdate) { + *outLen = 0; + } + if (ctx->tlsAadLen != UNINITIALISED_SIZET) { ok = wp_aesgcm_tls_cipher(ctx, out, outLen, NULL, 0); } else if (ctx->authErr) { ok = 0; } + else if (ctx->singleUpdate) { + if (ctx->ivState == IV_STATE_FINISHED) { + ok = 0; + } + else if (!ctx->singleDone) { + ok = wp_aesgcm_single_update(ctx, NULL, outLen, 0, NULL, 0); + } + OPENSSL_free(ctx->aad); + ctx->aad = NULL; + ctx->aadLen = 0; + ctx->aadSet = 0; + ctx->ivSet = 0; + ctx->ivState = IV_STATE_FINISHED; + } else { ok = wp_aesgcm_encdec(ctx, out, outLen, ctx->inLen, 1); ctx->ivSet = 0; diff --git a/test/test_aestag.c b/test/test_aestag.c index ab639e0c..38214eba 100644 --- a/test/test_aestag.c +++ b/test/test_aestag.c @@ -19,6 +19,7 @@ */ #include "unit.h" +#include #ifndef EVP_CCM_TLS_FIXED_IV_LEN #define EVP_CCM_TLS_FIXED_IV_LEN EVP_GCM_TLS_FIXED_IV_LEN @@ -2510,6 +2511,145 @@ int test_aes_gcm_final_no_update_no_iv(void *data) return err; } +#ifndef WOLFSSL_AESGCM_STREAM + +static int test_aes_gcm_single_init(EVP_CIPHER_CTX *ctx, EVP_CIPHER *cipher, + int enc, unsigned char *key, unsigned char *iv, unsigned char *aad, + int aadLen) +{ + OSSL_PARAM params[2]; + int on = 1; + int len = 0; + + params[0] = OSSL_PARAM_construct_int(WP_PARAM_GCM_SINGLE_UPDATE, &on); + params[1] = OSSL_PARAM_construct_end(); + + return (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) == 1) && + (EVP_CIPHER_CTX_set_params(ctx, params) == 1) && + (EVP_CipherUpdate(ctx, NULL, &len, aad, aadLen) == 1); +} + +static EVP_CIPHER_CTX *test_aes_gcm_single_ctx(EVP_CIPHER *cipher, int enc, + unsigned char *key, unsigned char *iv, unsigned char *aad, int aadLen) +{ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + if ((ctx != NULL) && + !test_aes_gcm_single_init(ctx, cipher, enc, key, iv, aad, aadLen)) { + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + } + return ctx; +} + +static int test_aes_gcm_single_dec(EVP_CIPHER *cipher, unsigned char *key, + unsigned char *iv, unsigned char *aad, int aadLen, unsigned char *ct, + int len, unsigned char *tag, unsigned char *pt) +{ + EVP_CIPHER_CTX *ctx; + unsigned char dec[64]; + int decLen = 0, fLen = 0; + int ok; + + ctx = test_aes_gcm_single_ctx(cipher, 0, key, iv, aad, aadLen); + ok = (ctx != NULL) && + (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, tag) == 1) && + (EVP_DecryptUpdate(ctx, dec, &decLen, ct, len) == 1) && + (EVP_DecryptFinal_ex(ctx, dec + decLen, &fLen) == 1) && + (memcmp(dec, pt, len) == 0); + EVP_CIPHER_CTX_free(ctx); + return ok; +} + +int test_aes_gcm_single_update(void *data) +{ + int err; + EVP_CIPHER *ossl; + EVP_CIPHER *wp; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char key[16]; + unsigned char iv[12]; + unsigned char aad[] = "additional data"; + int aadLen = (int)(sizeof(aad) - 1); + unsigned char pt[] = "GCM plaintext for single update test"; + int ptLen = (int)(sizeof(pt) - 1); + unsigned char refCt[64]; + unsigned char refTag[16]; + unsigned char emptyTag[16]; + unsigned char ct[64]; + unsigned char tag[16]; + int len = 0, fLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + + ossl = EVP_CIPHER_fetch(osslLibCtx, "AES-128-GCM", ""); + wp = EVP_CIPHER_fetch(wpLibCtx, "AES-128-GCM", ""); + err = (ossl == NULL) || (wp == NULL); + if (err == 0) { + err = test_aes_tag_enc(ossl, key, iv, sizeof(iv), aad, pt, ptLen, + refCt, refTag, 0, 0); + } + if (err == 0) { + err = test_aes_tag_enc(ossl, key, iv, sizeof(iv), aad, pt, 0, ct, + emptyTag, 0, 0); + } + + if (err == 0) { + PRINT_MSG("Single-update encrypt matches OpenSSL"); + ctx = test_aes_gcm_single_ctx(wp, 1, key, iv, aad, aadLen); + err = (ctx == NULL) || + (EVP_EncryptUpdate(ctx, ct, &len, pt, ptLen) != 1) || + (EVP_EncryptFinal_ex(ctx, ct + len, &fLen) != 1) || + (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tag) != 1) || + (memcmp(ct, refCt, ptLen) != 0) || (memcmp(tag, refTag, 16) != 0); + } + if (err == 0) { + /* The reused context still holds the computed tag. */ + PRINT_MSG("Single-update decrypt rejects a missing tag"); + err = !test_aes_gcm_single_init(ctx, NULL, 0, key, iv, aad, aadLen) || + (EVP_DecryptUpdate(ctx, ct, &len, refCt, ptLen) == 1); + } + EVP_CIPHER_CTX_free(ctx); + if (err == 0) { + PRINT_MSG("Single-update rejects a second payload Update"); + ctx = test_aes_gcm_single_ctx(wp, 1, key, iv, aad, aadLen); + err = (ctx == NULL) || + (EVP_EncryptUpdate(ctx, ct, &len, pt, 16) != 1) || + (EVP_EncryptUpdate(ctx, ct + 16, &len, pt + 16, + ptLen - 16) == 1); + EVP_CIPHER_CTX_free(ctx); + } + if (err == 0) { + PRINT_MSG("Single-update empty Final matches OpenSSL"); + ctx = test_aes_gcm_single_ctx(wp, 1, key, iv, aad, aadLen); + err = (ctx == NULL) || + (EVP_EncryptFinal_ex(ctx, ct, &fLen) != 1) || (fLen != 0) || + (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tag) != 1) || + (memcmp(tag, emptyTag, 16) != 0); + EVP_CIPHER_CTX_free(ctx); + } + if (err == 0) { + PRINT_MSG("Single-update decrypt with early tag"); + err = !test_aes_gcm_single_dec(wp, key, iv, aad, aadLen, refCt, ptLen, + refTag, pt); + } + if (err == 0) { + PRINT_MSG("Single-update decrypt rejects a bad tag"); + refTag[0] ^= 0x01; + err = test_aes_gcm_single_dec(wp, key, iv, aad, aadLen, refCt, ptLen, + refTag, pt); + } + + EVP_CIPHER_free(wp); + EVP_CIPHER_free(ossl); + return err; +} + +#endif /* !WOLFSSL_AESGCM_STREAM */ + #endif /* WP_HAVE_AESGCM */ /******************************************************************************/ diff --git a/test/unit.c b/test/unit.c index be7f72a2..453fa72d 100644 --- a/test/unit.c +++ b/test/unit.c @@ -337,6 +337,9 @@ TEST_CASE test_case[] = { TEST_DECL(test_aes_gcm_key_no_iv, NULL), TEST_DECL(test_aes_gcm_stream_key_no_iv, NULL), TEST_DECL(test_aes_gcm_final_no_update_no_iv, NULL), +#ifndef WOLFSSL_AESGCM_STREAM + TEST_DECL(test_aes_gcm_single_update, NULL), +#endif #endif #ifdef WP_HAVE_AESCCM TEST_DECL(test_aes128_ccm, NULL), diff --git a/test/unit.h b/test/unit.h index 35bc245b..5a0ce806 100644 --- a/test/unit.h +++ b/test/unit.h @@ -298,6 +298,9 @@ int test_aes_gcm_tag_len_undersized(void *data); int test_aes_gcm_key_no_iv(void *data); int test_aes_gcm_stream_key_no_iv(void *data); int test_aes_gcm_final_no_update_no_iv(void *data); +#ifndef WOLFSSL_AESGCM_STREAM +int test_aes_gcm_single_update(void *data); +#endif #endif /* WP_HAVE_AESGCM */