]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
AES-GCM: Allow the IV getter to generate the IV if it is not set yet.
authorslontis <shane.lontis@oracle.com>
Fri, 7 Nov 2025 04:22:48 +0000 (15:22 +1100)
committerPauli <paul.dale@oracle.com>
Sun, 9 Nov 2025 20:51:05 +0000 (07:51 +1100)
The EVP_CipherInit API allows mutiple calls to set up parameters such as
the key and iv. If the iv is not specified for encryption, then it is generated
internally during the update phase. If you try to get the IV before the
update it would return an error.
This PR allows the getter to generate the IV early for this case.
This also means that the gen_rand variable needs to be reset to 0 if an
iv is manually set after the getter is called.

Issue found by @davidmakepeace

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/29094)

providers/implementations/ciphers/ciphercommon_gcm.c
test/evp_extra_test.c

index 5bad232bfdf83d20fade14d0e8ce080abb51fe52..ca13834b983f87a01b08236e7bf5b6000f7d7942 100644 (file)
@@ -26,6 +26,7 @@ static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen,
 static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out,
                                size_t *padlen, const unsigned char *in,
                                size_t len);
+static int on_preupdate_generate_iv(PROV_GCM_CTX *ctx);
 
 /*
  * Called from EVP_CipherInit when there is currently no context via
@@ -63,6 +64,7 @@ static int gcm_init(void *vctx, const unsigned char *key, size_t keylen,
             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
             return 0;
         }
+        ctx->iv_gen_rand = 0;
         ctx->ivlen = ivlen;
         memcpy(ctx->iv, iv, ivlen);
         ctx->iv_state = IV_STATE_BUFFERED;
@@ -178,8 +180,12 @@ int ossl_gcm_get_ctx_params(void *vctx, OSSL_PARAM params[])
         }
     }
 
+    /*
+     * Note p.updiv and p.iv are aliases that get the same information,
+     * so any code changes should be duplicated below.
+     */
     if (p.iv != NULL) {
-        if (ctx->iv_state == IV_STATE_UNINITIALISED)
+        if (!on_preupdate_generate_iv(ctx))
             return 0;
         if (ctx->ivlen > p.iv->data_size) {
             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
@@ -190,9 +196,8 @@ int ossl_gcm_get_ctx_params(void *vctx, OSSL_PARAM params[])
             return 0;
         }
     }
-
     if (p.updiv != NULL) {
-        if (ctx->iv_state == IV_STATE_UNINITIALISED)
+        if (!on_preupdate_generate_iv(ctx))
             return 0;
         if (ctx->ivlen > p.updiv->data_size) {
             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
@@ -400,6 +405,21 @@ static int gcm_iv_generate(PROV_GCM_CTX *ctx, int offset)
     return 1;
 }
 
+/*
+ * If we try to grab the iv before the update - it wont be generated yet,
+ * so we generate it here for this case.
+ */
+static int on_preupdate_generate_iv(PROV_GCM_CTX *ctx)
+{
+    if (ctx->iv_state == IV_STATE_UNINITIALISED) {
+        if (ctx->tls_aad_len != UNINITIALISED_SIZET)
+            return 0;
+        if (!ctx->enc || !gcm_iv_generate(ctx, 0))
+            return 0;
+    }
+    return 1;
+}
+
 static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out,
                                size_t *padlen, const unsigned char *in,
                                size_t len)
index ac1b62c4fa2fa183b610cad2f90cb27d4023c5ca..52d684ea678b960e2dd7468e120653b3c24a4545 100644 (file)
@@ -4370,13 +4370,12 @@ static int test_evp_iv_aes(int idx)
         1, 2, 3, 4, 5, 6, 7, 8,
         9, 10, 11, 12, 13, 14, 15, 16
     };
