large CAB file support

This commit is contained in:
olszomal 2022-09-29 14:44:21 +02:00 committed by Michał Trojnara
parent db556d0a2d
commit 454e15326d

View File

@ -796,13 +796,17 @@ static int blob_has_nl = 0;
/* /*
* Callback for writing received data * Callback for writing received data
*/ */
static int curl_write(void *ptr, size_t sz, size_t nmemb, void *stream) static size_t curl_write(void *ptr, size_t sz, size_t nmemb, void *stream)
{ {
if (sz*nmemb > 0 && !blob_has_nl) { size_t written, len = sz * nmemb;
if (memchr(ptr, '\n', sz*nmemb))
if (len > 0 && !blob_has_nl) {
if (memchr(ptr, '\n', len))
blob_has_nl = 1; blob_has_nl = 1;
} }
return BIO_write((BIO*)stream, ptr, (int)(sz*nmemb)); if (!BIO_write_ex((BIO*)stream, ptr, len, &written) || written != len)
return 0; /* FAILED */
return written;
} }
static void print_timestamp_error(const char *url, long http_code) static void print_timestamp_error(const char *url, long http_code)
@ -3167,10 +3171,11 @@ static PKCS7 *msi_extract_existing_pkcs7(MSI_PARAMS *msiparams, MSI_ENTRY *ds, c
static int msi_extract_file(MSI_PARAMS *msiparams, BIO *outdata, int output_pkcs7) static int msi_extract_file(MSI_PARAMS *msiparams, BIO *outdata, int output_pkcs7)
{ {
int ret; int ret = 0;
PKCS7 *sig; PKCS7 *sig;
uint32_t len; uint32_t len;
char *data; char *data;
size_t written;
MSI_ENTRY *ds = msi_signatures_get(msiparams->dirent, NULL); MSI_ENTRY *ds = msi_signatures_get(msiparams->dirent, NULL);
if (!ds) { if (!ds) {
@ -3188,7 +3193,8 @@ static int msi_extract_file(MSI_PARAMS *msiparams, BIO *outdata, int output_pkcs
if (output_pkcs7) { if (output_pkcs7) {
ret = !PEM_write_bio_PKCS7(outdata, sig); ret = !PEM_write_bio_PKCS7(outdata, sig);
} else { } else {
ret = !BIO_write(outdata, data, (int)len); if (!BIO_write_ex(outdata, data, len, &written) || written != len)
ret = 1; /* FAILED */
} }
PKCS7_free(sig); PKCS7_free(sig);
OPENSSL_free(data); OPENSSL_free(data);
@ -3282,7 +3288,7 @@ static int pe_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER *
BIO *bio = NULL; BIO *bio = NULL;
u_char *bfb; u_char *bfb;
EVP_MD_CTX *mdctx; EVP_MD_CTX *mdctx;
size_t written; size_t written, nread;
uint32_t i, n, offset; uint32_t i, n, offset;
int ret = 0; int ret = 0;
const EVP_MD *md = EVP_get_digestbynid(mdtype); const EVP_MD *md = EVP_get_digestbynid(mdtype);
@ -3300,20 +3306,21 @@ static int pe_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER *
memset(mdbuf, 0, EVP_MAX_MD_SIZE); memset(mdbuf, 0, EVP_MAX_MD_SIZE);
bio = BIO_new(BIO_s_mem()); bio = BIO_new(BIO_s_mem());
i = n = header->header_size + 88 + 4 + 60 + header->pe32plus * 16 + 8; i = n = header->header_size + 88 + 4 + 60 + header->pe32plus * 16 + 8;
if (!BIO_write_ex(bio, indata, i, &written)) if (!BIO_write_ex(bio, indata, i, &written) || written != i)
goto err; goto err;
(void)BIO_seek(bio, 0); (void)BIO_seek(bio, 0);
bfb = OPENSSL_malloc(SIZE_64K); bfb = OPENSSL_malloc(SIZE_64K);
BIO_read(bio, bfb, (int)header->header_size + 88); if (!BIO_read_ex(bio, bfb, header->header_size + 88, &nread))
goto err;
EVP_DigestUpdate(mdctx, bfb, header->header_size + 88); EVP_DigestUpdate(mdctx, bfb, header->header_size + 88);
BIO_read(bio, bfb, 4); BIO_read(bio, bfb, 4);
BIO_read(bio, bfb, 60 + (int)header->pe32plus * 16); if (!BIO_read_ex(bio, bfb, 60 + header->pe32plus * 16, &nread))
goto err;
EVP_DigestUpdate(mdctx, bfb, 60 + header->pe32plus * 16); EVP_DigestUpdate(mdctx, bfb, 60 + header->pe32plus * 16);
BIO_read(bio, bfb, 8); BIO_read(bio, bfb, 8);
while (n < offset) { while (n < offset) {
size_t nread;
uint32_t want = offset - n; uint32_t want = offset - n;
if (i <= n) { if (i <= n) {
@ -3551,6 +3558,7 @@ static int pe_extract_file(char *indata, FILE_HEADER *header, BIO *outdata, int
{ {
int ret = 0; int ret = 0;
PKCS7 *sig; PKCS7 *sig;
size_t written;
(void)BIO_reset(outdata); (void)BIO_reset(outdata);
if (output_pkcs7) { if (output_pkcs7) {
@ -3562,8 +3570,9 @@ static int pe_extract_file(char *indata, FILE_HEADER *header, BIO *outdata, int
ret = !PEM_write_bio_PKCS7(outdata, sig); ret = !PEM_write_bio_PKCS7(outdata, sig);
PKCS7_free(sig); PKCS7_free(sig);
} else } else
ret = !BIO_write(outdata, indata + header->sigpos, (int)header->siglen); if (!BIO_write_ex(outdata, indata + header->sigpos, header->siglen, &written) \
|| written != header->siglen)
ret = 1; /* FAILED */
return ret; return ret;
} }
@ -3648,7 +3657,8 @@ static int pe_modify_header(char *indata, FILE_HEADER *header, BIO *hash, BIO *o
i += 8; i += 8;
len = header->fileend - i; len = header->fileend - i;
while (len > 0) { while (len > 0) {
BIO_write_ex(hash, indata + i, len, &written); if (!BIO_write_ex(hash, indata + i, len, &written))
return 0; /* FAILED */
len -= written; len -= written;
i += written; i += written;
} }
@ -3736,34 +3746,38 @@ static int cab_verify_header(char *indata, char *infile, uint32_t filesize, FILE
/* Compute a message digest value of the signed or unsigned CAB file */ /* Compute a message digest value of the signed or unsigned CAB file */
static int cab_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER *header) static int cab_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER *header)
{ {
BIO *bio; size_t left, written;
u_char *bfb; uint32_t i, n, offset, coffFiles;
EVP_MD_CTX *mdctx;
uint32_t offset, coffFiles;
int ret = 0; int ret = 0;
const EVP_MD *md = EVP_get_digestbynid(mdtype); const EVP_MD *md = EVP_get_digestbynid(mdtype);
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
BIO *bio = BIO_new(BIO_s_mem());
u_char *bfb = OPENSSL_malloc(SIZE_64K);
if (header->sigpos) if (header->sigpos)
offset = header->sigpos; offset = header->sigpos;
else else
offset = header->fileend; offset = header->fileend;
mdctx = EVP_MD_CTX_new();
if (!EVP_DigestInit(mdctx, md)) { if (!EVP_DigestInit(mdctx, md)) {
printf("Unable to set up the digest context\n"); printf("Unable to set up the digest context\n");
goto err; goto err;
} }
bio = BIO_new_mem_buf(indata, (int)offset);
memset(mdbuf, 0, EVP_MAX_MD_SIZE); memset(mdbuf, 0, EVP_MAX_MD_SIZE);
left = offset;
if (left > SIZE_64K)
left = SIZE_64K;
if (!BIO_write_ex(bio, indata, left, &written))
goto err;
(void)BIO_seek(bio, 0); (void)BIO_seek(bio, 0);
i = (uint32_t)written;
bfb = OPENSSL_malloc(SIZE_16M);
/* u1 signature[4] 4643534D MSCF: 0-3 */ /* u1 signature[4] 4643534D MSCF: 0-3 */
BIO_read(bio, bfb, 4); BIO_read(bio, bfb, 4);
EVP_DigestUpdate(mdctx, bfb, 4); EVP_DigestUpdate(mdctx, bfb, 4);
/* u4 reserved1 00000000: 4-7 */ /* u4 reserved1 00000000: 4-7 */
BIO_read(bio, bfb, 4); BIO_read(bio, bfb, 4);
n = 8;
if (header->sigpos) { if (header->sigpos) {
uint16_t nfolders, flags; uint16_t nfolders, flags;
uint32_t pos = 60; uint32_t pos = 60;
@ -3810,6 +3824,7 @@ static int cab_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER
BIO_read(bio, bfb, 22); BIO_read(bio, bfb, 22);
/* u22 abReserve: 56-59 */ /* u22 abReserve: 56-59 */
BIO_read(bio, bfb, 4); BIO_read(bio, bfb, 4);
n += 52;
EVP_DigestUpdate(mdctx, bfb, 4); EVP_DigestUpdate(mdctx, bfb, 4);
/* TODO */ /* TODO */
if (flags & FLAG_PREV_CABINET) { if (flags & FLAG_PREV_CABINET) {
@ -3818,12 +3833,14 @@ static int cab_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER
BIO_read(bio, bfb, 1); BIO_read(bio, bfb, 1);
EVP_DigestUpdate(mdctx, bfb, 1); EVP_DigestUpdate(mdctx, bfb, 1);
pos++; pos++;
n++;
} while (bfb[0] && pos < offset); } while (bfb[0] && pos < offset);
/* szDiskPrev */ /* szDiskPrev */
do { do {
BIO_read(bio, bfb, 1); BIO_read(bio, bfb, 1);
EVP_DigestUpdate(mdctx, bfb, 1); EVP_DigestUpdate(mdctx, bfb, 1);
pos++; pos++;
n++;
} while (bfb[0] && pos < offset); } while (bfb[0] && pos < offset);
} }
if (flags & FLAG_NEXT_CABINET) { if (flags & FLAG_NEXT_CABINET) {
@ -3832,12 +3849,14 @@ static int cab_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER
BIO_read(bio, bfb, 1); BIO_read(bio, bfb, 1);
EVP_DigestUpdate(mdctx, bfb, 1); EVP_DigestUpdate(mdctx, bfb, 1);
pos++; pos++;
n++;
} while (bfb[0] && pos < offset); } while (bfb[0] && pos < offset);
/* szDiskNext */ /* szDiskNext */
do { do {
BIO_read(bio, bfb, 1); BIO_read(bio, bfb, 1);
EVP_DigestUpdate(mdctx, bfb, 1); EVP_DigestUpdate(mdctx, bfb, 1);
pos++; pos++;
n++;
} while (bfb[0] && pos < offset); } while (bfb[0] && pos < offset);
} }
/* /*
@ -3848,28 +3867,38 @@ static int cab_calc_digest(char *indata, int mdtype, u_char *mdbuf, FILE_HEADER
BIO_read(bio, bfb, 8); BIO_read(bio, bfb, 8);
EVP_DigestUpdate(mdctx, bfb, 8); EVP_DigestUpdate(mdctx, bfb, 8);
nfolders--; nfolders--;
n += 8;
} }
} else { } else {
/* read what's left of the unsigned PE file */ /* read what's left of the unsigned CAB file */
coffFiles = 8; coffFiles = 8;
} }
/* (variable) ab - the compressed data bytes */ /* (variable) ab - the compressed data bytes */
while (coffFiles < offset) { while (coffFiles < offset) {
int l; size_t nread;
uint32_t want = offset - coffFiles; uint32_t want = offset - coffFiles;
if (want > sizeof bfb) if (i <= n) {
want = sizeof bfb; left = offset - i;
l = BIO_read(bio, bfb, (int)want); if (left > SIZE_64K)
if (l <= 0) left = SIZE_64K;
break; if (!BIO_write_ex(bio, indata + i, left, &written))
EVP_DigestUpdate(mdctx, bfb, (size_t)l); goto err;
coffFiles += (uint32_t)l; (void)BIO_seek(bio, 0);
i += (uint32_t)written;
}
if (want > SIZE_64K)
want = SIZE_64K;
if (!BIO_read_ex(bio, bfb, want, &nread))
goto err; /* FAILED */
EVP_DigestUpdate(mdctx, bfb, nread);
coffFiles += (uint32_t)nread;
n += (uint32_t)nread;
} }
OPENSSL_free(bfb);
BIO_free(bio);
EVP_DigestFinal(mdctx, mdbuf, NULL); EVP_DigestFinal(mdctx, mdbuf, NULL);
ret = 1; /* OK */ ret = 1; /* OK */
err: err:
OPENSSL_free(bfb);
BIO_free(bio);
EVP_MD_CTX_free(mdctx); EVP_MD_CTX_free(mdctx);
return ret; return ret;
} }
@ -3962,6 +3991,7 @@ static int cab_extract_file(char *indata, FILE_HEADER *header, BIO *outdata, int
{ {
int ret = 0; int ret = 0;
PKCS7 *sig; PKCS7 *sig;
size_t written;
(void)BIO_reset(outdata); (void)BIO_reset(outdata);
if (output_pkcs7) { if (output_pkcs7) {
@ -3973,16 +4003,16 @@ static int cab_extract_file(char *indata, FILE_HEADER *header, BIO *outdata, int
ret = !PEM_write_bio_PKCS7(outdata, sig); ret = !PEM_write_bio_PKCS7(outdata, sig);
PKCS7_free(sig); PKCS7_free(sig);
} else } else
ret = !BIO_write(outdata, indata + header->sigpos, (int)header->siglen); if (!BIO_write_ex(outdata, indata + header->sigpos, header->siglen, &written) \
|| written != header->siglen)
ret = 1; /* FAILED */
return ret; return ret;
} }
static void cab_optional_names(uint16_t flags, char *indata, BIO *outdata, int *len) static void cab_optional_names(uint16_t flags, char *indata, BIO *outdata, size_t *len)
{ {
int i; size_t i = *len;
i = *len;
/* TODO */ /* TODO */
if (flags & FLAG_PREV_CABINET) { if (flags & FLAG_PREV_CABINET) {
/* szCabinetPrev */ /* szCabinetPrev */
@ -4021,7 +4051,7 @@ static void cab_optional_names(uint16_t flags, char *indata, BIO *outdata, int *
static int cab_remove_file(char *indata, FILE_HEADER *header, uint32_t filesize, BIO *outdata) static int cab_remove_file(char *indata, FILE_HEADER *header, uint32_t filesize, BIO *outdata)
{ {
int i; size_t i, written, len;
uint32_t tmp; uint32_t tmp;
uint16_t nfolders, flags; uint16_t nfolders, flags;
char *buf = OPENSSL_malloc(SIZE_64K); char *buf = OPENSSL_malloc(SIZE_64K);
@ -4074,16 +4104,21 @@ static int cab_remove_file(char *indata, FILE_HEADER *header, uint32_t filesize,
i+=8; i+=8;
nfolders--; nfolders--;
} }
/* Write what's left - the compressed data bytes */
BIO_write(outdata, indata + i, (int)(filesize - header->siglen) - i);
OPENSSL_free(buf); OPENSSL_free(buf);
/* Write what's left - the compressed data bytes */
len = filesize - header->siglen - i;
while (len > 0) {
if (!BIO_write_ex(outdata, indata + i, len, &written))
return 1; /* FAILED */
len -= written;
i += written;
}
return 0; /* OK */ return 0; /* OK */
} }
static void cab_modify_header(char *indata, FILE_HEADER *header, BIO *hash, BIO *outdata) static int cab_modify_header(char *indata, FILE_HEADER *header, BIO *hash, BIO *outdata)
{ {
int i; size_t i, written, len;
uint16_t nfolders, flags; uint16_t nfolders, flags;
u_char buf[] = {0x00, 0x00}; u_char buf[] = {0x00, 0x00};
@ -4134,12 +4169,19 @@ static void cab_modify_header(char *indata, FILE_HEADER *header, BIO *hash, BIO
nfolders--; nfolders--;
} }
/* Write what's left - the compressed data bytes */ /* Write what's left - the compressed data bytes */
BIO_write(hash, indata + i, (int)header->sigpos - i); len = header->sigpos - i;
while (len > 0) {
if (!BIO_write_ex(hash, indata + i, len, &written))
return 0; /* FAILED */
len -= written;
i += written;
}
return 1; /* OK */
} }
static void cab_add_header(char *indata, FILE_HEADER *header, BIO *hash, BIO *outdata) static int cab_add_header(char *indata, FILE_HEADER *header, BIO *hash, BIO *outdata)
{ {
int i; size_t i, written, len;
uint32_t tmp; uint32_t tmp;
uint16_t nfolders, flags; uint16_t nfolders, flags;
u_char cabsigned[] = { u_char cabsigned[] = {
@ -4200,9 +4242,16 @@ static void cab_add_header(char *indata, FILE_HEADER *header, BIO *hash, BIO *ou
i += 8; i += 8;
nfolders--; nfolders--;
} }
/* Write what's left - the compressed data bytes */
BIO_write(hash, indata + i, (int)header->fileend - i);
OPENSSL_free(buf); OPENSSL_free(buf);
/* Write what's left - the compressed data bytes */
len = header->fileend - i;
while (len > 0) {
if (!BIO_write_ex(hash, indata + i, len, &written))
return 0; /* FAILED */
len -= written;
i += written;
}
return 1; /* OK */
} }
/* /*
@ -5600,11 +5649,14 @@ static PKCS7 *cab_presign_file(file_type_t type, cmd_type_t cmd, FILE_HEADER *he
if (cmd == CMD_ADD) if (cmd == CMD_ADD)
sig = *cursig; sig = *cursig;
} }
if (header->header_size == 20) if (header->header_size == 20) {
/* Strip current signature and modify header */ /* Strip current signature and modify header */
cab_modify_header(indata, header, hash, outdata); if (!cab_modify_header(indata, header, hash, outdata))
else return NULL; /* FAILED */
cab_add_header(indata, header, hash, outdata); } else {
if (!cab_add_header(indata, header, hash, outdata))
return NULL; /* FAILED */
}
/* Obtain an existing signature or create a new one */ /* Obtain an existing signature or create a new one */
if ((cmd == CMD_ATTACH) || (cmd == CMD_SIGN)) if ((cmd == CMD_ATTACH) || (cmd == CMD_SIGN))
sig = get_pkcs7(cmd, hash, type, indata, options, header, cparams, NULL); sig = get_pkcs7(cmd, hash, type, indata, options, header, cparams, NULL);