]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add an indicator for AES GCM that returns if the iv has been generated
authorslontis <shane.lontis@oracle.com>
Wed, 14 Aug 2024 07:21:54 +0000 (17:21 +1000)
committerPauli <ppzgs1@gmail.com>
Sun, 18 Aug 2024 21:21:28 +0000 (07:21 +1000)
internally.

This is not using a strict check since there may be applications that
require the IV to be generated externally (e.g. java).

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

doc/man3/EVP_EncryptInit.pod
providers/implementations/ciphers/ciphercommon.c
providers/implementations/ciphers/ciphercommon_gcm.c
test/acvp_test.c
util/perl/OpenSSL/paramnames.pm

index 0bad8d48738358febeb5a83dfce403c5849054e6..8e1e0e9e313e5f019ef5b14642df32f035259d4d 100644 (file)
@@ -905,6 +905,16 @@ A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
 This may be used after calling a cipher final operation such as
 EVP_EncryptFinal_ex(). It may return 0 if the "encrypt-check" option is set to 0.
 
+=item "iv-generated" (B<OSSL_CIPHER_PARAM_AEAD_IV_GENERATED>) <unsigned integer>
+
+An indicator that returns 1 if an IV was generated internally during encryption,
+or O otherwise.
+This may be used by GCM ciphers after calling a cipher final operation such
+as EVP_EncryptFinal_ex().
+GCM should generate an IV internally if the IV is not specified during a
+cipher initialisation call such as EVP_CipherInit_ex().
+See FIPS 140-3 IG C.H for information related to IV requirements.
+
 =back
 
 =head2 Settable EVP_CIPHER_CTX parameters
index 7ad3eb0a1f5230c67e73e26164ef76e275c9da72..a0b0f95ede898f308e1fad91c35e0e13e23ba19f 100644 (file)
@@ -152,6 +152,7 @@ static const OSSL_PARAM cipher_aead_known_gettable_ctx_params[] = {
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
     OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
     OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN, NULL, 0),
+    OSSL_PARAM_uint(OSSL_CIPHER_PARAM_AEAD_IV_GENERATED, NULL),
     OSSL_PARAM_END
 };
 const OSSL_PARAM *ossl_cipher_aead_gettable_ctx_params(
index fe24b450a5b027355c13f4ce046b83ff58af5d5d..4be2e1c94dfb91ef0c8fb35ad97fca51025fde91 100644 (file)
@@ -236,6 +236,9 @@ int ossl_gcm_get_ctx_params(void *vctx, OSSL_PARAM params[])
                 || !getivgen(ctx, p->data, p->data_size))
                 return 0;
             break;
+        case PIDX_CIPHER_PARAM_AEAD_IV_GENERATED:
+            if (!OSSL_PARAM_set_uint(p, ctx->iv_gen_rand))
+                return 0;
         }
     }
     return 1;
@@ -513,9 +516,11 @@ static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv,
             return 0;
     if (len > 0)
         memcpy(ctx->iv, iv, len);
-    if (ctx->enc
-        && RAND_bytes_ex(ctx->libctx, ctx->iv + len, ctx->ivlen - len, 0) <= 0)
+    if (ctx->enc) {
+        if (RAND_bytes_ex(ctx->libctx, ctx->iv + len, ctx->ivlen - len, 0) <= 0)
             return 0;
+        ctx->iv_gen_rand = 1;
+    }
     ctx->iv_gen = 1;
     ctx->iv_state = IV_STATE_BUFFERED;
     return 1;
index 341410ef2be20c7099b331e0994acc7fe4c6cc8c..44f7249505af62c5ecb5c56f31adc24e1f63755b 100644 (file)
@@ -829,13 +829,14 @@ static int aes_gcm_enc_dec(const char *alg,
                            const unsigned char *aad, size_t aad_len,
                            const unsigned char *ct, size_t ct_len,
                            const unsigned char *tag, size_t tag_len,
-                           int enc, int pass)
+                           int enc, int pass,
+                           unsigned char *out, int *out_len,
+                           unsigned char *outiv)
 {
     int ret = 0;
     EVP_CIPHER_CTX *ctx;
     EVP_CIPHER *cipher = NULL;
-    int out_len, len;
-    unsigned char out[1024];
+    int olen, len;
 
     TEST_note("%s : %s : expected to %s", alg, enc ? "encrypt" : "decrypt",
               pass ? "pass" : "fail");
@@ -853,9 +854,9 @@ static int aes_gcm_enc_dec(const char *alg,
             goto err;
     }
     /*
-     * For testing purposes the IV it being set here. In a compliant application
-     * the IV would be generated internally. A fake entropy source could also
-     * be used to feed in the random IV bytes (see fake_random.c)
+     * For testing purposes the IV may be passed in here. In a compliant
+     * application the IV would be generated internally. A fake entropy source
+     * could also be used to feed in the random IV bytes (see fake_random.c)
      */
     if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc))
         || !TEST_true(EVP_CIPHER_CTX_set_padding(ctx, 0))
@@ -863,23 +864,41 @@ static int aes_gcm_enc_dec(const char *alg,
         || !TEST_true(EVP_CipherUpdate(ctx, out, &len, pt, pt_len)))
         goto err;
 
-    if (!TEST_int_eq(EVP_CipherFinal_ex(ctx, out + len, &out_len), pass))
+    if (!TEST_int_eq(EVP_CipherFinal_ex(ctx, out + len, &olen), pass))
         goto err;
     if (!pass) {
         ret = 1;
         goto err;
     }
