Skip to content

Commit 1ab2f15

Browse files
committed
Add support for update/final-style AES-GCM to we_aes_gcm_cipher.
OpenSSL's AES-GCM code allows you to call EVP_CipherUpdate() with just the ciphertext and no tag. Then, you set the tag and call EVP_CipherFinal() to check the tag. For the FIPS v2 wolfCrypt module, there's no way to do an AES-GCM decryption without checking the tag. To work around this, defining WE_AES_GCM_DECRYPT_ON_FINAL will do the following: - If we_aes_gcm_cipher is called for decryption when the tag hasn't been set, the ciphertext is saved in a temporary buffer on the we_AesGcm object. - Then, when we_aes_gcm_cipher is called by EVP_CipherFinal() (or similar "final" function), we decrypt the saved ciphertext and check the tag. WE_AES_GCM_DECRYPT_ON_FINAL is not defined by default. Defining it fixes an error when using wolfEngine with OpenVPN and OpenSSL 1.0.2 or later.
1 parent 0e50adc commit 1ab2f15

File tree

1 file changed

+134
-25
lines changed

1 file changed

+134
-25
lines changed

src/we_aes_gcm.c

Lines changed: 134 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ typedef struct we_AesGcm
5858
unsigned char *aad;
5959
/** Length of AAD stored. */
6060
int aadLen;
61+
#ifdef WE_AES_GCM_DECRYPT_ON_FINAL
62+
/* Buffer to hold input data when we_aes_gcm_cipher called to decrypt
63+
* with no tag. */
64+
unsigned char *decryptBuf;
65+
int decryptBufLen;
66+
#endif
67+
/** Flag to indicate if there was a tag error during decryption. */
68+
int tagErr:1;
6169
/** Flag to indicate whether object initialized. */
6270
unsigned int init:1;
6371
/** Flag to indicate whether we are doing encrypt (1) or decrpyt (0). */
@@ -147,6 +155,14 @@ static int we_aes_gcm_cleanup(EVP_CIPHER_CTX *ctx)
147155
if (aes->aad != NULL) {
148156
OPENSSL_free(aes->aad);
149157
}
158+
#ifdef WE_AES_GCM_DECRYPT_ON_FINAL
159+
if (aes->decryptBuf != NULL) {
160+
OPENSSL_free(aes->decryptBuf);
161+
aes->decryptBuf = NULL;
162+
}
163+
aes->decryptBufLen = 0;
164+
#endif
165+
aes->tagErr = 0;
150166
}
151167

152168
return ret;
@@ -241,6 +257,61 @@ static int we_aes_gcm_tls_cipher(we_AesGcm *aes, unsigned char *out,
241257
return ret;
242258
}
243259

