Skip to content

Commit 09d3312

Browse files
opera-aklajnmtrojnar
authored andcommitted
Fixed integer overflow, integer underflow and Out-of-Bounds Read
1 parent 9d02a20 commit 09d3312

File tree

8 files changed

+88
-46
lines changed

8 files changed

+88
-46
lines changed

cab.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
342342
const u_char *p = content_val->data;
343343
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
344344
if (idc) {
345-
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
345+
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
346+
fprintf(stderr, "Failed to extract message digest from signature\n\n");
346347
SpcIndirectDataContent_free(idc);
347348
return 0; /* FAILED */
348349
}

cat.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,12 @@ static int cat_print_content_member_digest(ASN1_TYPE *content)
390390
idc = d2i_SpcIndirectDataContent(NULL, &data, ASN1_STRING_length(value));
391391
if (!idc)
392392
return 0; /* FAILED */
393-
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
393+
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
394+
fprintf(stderr, "Failed to extract message digest from signature\n\n");
394395
SpcIndirectDataContent_free(idc);
395396
return 0; /* FAILED */
396397
}
397398
SpcIndirectDataContent_free(idc);
398-
if (mdtype == -1) {
399-
fprintf(stderr, "Failed to extract current message digest\n\n");
400-
return 0; /* FAILED */
401-
}
402399
printf("\tHash algorithm: %s\n", OBJ_nid2sn(mdtype));
403400
print_hash("\tMessage digest", "", mdbuf, EVP_MD_size(EVP_get_digestbynid(mdtype)));
404401
return 1; /* OK */

helpers.c

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -548,33 +548,6 @@ SpcLink *spc_link_obsolete_get(void)
548548
return link;
549549
}
550550

551-
/*
552-
* Safely extract digest from SpcIndirectDataContent
553-
* [in] idc: parsed SpcIndirectDataContent
554-
* [out] mdbuf: output buffer (must be EVP_MAX_MD_SIZE bytes)
555-
* [out] mdtype: digest algorithm's NID
556-
* [returns] -1 on error or digest length on success
557-
*/
558-
int spc_extract_digest_safe(SpcIndirectDataContent *idc,
559-
u_char *mdbuf, int *mdtype)
560-
{
561-
int digest_len;
562-
563-
if (!idc || !idc->messageDigest || !idc->messageDigest->digest ||
564-
!idc->messageDigest->digestAlgorithm) {
565-
fprintf(stderr, "Missing digest data\n");
566-
return -1;
567-
}
568-
digest_len = idc->messageDigest->digest->length;
569-
if (digest_len <= 0 || digest_len > EVP_MAX_MD_SIZE) {
570-
fprintf(stderr, "Invalid digest length: %d\n", digest_len);
571-
return -1;
572-
}
573-
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)digest_len);
574-
*mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
575-
return digest_len;
576-
}
577-
578551
/*
579552
* [in] mdbuf, cmdbuf: message digests
580553
* [in] mdtype: message digest algorithm type
@@ -590,6 +563,37 @@ int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype)
590563
return mdok;
591564
}
592565

566+
/*
567+
* Safely extract digest from SpcIndirectDataContent with bounds checking.
568+
* This function validates that the digest length from the ASN.1 structure
569+
* does not exceed the destination buffer size, preventing buffer overflows
570+
* from maliciously crafted signatures.
571+
* [in] idc: parsed SpcIndirectDataContent structure
572+
* [out] mdbuf: output buffer (must be at least EVP_MAX_MD_SIZE bytes)
573+
* [out] mdtype: digest algorithm NID
574+
* [returns] digest length on success, -1 on error
575+
*/
576+
int spc_indirect_data_content_get_digest(SpcIndirectDataContent *idc, u_char *mdbuf, int *mdtype)
577+
{
578+
int digest_len;
579+
580+
if (!idc || !idc->messageDigest || !idc->messageDigest->digest ||
581+
!idc->messageDigest->digestAlgorithm) {
582+
return -1; /* FAILED */
583+
}
584+
digest_len = idc->messageDigest->digest->length;
585+
586+
/* Validate digest length to prevent buffer overflow */
587+
if (digest_len <= 0 || digest_len > EVP_MAX_MD_SIZE) {
588+
fprintf(stderr, "Invalid digest length in signature: %d (expected 1-%d)\n",
589+
digest_len, EVP_MAX_MD_SIZE);
590+
return -1; /* FAILED */
591+
}
592+
*mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
593+
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)digest_len);
594+
return digest_len; /* OK */
595+
}
596+
593597
/*
594598
* Helper functions
595599
*/
@@ -645,6 +649,10 @@ static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT
645649
idc->data->value->type = V_ASN1_SEQUENCE;
646650
idc->data->value->value.sequence = ASN1_STRING_new();
647651
idc->data->type = ctx->format->data_blob_get(&p, &l, ctx);
652+
if (!idc->data->type) {
653+
SpcIndirectDataContent_free(idc);
654+
return 0; /* FAILED */
655+
}
648656
idc->data->value->value.sequence->data = p;
649657
idc->data->value->value.sequence->length = l;
650658
idc->messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(mdtype);

