One can duplicate the entire EVP_CIPHER_CTX with a call to
EVP_CIPHER_CTX_copy.
By default the state (cipher_data) is duplicated bytewize (malloc+memcpy).
Since AES
gcm has pointers in its state this naive copy method leads to crashes.
diff -ur /tmp/openssl/crypto/evp/e_aes.c /home/test/openssl/crypto/evp/e_aes.c
--- /tmp/openssl/crypto/evp/e_aes.c 2014-02-28 19:26:02.105531053 +0400
+++ /home/test/openssl/crypto/evp/e_aes.c 2014-02-28 17:53:07.545605738 +0400
@@ -1231,6 +1231,22 @@
/* Extra padding: tag appended to record */
return EVP_GCM_TLS_TAG_LEN;
+ case EVP_CTRL_COPY:
+ {
+ EVP_CIPHER_CTX *out = ptr;
+ EVP_AES_GCM_CTX *gctx_out = out->cipher_data;
+ if (gctx->iv == c->iv)
+ gctx_out->iv = out->iv;
+ else
+ {
+ gctx_out->iv = OPENSSL_malloc(gctx->ivlen);
+ if (!gctx_out->iv)
+ return 0;
+ memcpy(gctx_out->iv, gctx->iv, gctx->ivlen);
+ }
+ return 1;
+ }
+
default:
return -1;
@@ -1605,7 +1621,8 @@
#define CUSTOM_FLAGS (EVP_CIPH_FLAG_DEFAULT_ASN1 \
| EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
- | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT)
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \
+ | EVP_CIPH_CUSTOM_COPY)
BLOCK_CIPHER_custom(NID_aes,128,1,12,gcm,GCM,
EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS)