Commit a20fa49828 for openssl.org

commit a20fa498281912c5a34d6d14d2cfb0538fd836cf
Author: Nikola Pajkovsky <nikolap@openssl.org>
Date:   Wed Jul 15 09:41:06 2026 +0200

    test/p_ossltest: fix uninitialised bytes written in TLS1-AAD GCM mode

    The test provider's fake AES-128-GCM cipher works by running the real
    sub-cipher for its side effects and then copying the memdup'd input
    back over the output buffer, so the "encrypted" record is really the
    plaintext.

    In a TLS record the buffer handed to the cipher reserves an
    uninitialised 8-byte explicit IV at the front and a 16-byte auth tag
    at the end for the cipher to fill. OPENSSL_memdup() duplicated those
    uninitialised IV/tag regions, and the subsequent memcpy(out, inbuf, inl)
    copied them into out. That output was then written to the socket,
    triggering valgrind's "Syscall param write(buf) points to uninitialised
    byte(s)":

        at sock_write (bss_sock.c:155)
        by bwrite_conv (bio_meth.c:79)
        by BIO_write (bio_lib.c:397)
        by statem_flush (statem.c:963)
        by ossl_statem_client_post_work (statem_clnt.c:881)
        ...

    Track whether EVP_CTRL_AEAD_TLS1_AAD was set (recorded in
    set_ctx_params) and, when encrypting a TLS record, copy only the
    plaintext payload back, leaving the explicit IV and tag that the real
    sub-cipher actually produced intact.

    Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>

    Reviewed-by: Tim Hudson <tjh@openssl.org>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    MergeDate: Mon Jul 20 09:07:08 2026
    (Merged from https://github.com/openssl/openssl/pull/31961)

diff --git a/test/p_ossltest.c b/test/p_ossltest.c
index 2f545ebf16..06bd9bc64c 100644
--- a/test/p_ossltest.c
+++ b/test/p_ossltest.c
@@ -695,6 +695,7 @@ static const OSSL_DISPATCH ossl_testaes128_cbc_functions[] = {
 typedef struct {
     OSSL_LIB_CTX *libctx;
     EVP_CIPHER_CTX *sub_ctx;
+    int tls1_aad;
 } PROV_EVP_AES128_GCM_CTX;

 /**
@@ -838,10 +839,16 @@ static int ossl_test_aes128gcm_update(void *vprovctx, char *out, size_t *outl,
     size_t inl)
 {
     PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
-    int ret, soutl;
-    uint8_t *inbuf;
+    int ret = 0, soutl = 0;
+    uint8_t *inbuf = NULL;

-    inbuf = OPENSSL_memdup(in, inl);
+    *outl = 0;
+
+    if (in != NULL && inl > 0) {
+        inbuf = OPENSSL_memdup(in, inl);
+        if (inbuf == NULL)
+            goto end;
+    }

     if (EVP_CIPHER_CTX_is_encrypting(ctx->sub_ctx))
         ret = EVP_EncryptUpdate(ctx->sub_ctx, (unsigned char *)out,
@@ -849,16 +856,31 @@ static int ossl_test_aes128gcm_update(void *vprovctx, char *out, size_t *outl,
     else
         ret = EVP_DecryptUpdate(ctx->sub_ctx, (unsigned char *)out,
             &soutl, in, (int)inl);
-    *outl = soutl;

     /*
      * Once the cipher is complete, throw it away and use the
      * plaintext as our output
      */
-    if (inbuf != NULL && out != NULL)
-        memcpy(out, inbuf, inl);
-    OPENSSL_free(inbuf);
+    if (ret > 0 && inbuf != NULL && out != NULL) {
+        if (ctx->tls1_aad && EVP_CIPHER_CTX_is_encrypting(ctx->sub_ctx)) {
+            if (inl < EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN) {
+                ret = 0;
+                goto end;
+            }

+            memcpy(out + EVP_GCM_TLS_EXPLICIT_IV_LEN,
+                inbuf + EVP_GCM_TLS_EXPLICIT_IV_LEN,
+                inl - EVP_GCM_TLS_EXPLICIT_IV_LEN - EVP_GCM_TLS_TAG_LEN);
+        } else {
+            memcpy(out, inbuf, inl);
+        }
+    }
+
+    *outl = soutl;
+
+end:
+    ctx->tls1_aad = 0;
+    OPENSSL_free(inbuf);
     return ret;
 }

@@ -955,8 +977,15 @@ static int ossl_test_aes128gcm_get_ctx_params(void *vprovctx, OSSL_PARAM params[
 static int ossl_test_aes128gcm_set_ctx_params(void *vprovctx, const OSSL_PARAM params[])
 {
     PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+    int tls1_aad;
+    int ret;

-    return EVP_CIPHER_CTX_set_params(ctx->sub_ctx, params);
+    tls1_aad = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD) != NULL;
+    ret = EVP_CIPHER_CTX_set_params(ctx->sub_ctx, params);
+    if (ret)
+        ctx->tls1_aad = tls1_aad;
+
+    return ret;
 }

 /**