@@ -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