helpers.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ int is_content_type(PKCS7 *p7, const char *objid);
2424
MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
2525
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
2626
SpcLink *spc_link_obsolete_get(void);
27-
int spc_extract_digest_safe(SpcIndirectDataContent *idc,
28-
u_char *mdbuf, int *mdtype);
2927
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
28+
int spc_indirect_data_content_get_digest(SpcIndirectDataContent *idc, u_char *mdbuf, int *mdtype);
3029

3130
/*
3231
Local Variables:

msi.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,8 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
419419
const u_char *p = content_val->data;
420420
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
421421
if (idc) {
422-
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
422+
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
423+
fprintf(stderr, "Failed to extract message digest from signature\n\n");
423424
SpcIndirectDataContent_free(idc);
424425
return 0; /* FAILED */
425426
}

osslsigncode.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,12 +3082,8 @@ static int verify_content_member_digest(FILE_FORMAT_CTX *ctx, ASN1_TYPE *content
30823082
fprintf(stderr, "Failed to extract SpcIndirectDataContent data\n");
30833083
return 1; /* FAILED */
30843084
}
3085-
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
3086-
SpcIndirectDataContent_free(idc);
3087-
return 1; /* FAILED */
3088-
}
3089-
if (mdtype == -1) {
3090-
fprintf(stderr, "Failed to extract current message digest\n\n");
3085+
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
3086+
fprintf(stderr, "Failed to extract message digest from signature\n\n");
30913087
SpcIndirectDataContent_free(idc);
30923088
return 1; /* FAILED */
30933089
}

pe.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,9 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
255255
SpcIndirectDataContent_free(idc);
256256
return 0; /* FAILED */
257257
}
258-
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
258+
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
259+
fprintf(stderr, "Failed to extract message digest from signature\n\n");
260+
OPENSSL_free(ph);
259261
SpcIndirectDataContent_free(idc);
260262
return 0; /* FAILED */
261263
}
@@ -920,6 +922,8 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
920922
char *sections;
921923
const EVP_MD *md = EVP_get_digestbynid(phtype);
922924
BIO *bhash;
925+
uint32_t filebound;
926+
size_t pphlen_sz, sections_factor;
923927

