The `num` parameter in DES OFB64/CFB64 functions tracks the byte offset
within an 8-byte DES block, so valid values are 0-7. However, neither
the EVP set_params path nor the low-level DES functions validated this
bound, allowing an out-of-range `num` to cause a stack buffer over-read
when used as an array index into the 8-byte keystream buffer.
Fix at two levels:
1. Provider layer: reject num >= blocksize in
ossl_cipher_common_set_ctx_params() before it reaches the cipher.
2. Low-level DES: mask `*num` with `& 0x07` on entry to
DES_ofb64_encrypt, DES_ede3_ofb64_encrypt, DES_cfb64_encrypt,
and DES_ede3_cfb64_encrypt, consistent with how `n` is already
masked at the end of these functions before being written back.
Fixes #30284
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
MergeDate: Thu Mar 12 14:24:12 2026
(Merged from https://github.com/openssl/openssl/pull/30332)
(cherry picked from commit
134342e194a23b1d3cc0687b05d97cfdd0f31c4a)
{
register DES_LONG v0, v1;
register long l = length;
- register int n = *num;
+ register int n = *num & 0x07;
DES_LONG ti[2];
unsigned char *iv, c, cc;
{
register DES_LONG v0, v1;
register long l = length;
- register int n = *num;
+ register int n = *num & 0x07;
DES_LONG ti[2];
unsigned char *iv, c, cc;
DES_key_schedule *k3, DES_cblock *ivec, int *num)
{
register DES_LONG v0, v1;
- register int n = *num;
+ register int n = *num & 0x07;
register long l = length;
DES_cblock d;
register char *dp;
DES_key_schedule *schedule, DES_cblock *ivec, int *num)
{
register DES_LONG v0, v1, t;
- register int n = *num;
+ register int n = *num & 0x07;
register long l = length;
DES_cblock d;
register unsigned char *dp;
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
+ if (ctx->blocksize > 0 && num >= (unsigned int)ctx->blocksize) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
ctx->num = num;
}
return 1;