260+
/**
261+
* Decrypt the ciphertext and check the tag. If the tag is bad, aes->tagErr will
262+
* be set to 1, but the return value will still be 1 (success).
263+
*
264+
* @param aes [in,out] wolfEngine AES object.
265+
* @param out [out] Buffer to store decrypted result.
266+
* @param in [in] Ciphertext to decrypt.
267+
* @param len [in] Length of ciphertext.
268+
* @return 1 on success and -1 on failure.
269+
*/
270+
static int we_aes_gcm_decrypt(we_AesGcm* aes, unsigned char *out,
271+
const unsigned char *in, size_t len)
272+
{
273+
int ret = 1;
274+
int rc = 0;
275+
276+
WOLFENGINE_ENTER(WE_LOG_CIPHER, "we_aes_gcm_decrypt");
277+
WOLFENGINE_MSG_VERBOSE(WE_LOG_CIPHER, "ARGS [aes = %p, out = %p, in = %p, "
278+
"len = %zu]", aes, out, in, len);
279+
if (aes == NULL || out == NULL || in == NULL) {
280+
WOLFENGINE_ERROR_MSG(WE_LOG_CIPHER, "Bad parameter.");
281+
ret = -1;
282+
}
283+
284+
if (ret == 1) {
285+
/* Decrypt the data, use with AAD to verify tag is correct. */
286+
rc = wc_AesGcmDecrypt(&aes->aes, out, in, (word32)len, aes->iv,
287+
aes->ivLen, aes->tag, aes->tagLen,
288+
aes->aad, aes->aadLen);
289+
if (rc == AES_GCM_AUTH_E) {
290+
/* Defer reporting the tag failure until "final" gets
291+
* called.*/
292+
aes->tagErr = 1;
293+
}
294+
else if (rc != 0) {
295+
WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesGcmDecrypt",
296+
rc);
297+
ret = -1;
298+
}
299+
else {
300+
WOLFENGINE_MSG_VERBOSE(WE_LOG_CIPHER, "Decrypted %zu bytes "
301+
"(AES-GCM):", len);
302+
WOLFENGINE_BUFFER(WE_LOG_CIPHER, out, (unsigned int)len);
303+
WOLFENGINE_MSG(WE_LOG_CIPHER,
304+
"Caching nonce/IV to aes->iv");
305+
/* Cache nonce/IV to guard against accidental reuse. */
306+
XMEMCPY(aes->iv, aes->aes.reg, aes->ivLen);
307+
}
308+
}
309+
310+
WOLFENGINE_LEAVE(WE_LOG_CIPHER, "we_aes_gcm_decrypt", ret);
311+
312+
return ret;
313+
}
314+
244315
/**
245316
* Encrypt/decrypt the data.
246317
* One-shot encrypt/decrypt - not streaming.
@@ -262,6 +333,7 @@ static int we_aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
262333
int rc;
263334
we_AesGcm *aes;
264335
unsigned char *p;
336+
int decryptFinal = 0;
265337

266338
WOLFENGINE_ENTER(WE_LOG_CIPHER, "we_aes_gcm_cipher");
267339
WOLFENGINE_MSG_VERBOSE(WE_LOG_CIPHER, "ARGS [ctx = %p, out = %p, in = %p, "
@@ -275,6 +347,8 @@ static int we_aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
275347
ret = -1;
276348
}
277349

350+
decryptFinal = (!aes->enc && len == 0 && in == NULL);
351+
278352
if ((ret == 1) && aes->tls) {
279353
ret = we_aes_gcm_tls_cipher(aes, out, in, len);
280354
}
@@ -296,7 +370,8 @@ static int we_aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
296370
}
297371
}
298372
/* Length may be zero for cases with AAD data only (GMAC) */
299-
else if ((ret == 1) && (out != NULL) && (in != NULL || aes->aadLen > 0)) {
373+
else if ((ret == 1) && (out != NULL) && (in != NULL || aes->aadLen > 0) &&
374+
!decryptFinal) {
300375
if (aes->enc) {
301376
if (!aes->ivSet) {
302377
/* Set extern IV. */
@@ -330,48 +405,77 @@ static int we_aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
330405
WOLFENGINE_BUFFER(WE_LOG_CIPHER, aes->tag, aes->tagLen);
331406
WOLFENGINE_MSG(WE_LOG_CIPHER, "Caching nonce/IV to aes->iv");
332407

333-
/* Cache nonce/IV. */
408+
/* Cache nonce/IV to guard against accidental reuse. */
334409
XMEMCPY(aes->iv, aes->aes.reg, aes->ivLen);
335410
}
336411
}
337412
else {
338-
/* Decrypt the data, use with AAD to verify tag is correct. */
339-
rc = wc_AesGcmDecrypt(&aes->aes, out, in, (word32)len, aes->iv,
340-
aes->ivLen, aes->tag, aes->tagLen,
341-
aes->aad, aes->aadLen);
342-
if (rc != 0) {
343-
WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesGcmDecrypt_ex", rc);
344-
ret = -1;
413+
#ifdef WE_AES_GCM_DECRYPT_ON_FINAL
414+
if (aes->tagLen == 0) {
415+
WOLFENGINE_MSG_VERBOSE(WE_LOG_CIPHER, "No tag yet, deferring "
416+
"decryption until \"final\" called with tag.");
417+
if (aes->decryptBuf != NULL) {
418+
OPENSSL_free(aes->decryptBuf);
419+
}
420+
aes->decryptBuf = (unsigned char*)OPENSSL_malloc(len);
421+
if (aes->decryptBuf == NULL) {
422+
WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER,
423+
"OPENSSL_malloc", aes->decryptBuf);
424+
ret = -1;
425+
}
426+
else {
427+
XMEMCPY(aes->decryptBuf, in, len);
428+
aes->decryptBufLen = len;
429+
}
345430
}
346-
if (ret == 1) {
347-
348-
WOLFENGINE_MSG_VERBOSE(WE_LOG_CIPHER, "Decrypted %zu bytes "
349-
"(AES-GCM):", len);
350-
WOLFENGINE_BUFFER(WE_LOG_CIPHER, out, (unsigned int)len);
351-
WOLFENGINE_MSG(WE_LOG_CIPHER, "Caching nonce/IV to aes->iv");
352-
353-
/* Cache nonce/IV. */
354-
XMEMCPY(aes->iv, aes->aes.reg, aes->ivLen);
431+
else
432+
#endif
433+
{
434+
ret = we_aes_gcm_decrypt(aes, out, in, len);
355435
}
356436
}
357437

358-
/* Dispose of any AAD - all used now. */
359-
OPENSSL_free(aes->aad);
360-
aes->aad = NULL;
361-
aes->aadLen = 0;
438+
#ifdef WE_AES_GCM_DECRYPT_ON_FINAL
439+
if (aes->enc || (!aes->enc && aes->tagLen > 0))
440+
#endif
441+
{
442+
/* Dispose of any AAD - all used now. */
443+
OPENSSL_free(aes->aad);
444+
aes->aad = NULL;
445+
aes->aadLen = 0;
446+
}
362447
if (ret == 1) {
363448
ret = (int)len;
364449
}
365450
}
366451
else if ((ret == 1) && (len == 0)) {
367-
/* Final called and nothing to do - no data output. */
368-
WOLFENGINE_MSG(WE_LOG_CIPHER, "Final called, nothing to do");
452+
#ifdef WE_AES_GCM_DECRYPT_ON_FINAL
453+
if (!aes->enc) {
454+
ret = we_aes_gcm_decrypt(aes, out, aes->decryptBuf,
455+
aes->decryptBufLen);
456+
457+
OPENSSL_free(aes->decryptBuf);
458+
aes->decryptBuf = NULL;
459+
aes->decryptBufLen = 0;
460+
}
461+
#endif
462+
463+
if (ret == 1) {
464+
if (aes->tagErr) {
465+
WOLFENGINE_ERROR_MSG(WE_LOG_CIPHER, "AES-GCM: tag error.");
466+
ret = -1;
467+
}
468+
else {
469+
ret = 0;
470+
}
471+
}
472+
369473
if (aes->aad != NULL) {
370474
OPENSSL_free(aes->aad);
371475
aes->aad = NULL;
372476
aes->aadLen = 0;
373477
}
374-
ret = 0;
478+
aes->tagErr = 0;
375479
}
376480

377481
WOLFENGINE_LEAVE(WE_LOG_CIPHER, "we_aes_gcm_cipher", ret);
@@ -431,6 +535,11 @@ static int we_aes_gcm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
431535
aes->init = 1;
432536
/* Not doing GCM for TLS unless ctrl function called. */
433537
aes->tls = 0;
538+
#ifdef WE_AES_GCM_DECRYPT_ON_FINAL
539+
aes->decryptBuf = NULL;
540+
aes->decryptBufLen = 0;
541+
#endif
542+
aes->tagErr = 0;
434543
break;
435544

436545
case EVP_CTRL_AEAD_SET_IVLEN:

0 commit comments

Comments
 (0)