-    out_len += len;
+    olen += len;
     if (enc) {
-        if (!TEST_mem_eq(out, out_len, ct, ct_len)
-            || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG,
-                                              tag_len, out + out_len), 0)
-            || !TEST_mem_eq(out + out_len, tag_len, tag, tag_len))
-                    goto err;
+        if ((ct != NULL && !TEST_mem_eq(out, olen, ct, ct_len))
+                || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG,
+                                                    tag_len, out + olen), 0)
+                || (tag != NULL
+                    && !TEST_mem_eq(out + olen, tag_len, tag, tag_len)))
+            goto err;
     } else {
-        if (!TEST_mem_eq(out, out_len, ct, ct_len))
+        if (ct != NULL && !TEST_mem_eq(out, olen, ct, ct_len))
+            goto err;
+    }
+
+    {
+        OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
+        unsigned int iv_generated = -1;
+
+        params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_AEAD_IV_GENERATED,
+                                              &iv_generated);
+        if (outiv != NULL)
+            params[1] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_IV,
+                                                          outiv, iv_len);
+        if (!TEST_true(EVP_CIPHER_CTX_get_params(ctx, params)))
+            goto err;
+        if (!TEST_uint_eq(iv_generated, (enc == 0 || iv != NULL ? 0 : 1)))
             goto err;
     }
+    if (out_len != NULL)
+        *out_len = olen;
 
     ret = 1;
 err:
@@ -893,23 +912,45 @@ static int aes_gcm_enc_dec_test(int id)
     const struct cipher_gcm_st *tst = &aes_gcm_enc_data[id];
     int enc = 1;
     int pass = 1;
+    unsigned char out[1024];
 
     return aes_gcm_enc_dec(tst->alg, tst->pt, tst->pt_len,
                            tst->key, tst->key_len,
                            tst->iv, tst->iv_len, tst->aad, tst->aad_len,
                            tst->ct, tst->ct_len, tst->tag, tst->tag_len,
-                           enc, pass)
+                           enc, pass, out, NULL, NULL)
             && aes_gcm_enc_dec(tst->alg, tst->ct, tst->ct_len,
                                tst->key, tst->key_len,
                                tst->iv, tst->iv_len, tst->aad, tst->aad_len,
                                tst->pt, tst->pt_len, tst->tag, tst->tag_len,
-                               !enc, pass)
+                               !enc, pass, out, NULL, NULL)
             /* Fail if incorrect tag passed to decrypt */
             && aes_gcm_enc_dec(tst->alg, tst->ct, tst->ct_len,
                                tst->key, tst->key_len,
                                tst->iv, tst->iv_len, tst->aad, tst->aad_len,
                                tst->pt, tst->pt_len, tst->aad, tst->tag_len,
-                               !enc, !pass);
+                               !enc, !pass, out, NULL, NULL);
+}
+
+static int aes_gcm_gen_iv_internal_test(void)
+{
+    const struct cipher_gcm_st *tst = &aes_gcm_enc_data[0];
+    int enc = 1;
+    int pass = 1;
+    int out_len = 0;
+    unsigned char out[1024];
+    unsigned char iv[16];
+
+    return aes_gcm_enc_dec(tst->alg, tst->pt, tst->pt_len,
+                           tst->key, tst->key_len,
+                           NULL, tst->iv_len, tst->aad, tst->aad_len,
+                           NULL, tst->ct_len, NULL, tst->tag_len,
+                           enc, pass, out, &out_len, iv)
+            && aes_gcm_enc_dec(tst->alg, out, out_len,
+                               tst->key, tst->key_len,
+                               iv, tst->iv_len, tst->aad, tst->aad_len,
+                               tst->pt, tst->pt_len, out + out_len, tst->tag_len,
+                               !enc, pass, out, NULL, NULL);
 }
 
 #ifndef OPENSSL_NO_DH
@@ -1492,6 +1533,8 @@ int setup_tests(void)
     ADD_ALL_TESTS(cipher_enc_dec_test, OSSL_NELEM(cipher_enc_data));
     ADD_ALL_TESTS(aes_ccm_enc_dec_test, OSSL_NELEM(aes_ccm_enc_data));
     ADD_ALL_TESTS(aes_gcm_enc_dec_test, OSSL_NELEM(aes_gcm_enc_data));
+    if (fips_provider_version_ge(libctx, 3, 4, 0))
+        ADD_TEST(aes_gcm_gen_iv_internal_test);
 
     pass_sig_gen_params = fips_provider_version_ge(libctx, 3, 4, 0);
     rsa_sign_x931_pad_allowed = fips_provider_version_lt(libctx, 3, 4, 0);
index 1fadafc7cf50d213b1979e6ea9e6a0b7cd154673..e4edb550be03dae3d7243c951ddd6ffab6bc358d 100644 (file)
@@ -115,6 +115,7 @@ my %params = (
     'CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN' => "tlsivgen",    # octet_string
     'CIPHER_PARAM_AEAD_TLS1_SET_IV_INV' => "tlsivinv",    # octet_string
     'CIPHER_PARAM_AEAD_IVLEN' =>           '*CIPHER_PARAM_IVLEN',
+    'CIPHER_PARAM_AEAD_IV_GENERATED' => "iv-generated",   # uint
     'CIPHER_PARAM_AEAD_TAGLEN' =>          "taglen",      # size_t
     'CIPHER_PARAM_AEAD_MAC_KEY' =>         "mackey",      # octet_string
     'CIPHER_PARAM_RANDOM_KEY' =>           "randkey",     # octet_string