-    unsigned char ciphertext[32], oiv[16], iv[16];
-    unsigned char *ref_iv;
+    unsigned char ciphertext[32], oiv1[16], oiv[16], iv[16], uiv[16];
+    unsigned char *ref_iv, *start_iv = init_iv;
     unsigned char cbc_state[16] = {
         0x10, 0x2f, 0x05, 0xcc, 0xc2, 0x55, 0x72, 0xb9,
         0x88, 0xe6, 0x4a, 0x17, 0x10, 0x74, 0x22, 0x5e
     };
-
     unsigned char ofb_state[16] = {
         0x76, 0xe6, 0x66, 0x61, 0xd0, 0x8a, 0xe4, 0x64,
         0xdd, 0x66, 0xbf, 0x00, 0xf0, 0xe3, 0x6f, 0xfd
@@ -4444,6 +4443,12 @@ static int test_evp_iv_aes(int idx)
         ref_iv = gcm_state;
         ref_len = sizeof(gcm_state);
         break;
+    case 12:
+        ref_iv = NULL;
+        ref_len = 0;
+        start_iv = NULL; /* This will cause a random iv to be generated internally */
+        type = EVP_CIPHER_fetch(testctx, "aes-128-gcm", testpropq);
+        break;
     case 4:
         type = EVP_aes_128_ccm();
         /* FALLTHROUGH */
@@ -4474,7 +4479,8 @@ static int test_evp_iv_aes(int idx)
 
     if (!TEST_ptr(type)
             || !TEST_ptr((ctx = EVP_CIPHER_CTX_new()))
-            || !TEST_true(EVP_EncryptInit_ex(ctx, type, NULL, key, init_iv))
+            || !TEST_true(EVP_EncryptInit_ex(ctx, type, NULL, key, start_iv))
+            || !TEST_true(EVP_CIPHER_CTX_get_original_iv(ctx, oiv1, sizeof(oiv1)))
             || !TEST_true(EVP_EncryptUpdate(ctx, ciphertext, &len, msg,
                           (int)sizeof(msg)))
             || !TEST_true(EVP_CIPHER_CTX_get_original_iv(ctx, oiv, sizeof(oiv)))
@@ -4486,19 +4492,21 @@ static int test_evp_iv_aes(int idx)
     if (!TEST_size_t_gt(ivlen, 0))
         goto err;
 
-    if (!TEST_mem_eq(init_iv, ivlen, oiv, ivlen)
-            || !TEST_mem_eq(ref_iv, ref_len, iv, ivlen))
+    if (start_iv == NULL)
+        start_iv = oiv1;
+    if (!TEST_mem_eq(start_iv, ivlen, oiv, ivlen)
+            || (ref_iv != NULL && !TEST_mem_eq(ref_iv, ref_len, iv, ivlen)))
         goto err;
 
     /* CBC, OFB, and CFB modes: the updated iv must be reset after reinit */
     if (!TEST_true(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, NULL))
-        || !TEST_true(EVP_CIPHER_CTX_get_updated_iv(ctx, iv, sizeof(iv))))
+        || !TEST_true(EVP_CIPHER_CTX_get_updated_iv(ctx, uiv, sizeof(uiv))))
         goto err;
     if (iv_reset) {
-        if (!TEST_mem_eq(init_iv, ivlen, iv, ivlen))
+        if (!TEST_mem_eq(start_iv, ivlen, uiv, ivlen))
             goto err;
     } else {
-        if (!TEST_mem_eq(ref_iv, ivlen, iv, ivlen))
+        if (!TEST_mem_eq(uiv, ivlen, iv, ivlen))
             goto err;
     }
 
@@ -6986,7 +6994,7 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_pkey_ctx_fail_without_provider, 2);
 
     ADD_TEST(test_rand_agglomeration);
-    ADD_ALL_TESTS(test_evp_iv_aes, 12);
+    ADD_ALL_TESTS(test_evp_iv_aes, 13);
 #ifndef OPENSSL_NO_DES
     ADD_ALL_TESTS(test_evp_iv_des, 6);
 #endif