/* Provenance: openssl/openssl kek_unwrap_key (fixed). * repo: openssl/openssl * commit: 51d1800e95283a8beec85152e35e3634dab8dd82 * parent: 97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 * commit_url: https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82 * cve: CVE-2026-9076 * license: Apache-2.0 * function: kek_unwrap_key * relpath: crypto/cms/cms_pwri.c */ static int kek_unwrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen, EVP_CIPHER_CTX *ctx) { int blocklen = EVP_CIPHER_CTX_get_block_size(ctx); unsigned char *tmp; int outl, rv = 0; if (blocklen < 4) return 0; if (inlen < 2 * (size_t)blocklen) { /* too small */ return 0; } if (inlen > INT_MAX || inlen % blocklen) { /* Invalid size */ return 0; } if ((tmp = OPENSSL_malloc(inlen)) == NULL) return 0; /* setup IV by decrypting last two blocks */ if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, in + inlen - 2 * blocklen, blocklen * 2) /* * Do a decrypt of last decrypted block to set IV to correct value * output it to start of buffer so we don't corrupt decrypted block * this works because buffer is at least two block lengths long. */ || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp + inlen - blocklen, blocklen) /* Can now decrypt first n - 1 blocks */ || !EVP_DecryptUpdate(ctx, tmp, &outl, in, (int)(inlen - blocklen)) /* Reset IV to original value */ || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) /* Decrypt again */ || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, (int)inlen)) goto err; /* Check check bytes */ if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { /* Check byte failure */ goto err; } if (inlen < 4 + (size_t)tmp[0]) { /* Invalid length value */ goto err; } *outlen = (size_t)tmp[0]; memcpy(out, tmp + 4, *outlen); rv = 1; err: OPENSSL_clear_free(tmp, inlen); return rv; }