Fix NULL derefs, buffer overflow, and i2d contract in EVP/OCSP/X509

Harden OpenSSL compatibility layer against NULL pointers, negative lengths,
and buffer overflows across EVP, OCSP, and X509 APIs. Fix DSA SignFinal
write-before-check overflow, add missing i2d_OCSP_RESPONSE allocation path,
and fix unaligned keyUsage access.
This commit is contained in:
Colton Willey
2026-04-13 20:29:50 -07:00
parent c36beba9b7
commit 58a27848a8
6 changed files with 94 additions and 20 deletions
+32 -7
View File
@@ -749,7 +749,9 @@ int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
single = bs->single;
while (single != NULL) {
if ((XMEMCMP(single->status->serial, id->status->serial, (size_t)single->status->serialSz) == 0)
if (single->status != NULL && id->status != NULL &&
(XMEMCMP(single->status->serial, id->status->serial,
(size_t)single->status->serialSz) == 0)
&& (XMEMCMP(single->issuerHash, id->issuerHash, OCSP_DIGEST_SIZE) == 0)
&& (XMEMCMP(single->issuerKeyHash, id->issuerKeyHash, OCSP_DIGEST_SIZE) == 0)) {
break;
@@ -757,7 +759,7 @@ int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
single = single->next;
}
if (single == NULL)
if (single == NULL || single->status == NULL)
return WOLFSSL_FAILURE;
if (status != NULL)
@@ -1108,6 +1110,9 @@ int wolfSSL_OCSP_basic_verify(WOLFSSL_OCSP_BASICRESP* bs,
int embedded;
DecodedCert *cert = NULL;
if (bs == NULL)
return WOLFSSL_FAILURE;
ret = OcspFindSigner(bs, certs, &cert, &embedded, flags);
if (ret != 0) {
WOLFSSL_MSG("OCSP no signer found");
@@ -1300,15 +1305,31 @@ int wolfSSL_i2d_OCSP_RESPONSE(OcspResponse* response,
if (response == NULL)
return BAD_FUNC_ARG;
if (response->source == NULL)
return BAD_FUNC_ARG;
if (data == NULL)
return (int)response->maxIdx;
XMEMCPY(*data, response->source, response->maxIdx);
if (*data == NULL) {
*data = (unsigned char*)XMALLOC(response->maxIdx, NULL,
DYNAMIC_TYPE_OPENSSL);
if (*data == NULL)
return -1;
XMEMCPY(*data, response->source, response->maxIdx);
}
else {
XMEMCPY(*data, response->source, response->maxIdx);
*data += response->maxIdx;
}
return (int)response->maxIdx;
}
int wolfSSL_OCSP_response_status(OcspResponse *response)
{
if (response == NULL)
return -1;
return response->responseStatus;
}
@@ -1335,8 +1356,12 @@ const char *wolfSSL_OCSP_response_status_str(long s)
WOLFSSL_OCSP_BASICRESP* wolfSSL_OCSP_response_get1_basic(OcspResponse* response)
{
WOLFSSL_OCSP_BASICRESP* bs;
const unsigned char *ptr = response->source;
const unsigned char *ptr;
if (response == NULL || response->source == NULL)
return NULL;
ptr = response->source;
bs = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, response->maxIdx);
return bs;
}
@@ -1637,8 +1662,8 @@ int wolfSSL_OCSP_single_get0_status(WOLFSSL_OCSP_SINGLERESP *single,
WOLFSSL_ASN1_TIME **thisupd,
WOLFSSL_ASN1_TIME **nextupd)
{
if (single == NULL)
return WOLFSSL_FAILURE;
if (single == NULL || single->status == NULL)
return -1;
#ifdef WOLFSSL_OCSP_PARSE_STATUS
if (thisupd != NULL)
@@ -1784,7 +1809,7 @@ int wolfSSL_OCSP_REQ_CTX_add1_header(WOLFSSL_OCSP_REQ_CTX *ctx,
{
WOLFSSL_ENTER("wolfSSL_OCSP_REQ_CTX_add1_header");
if (name == NULL) {
if (ctx == NULL || name == NULL) {
WOLFSSL_MSG("Bad parameter");
return WOLFSSL_FAILURE;
}
+7 -1
View File
@@ -11699,13 +11699,19 @@ char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in,
int wolfSSL_OCSP_parse_url(const char* url, char** host, char** port,
char** path, int* ssl)
{
const char* u = url;
const char* u;
const char* upath; /* path in u */
const char* uport; /* port in u */
const char* hostEnd;
WOLFSSL_ENTER("OCSP_parse_url");
if (url == NULL || host == NULL || port == NULL || path == NULL ||
ssl == NULL) {
return WOLFSSL_FAILURE;
}
u = url;
*host = NULL;
*port = NULL;
*path = NULL;
+10 -2
View File
@@ -1317,7 +1317,9 @@ int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext,
if (ext && ext->value.data) {
if (ext->value.length == sizeof(word16)) {
/* if ext->value is already word16, set directly */
x509->keyUsage = *(word16*)ext->value.data;
word16 ku;
XMEMCPY(&ku, ext->value.data, sizeof(word16));
x509->keyUsage = ku;
#ifdef BIG_ENDIAN_ORDER
x509->keyUsage = rotlFixed16(x509->keyUsage, 8U);
#endif
@@ -10998,6 +11000,11 @@ WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509* x509)
if (x509->serialNumber != NULL)
return x509->serialNumber;
if (x509->serialSz < 0) {
WOLFSSL_MSG("Invalid serial number size");
return NULL;
}
a = wolfSSL_ASN1_INTEGER_new();
if (a == NULL)
return NULL;
@@ -16120,7 +16127,8 @@ int wolfSSL_X509_set1_notBefore(WOLFSSL_X509* x509, const WOLFSSL_ASN1_TIME *t)
int wolfSSL_X509_set_serialNumber(WOLFSSL_X509* x509, WOLFSSL_ASN1_INTEGER* s)
{
WOLFSSL_ENTER("wolfSSL_X509_set_serialNumber");
if (x509 == NULL || s == NULL || s->length >= EXTERNAL_SERIAL_SIZE)
if (x509 == NULL || s == NULL || s->data == NULL ||
s->length >= EXTERNAL_SERIAL_SIZE)
return WOLFSSL_FAILURE;
/* WOLFSSL_ASN1_INTEGER has type | size | data
+1 -1
View File
@@ -20274,7 +20274,7 @@ static int test_wolfSSL_OCSP_single_get0_status(void)
ExpectPtrEq(nextDate, &certStatus.nextDateParsed);
ExpectIntEQ(wolfSSL_OCSP_single_get0_status(NULL, NULL, NULL, NULL, NULL),
CERT_GOOD);
-1);
ExpectIntEQ(wolfSSL_OCSP_single_get0_status(&single, NULL, NULL, NULL,
NULL), CERT_GOOD);
#endif
+41 -9
View File
@@ -1314,7 +1314,11 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out,
#ifndef WOLFSSL_AESGCM_STREAM
if ((ctx->authBuffer && ctx->authBufferLen > 0)
|| (ctx->authBufferLen == 0)) {
if (ctx->enc)
if (ctx->authBufferLen > 0 && out == NULL) {
ret = WOLFSSL_FAILURE;
*outl = 0;
}
else if (ctx->enc)
ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out,
ctx->authBuffer, ctx->authBufferLen,
ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz,
@@ -1397,7 +1401,11 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out,
case WC_AES_256_CCM_TYPE:
if ((ctx->authBuffer && ctx->authBufferLen > 0)
|| (ctx->authBufferLen == 0)) {
if (ctx->enc) {
if (ctx->authBufferLen > 0 && out == NULL) {
ret = WOLFSSL_FAILURE;
*outl = 0;
}
else if (ctx->enc) {
ret = wc_AesCcmEncrypt(&ctx->cipher.aes, out,
ctx->authBuffer, (word32)ctx->authBufferLen,
ctx->iv, (word32)ctx->ivSz, ctx->authTag,
@@ -4309,16 +4317,19 @@ int wolfSSL_EVP_SignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sigret,
#ifndef NO_DSA
case WC_EVP_PKEY_DSA: {
int bytes;
ret = wolfSSL_DSA_do_sign(md, sigret, pkey->dsa);
unsigned char tmpSig[DSA_MAX_SIG_SIZE];
ret = wolfSSL_DSA_do_sign(md, tmpSig, pkey->dsa);
/* wolfSSL_DSA_do_sign() can return WOLFSSL_FATAL_ERROR */
if (ret != WOLFSSL_SUCCESS)
return ret;
bytes = wolfSSL_BN_num_bytes(pkey->dsa->q);
if (bytes == WC_NO_ERR_TRACE(WOLFSSL_FAILURE) ||
(int)*siglen < bytes * 2)
bytes > DSA_MAX_HALF_SIZE ||
bytes * 2 > (int)*siglen)
{
return WOLFSSL_FAILURE;
}
XMEMCPY(sigret, tmpSig, bytes * 2);
*siglen = (unsigned int)(bytes * 2);
return WOLFSSL_SUCCESS;
}
@@ -4398,7 +4409,8 @@ int wolfSSL_EVP_VerifyFinal(WOLFSSL_EVP_MD_CTX *ctx,
unsigned char md[WC_MAX_DIGEST_SIZE];
unsigned int mdsize;
if (ctx == NULL) return WOLFSSL_FAILURE;
if (ctx == NULL || pkey == NULL || sig == NULL)
return WOLFSSL_FAILURE;
WOLFSSL_ENTER("EVP_VerifyFinal");
ret = wolfSSL_EVP_DigestFinal(ctx, md, &mdsize);
if (ret <= 0)
@@ -4459,6 +4471,9 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_mac_key(int type, WOLFSSL_ENGINE* e,
if (type != WC_EVP_PKEY_HMAC || (key == NULL && keylen != 0))
return NULL;
if (keylen < 0)
return NULL;
pkey = wolfSSL_EVP_PKEY_new();
if (pkey != NULL) {
pkey->pkey.ptr = (char*)XMALLOC((size_t)keylen, NULL,
@@ -4870,6 +4885,9 @@ int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig,
return WOLFSSL_SUCCESS;
}
}
else if (ctx->pctx == NULL || ctx->pctx->pkey == NULL) {
return WOLFSSL_FAILURE;
}
#ifndef NO_RSA
else if (ctx->pctx->pkey->type == WC_EVP_PKEY_RSA) {
if (sig == NULL) {
@@ -5007,6 +5025,8 @@ int wolfSSL_EVP_DigestVerifyFinal(WOLFSSL_EVP_MD_CTX *ctx,
return WOLFSSL_FAILURE;
}
else {
if (ctx->pctx == NULL || ctx->pctx->pkey == NULL)
return WOLFSSL_FAILURE;
/* Verify the signature with the digest. */
switch (ctx->pctx->pkey->type) {
#if !defined(NO_RSA)
@@ -10233,6 +10253,9 @@ int wolfSSL_EVP_Digest(const unsigned char* in, int inSz, unsigned char* out,
return WOLFSSL_FAILURE;
}
if (inSz < 0)
return WOLFSSL_FAILURE;
err = wolfSSL_EVP_get_hashinfo(evp, &hashType, &hashSz);
if (err != WOLFSSL_SUCCESS)
return err;
@@ -11280,6 +11303,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
enum wc_HashType macType;
WOLFSSL_ENTER("wolfSSL_EVP_DigestFinal");
macType = EvpMd2MacType(wolfSSL_EVP_MD_CTX_md(ctx));
switch (macType) {
case WC_HASH_TYPE_MD4:
@@ -11305,16 +11329,18 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
case WC_HASH_TYPE_SHAKE128:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
*s = 16; /* if mixing up XOF with plain digest 128 bit is
* default for SHAKE128 */
if (s != NULL)
*s = 16; /* if mixing up XOF with plain digest 128 bit is
* default for SHAKE128 */
#else
return WOLFSSL_FAILURE;
#endif
break;
case WC_HASH_TYPE_SHAKE256:
#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
*s = 32; /* if mixing up XOF with plain digest 256 bit is
* default for SHAKE256 */
if (s != NULL)
*s = 32; /* if mixing up XOF with plain digest 256 bit is
* default for SHAKE256 */
#else
return WOLFSSL_FAILURE;
#endif
@@ -12882,6 +12908,9 @@ int wolfSSL_EVP_EncodeBlock(unsigned char *out, const unsigned char *in,
if (out == NULL || in == NULL)
return WOLFSSL_FATAL_ERROR;
if (inLen < 0)
return WOLFSSL_FATAL_ERROR;
if (Base64_Encode_NoNl(in, (word32)inLen, out, &ret) == 0)
return (int)ret;
else
@@ -12898,6 +12927,9 @@ int wolfSSL_EVP_DecodeBlock(unsigned char *out, const unsigned char *in,
if (out == NULL || in == NULL)
return WOLFSSL_FATAL_ERROR;
if (inLen < 0)
return WOLFSSL_FATAL_ERROR;
if (Base64_Decode(in, (word32)inLen, out, &ret) == 0)
return (int)ret;
else
+3
View File
@@ -76,6 +76,9 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
return BAD_FUNC_ARG;
}
if (keyLen > INT_MAX - ivLen)
return BAD_FUNC_ARG;
if (iterations <= 0)
iterations = 1;