924928
/* NumberOfSections indicates the size of the section table,
925929
* which immediately follows the headers, can be up to 65535 under Vista and later */
@@ -961,8 +965,29 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
961965
fprintf(stderr, "Corrupted optional header size: 0x%08X\n", opthdr_size);
962966
return NULL; /* FAILED */
963967
}
968+
/* Validate that pagesize >= hdrsize to prevent integer underflow */
969+
if (pagesize < hdrsize) {
970+
fprintf(stderr, "Page size (0x%08X) is smaller than header size (0x%08X)\n",
971+
pagesize, hdrsize);
972+
return NULL; /* FAILED */
973+
}
964974
pphlen = 4 + EVP_MD_size(md);
965-
phlen = pphlen * (3 + (int)nsections + (int)(ctx->pe_ctx->fileend / pagesize));
975+
976+
/* Use size_t arithmetic and check for overflow */
977+
pphlen_sz = (size_t)pphlen;
978+
sections_factor = 3 + (size_t)nsections + ((size_t)ctx->pe_ctx->fileend / pagesize);
979+
980+
/* Check for multiplication overflow */
981+
if (sections_factor > SIZE_MAX / pphlen_sz) {
982+
fprintf(stderr, "Page hash allocation size would overflow\n");
983+
return NULL; /* FAILED */
984+
}
985+
phlen = (int)(pphlen_sz * sections_factor);
986+
/* Sanity limit - page hash shouldn't exceed reasonable size (16 MB) */
987+
if (phlen < 0 || (size_t)phlen > SIZE_16M) {
988+
fprintf(stderr, "Page hash size exceeds limit: %d\n", phlen);
989+
return NULL; /* FAILED */
990+
}
966991

967992
bhash = BIO_new(BIO_f_md());
968993
#if defined(__GNUC__)
@@ -1008,14 +1033,24 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
10081033
BIO_gets(bhash, (char*)res + 4, EVP_MD_size(md));
10091034
BIO_free_all(bhash);
10101035
sections = ctx->options->indata + ctx->pe_ctx->header_size + 24 + opthdr_size;
1036+
/* Determine the file boundary for section data validation */
1037+
filebound = ctx->pe_ctx->sigpos ? ctx->pe_ctx->sigpos : ctx->pe_ctx->fileend;
10111038
for (i=0; i<nsections; i++) {
1012-
/* Resource Table address and size */
1039+
/* SizeOfRawData and PointerToRawData from section header */
10131040
rs = GET_UINT32_LE(sections + 16);
10141041
ro = GET_UINT32_LE(sections + 20);
10151042
if (rs == 0 || rs >= UINT32_MAX) {
10161043
sections += 40;
10171044
continue;
10181045
}
1046+
/* Validate section bounds against file size to prevent OOB read */
1047+
if (ro >= filebound || rs > filebound - ro) {
1048+
fprintf(stderr, "Section %d has invalid bounds: offset=0x%08X, size=0x%08X, fileend=0x%08X\n",
1049+
i, ro, rs, filebound);
1050+
OPENSSL_free(zeroes);
1051+
OPENSSL_free(res);
1052+
return NULL; /* FAILED */
1053+
}
10191054
for (l=0; l<rs; l+=pagesize, pi++) {
10201055
PUT_UINT32_LE(ro + l, res + pi*pphlen);
10211056
bhash = BIO_new(BIO_f_md());
@@ -1088,6 +1123,10 @@ static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int
10881123
if (!ph)
10891124
return 1; /* OK */
10901125
cph = pe_page_hash_calc(&cphlen, ctx, phtype);
1126+
if (!cph) {
1127+
fprintf(stderr, "Page hash verification failed: could not calculate page hash\n");
1128+
return 0; /* FAILED */
1129+
}
10911130
mdok = (phlen == cphlen) && !memcmp(ph, cph, (size_t)phlen);
10921131
printf("Page hash algorithm : %s\n", OBJ_nid2sn(phtype));
10931132
if (ctx->options->verbose) {

script.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
294294
const u_char *p = content_val->data;
295295
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
296296
if (idc) {
297-
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
297+
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
298+
fprintf(stderr, "Failed to extract message digest from signature\n\n");
298299
SpcIndirectDataContent_free(idc);
299300
return 0; /* FAILED */
300301
}

0 commit comments

Comments
 (0)