зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1806394 r=nalexander
Differential Revision: https://phabricator.services.mozilla.com/D168294
This commit is contained in:
Родитель
7d98300d55
Коммит
7182ee6a89
|
@ -55,7 +55,8 @@ typedef struct SeenIndex_ {
|
|||
* Mozilla ARchive (MAR) file data structure
|
||||
*/
|
||||
struct MarFile_ {
|
||||
FILE* fp; /* file pointer to the archive */
|
||||
unsigned char* buffer; /* file buffer containing the entire MAR */
|
||||
size_t data_len; /* byte count of the data in the buffer */
|
||||
MarItem* item_table[TABLESIZE]; /* hash table of files in the archive */
|
||||
SeenIndex* index_list; /* file indexes processed */
|
||||
int item_table_is_valid; /* header and index validation flag */
|
||||
|
@ -72,16 +73,29 @@ typedef struct MarFile_ MarFile;
|
|||
*/
|
||||
typedef int (*MarItemCallback)(MarFile* mar, const MarItem* item, void* data);
|
||||
|
||||
enum MarReadResult_ {
|
||||
MAR_READ_SUCCESS,
|
||||
MAR_IO_ERROR,
|
||||
MAR_MEM_ERROR,
|
||||
MAR_FILE_TOO_BIG_ERROR,
|
||||
};
|
||||
|
||||
typedef enum MarReadResult_ MarReadResult;
|
||||
|
||||
/**
|
||||
* Open a MAR file for reading.
|
||||
* @param path Specifies the path to the MAR file to open. This path must
|
||||
* be compatible with fopen.
|
||||
* @param out_mar Out-parameter through which the created MarFile structure is
|
||||
* returned. Guaranteed to be a valid structure if
|
||||
* MAR_READ_SUCCESS is returned. Otherwise NULL will be
|
||||
* assigned.
|
||||
* @return NULL if an error occurs.
|
||||
*/
|
||||
MarFile* mar_open(const char* path);
|
||||
MarReadResult mar_open(const char* path, MarFile** out_mar);
|
||||
|
||||
#ifdef XP_WIN
|
||||
MarFile* mar_wopen(const wchar_t* path);
|
||||
MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -90,6 +104,49 @@ MarFile* mar_wopen(const wchar_t* path);
|
|||
*/
|
||||
void mar_close(MarFile* mar);
|
||||
|
||||
/**
|
||||
* Reads the specified amount of data from the buffer in MarFile that contains
|
||||
* the entirety of the MAR file data.
|
||||
* @param mar The MAR file to read from.
|
||||
* @param dest The buffer to read into.
|
||||
* @param position The byte index to start reading from the MAR at.
|
||||
* On success, position will be incremented by size.
|
||||
* @param size The number of bytes to read.
|
||||
* @return 0 If the specified amount of data was read.
|
||||
* -1 If the buffer MAR is not large enough to read the
|
||||
* specified amount of data at the specified position.
|
||||
*/
|
||||
int mar_read_buffer(MarFile* mar, void* dest, size_t* position, size_t size);
|
||||
|
||||
/**
|
||||
* Reads the specified amount of data from the buffer in MarFile that contains
|
||||
* the entirety of the MAR file data. If there isn't that much data remaining,
|
||||
* reads as much as possible.
|
||||
* @param mar The MAR file to read from.
|
||||
* @param dest The buffer to read into.
|
||||
* @param position The byte index to start reading from the MAR at.
|
||||
* This function will increment position by the number of bytes
|
||||
* copied.
|
||||
* @param size The maximum number of bytes to read.
|
||||
* @return The number of bytes copied into dest.
|
||||
*/
|
||||
int mar_read_buffer_max(MarFile* mar, void* dest, size_t* position,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Increments position by distance. Checks that the resulting position is still
|
||||
* within the bounds of the buffer. Much like fseek, this will allow position to
|
||||
* be successfully placed just after the end of the buffer.
|
||||
* @param mar The MAR file to read from.
|
||||
* @param position The byte index to start reading from the MAR at.
|
||||
* On success, position will be incremented by size.
|
||||
* @param distance The number of bytes to move forward by.
|
||||
* @return 0 If position was successfully moved.
|
||||
* -1 If moving position by distance would move it outside the
|
||||
* bounds of the buffer.
|
||||
*/
|
||||
int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance);
|
||||
|
||||
/**
|
||||
* Find an item in the MAR file by name.
|
||||
* @param mar The MarFile object to query.
|
||||
|
|
|
@ -75,8 +75,8 @@ int mar_extract(const char* path) {
|
|||
MarFile* mar;
|
||||
int rv;
|
||||
|
||||
mar = mar_open(path);
|
||||
if (!mar) {
|
||||
MarReadResult result = mar_open(path, &mar);
|
||||
if (result != MAR_READ_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,25 +112,28 @@ static int mar_consume_index(MarFile* mar, char** buf, const char* buf_end) {
|
|||
static int mar_read_index(MarFile* mar) {
|
||||
char id[MAR_ID_SIZE], *buf, *bufptr, *bufend;
|
||||
uint32_t offset_to_index, size_of_index;
|
||||
size_t mar_position = 0;
|
||||
|
||||
/* verify MAR ID */
|
||||
fseek(mar->fp, 0, SEEK_SET);
|
||||
if (fread(id, MAR_ID_SIZE, 1, mar->fp) != 1) {
|
||||
if (mar_read_buffer(mar, id, &mar_position, MAR_ID_SIZE) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fread(&offset_to_index, sizeof(uint32_t), 1, mar->fp) != 1) {
|
||||
if (mar_read_buffer(mar, &offset_to_index, &mar_position, sizeof(uint32_t)) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
offset_to_index = ntohl(offset_to_index);
|
||||
|
||||
if (fseek(mar->fp, offset_to_index, SEEK_SET)) {
|
||||
mar_position = 0;
|
||||
if (mar_buffer_seek(mar, &mar_position, offset_to_index) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (fread(&size_of_index, sizeof(uint32_t), 1, mar->fp) != 1) {
|
||||
if (mar_read_buffer(mar, &size_of_index, &mar_position, sizeof(uint32_t)) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
size_of_index = ntohl(size_of_index);
|
||||
|
@ -139,7 +142,7 @@ static int mar_read_index(MarFile* mar) {
|
|||
if (!buf) {
|
||||
return -1;
|
||||
}
|
||||
if (fread(buf, size_of_index, 1, mar->fp) != 1) {
|
||||
if (mar_read_buffer(mar, buf, &mar_position, size_of_index) != 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
@ -210,50 +213,96 @@ static int mar_insert_offset(MarFile* mar, uint32_t offset, uint32_t length) {
|
|||
|
||||
/**
|
||||
* Internal shared code for mar_open and mar_wopen.
|
||||
* On failure, will fclose(fp).
|
||||
* Reads the entire MAR into memory. Fails if it is bigger than
|
||||
* MAX_SIZE_OF_MAR_FILE bytes.
|
||||
*/
|
||||
static MarFile* mar_fpopen(FILE* fp) {
|
||||
static MarReadResult mar_fpopen(FILE* fp, MarFile** out_mar) {
|
||||
*out_mar = NULL;
|
||||
MarFile* mar;
|
||||
|
||||
mar = (MarFile*)malloc(sizeof(*mar));
|
||||
if (!mar) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
return MAR_MEM_ERROR;
|
||||
}
|
||||
|
||||
off_t buffer_size = -1;
|
||||
if (fseeko(fp, 0, SEEK_END) == 0) {
|
||||
buffer_size = ftello(fp);
|
||||
}
|
||||
rewind(fp);
|
||||
if (buffer_size < 0) {
|
||||
fprintf(stderr, "Warning: MAR size could not be determined\n");
|
||||
buffer_size = MAX_SIZE_OF_MAR_FILE;
|
||||
}
|
||||
if (buffer_size > MAX_SIZE_OF_MAR_FILE) {
|
||||
fprintf(stderr, "ERROR: MAR exceeds maximum size (%lli)\n",
|
||||
(long long int)buffer_size);
|
||||
free(mar);
|
||||
return MAR_FILE_TOO_BIG_ERROR;
|
||||
}
|
||||
|
||||
mar->buffer = malloc(buffer_size);
|
||||
if (!mar->buffer) {
|
||||
fprintf(stderr, "ERROR: MAR buffer could not be allocated\n");
|
||||
free(mar);
|
||||
return MAR_MEM_ERROR;
|
||||
}
|
||||
mar->data_len = fread(mar->buffer, 1, buffer_size, fp);
|
||||
if (fgetc(fp) != EOF) {
|
||||
fprintf(stderr, "ERROR: File is larger than buffer (%lli)\n",
|
||||
(long long int)buffer_size);
|
||||
free(mar->buffer);
|
||||
free(mar);
|
||||
return MAR_IO_ERROR;
|
||||
}
|
||||
if (ferror(fp)) {
|
||||
fprintf(stderr, "ERROR: Failed to read MAR\n");
|
||||
free(mar->buffer);
|
||||
free(mar);
|
||||
return MAR_IO_ERROR;
|
||||
}
|
||||
|
||||
mar->fp = fp;
|
||||
mar->item_table_is_valid = 0;
|
||||
memset(mar->item_table, 0, sizeof(mar->item_table));
|
||||
mar->index_list = NULL;
|
||||
|
||||
return mar;
|
||||
*out_mar = mar;
|
||||
return MAR_READ_SUCCESS;
|
||||
}
|
||||
|
||||
MarFile* mar_open(const char* path) {
|
||||
MarReadResult mar_open(const char* path, MarFile** out_mar) {
|
||||
*out_mar = NULL;
|
||||
|
||||
FILE* fp;
|
||||
|
||||
fp = fopen(path, "rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "ERROR: could not open file in mar_open()\n");
|
||||
perror(path);
|
||||
return NULL;
|
||||
return MAR_IO_ERROR;
|
||||
}
|
||||
|
||||
return mar_fpopen(fp);
|
||||
MarReadResult result = mar_fpopen(fp, out_mar);
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
MarFile* mar_wopen(const wchar_t* path) {
|
||||
MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar) {
|
||||
*out_mar = NULL;
|
||||
|
||||
FILE* fp;
|
||||
|
||||
_wfopen_s(&fp, path, L"rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "ERROR: could not open file in mar_wopen()\n");
|
||||
_wperror(path);
|
||||
return NULL;
|
||||
return MAR_IO_ERROR;
|
||||
}
|
||||
|
||||
return mar_fpopen(fp);
|
||||
MarReadResult result = mar_fpopen(fp, out_mar);
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -262,7 +311,7 @@ void mar_close(MarFile* mar) {
|
|||
SeenIndex* index;
|
||||
int i;
|
||||
|
||||
fclose(mar->fp);
|
||||
free(mar->buffer);
|
||||
|
||||
for (i = 0; i < TABLESIZE; ++i) {
|
||||
item = mar->item_table[i];
|
||||
|
@ -282,10 +331,61 @@ void mar_close(MarFile* mar) {
|
|||
free(mar);
|
||||
}
|
||||
|
||||
int mar_read_buffer(MarFile* mar, void* dest, size_t* position, size_t size) {
|
||||
// size may be provided by the MAR, which we may not have finished validating
|
||||
// the signature on yet. Make sure not to trust it in a way that could
|
||||
// cause an overflow.
|
||||
if (size > mar->data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (*position > mar->data_len - size) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, mar->buffer + *position, size);
|
||||
*position += size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mar_read_buffer_max(MarFile* mar, void* dest, size_t* position,
|
||||
size_t size) {
|
||||
// size may be provided by the MAR, which we may not have finished validating
|
||||
// the signature on yet. Make sure not to trust it in a way that could
|
||||
// cause an overflow.
|
||||
if (mar->data_len <= *position) {
|
||||
return 0;
|
||||
}
|
||||
size_t read_count = mar->data_len - *position;
|
||||
if (read_count > size) {
|
||||
read_count = size;
|
||||
}
|
||||
memcpy(dest, mar->buffer + *position, read_count);
|
||||
*position += read_count;
|
||||
return read_count;
|
||||
}
|
||||
|
||||
int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance) {
|
||||
// distance may be provided by the MAR, which we may not have finished
|
||||
// validating the signature on yet. Make sure not to trust it in a way that
|
||||
// could cause an overflow.
|
||||
if (distance > mar->data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (*position > mar->data_len - distance) {
|
||||
return -1;
|
||||
}
|
||||
*position += distance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the MAR file information.
|
||||
*
|
||||
* @param fp An opened MAR file in read mode.
|
||||
* @param mar An open MAR file.
|
||||
* @param mar_position The current position in the MAR.
|
||||
* Its value will be updated to the current
|
||||
* position in the MAR after the function exits.
|
||||
* Since its initial value will never actually be
|
||||
* used, this is effectively an outparam.
|
||||
* @param hasSignatureBlock Optional out parameter specifying if the MAR
|
||||
* file has a signature block or not.
|
||||
* @param numSignatures Optional out parameter for storing the number
|
||||
|
@ -300,8 +400,9 @@ void mar_close(MarFile* mar) {
|
|||
* hasAdditionalBlocks is not equal to 0.
|
||||
* @return 0 on success and non-zero on failure.
|
||||
*/
|
||||
int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock,
|
||||
uint32_t* numSignatures, int* hasAdditionalBlocks,
|
||||
int get_open_mar_file_info(MarFile* mar, size_t* mar_position,
|
||||
int* hasSignatureBlock, uint32_t* numSignatures,
|
||||
int* hasAdditionalBlocks,
|
||||
uint32_t* offsetAdditionalBlocks,
|
||||
uint32_t* numAdditionalBlocks) {
|
||||
uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i;
|
||||
|
@ -312,24 +413,27 @@ int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock,
|
|||
}
|
||||
|
||||
/* Skip to the start of the offset index */
|
||||
if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) {
|
||||
*mar_position = 0;
|
||||
if (mar_buffer_seek(mar, mar_position, MAR_ID_SIZE) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the offset to the index. */
|
||||
if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &offsetToIndex, mar_position,
|
||||
sizeof(offsetToIndex)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
offsetToIndex = ntohl(offsetToIndex);
|
||||
|
||||
if (numSignatures) {
|
||||
/* Skip past the MAR file size field */
|
||||
if (fseek(fp, sizeof(uint64_t), SEEK_CUR)) {
|
||||
if (mar_buffer_seek(mar, mar_position, sizeof(uint64_t)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the number of signatures field */
|
||||
if (fread(numSignatures, sizeof(*numSignatures), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, numSignatures, mar_position,
|
||||
sizeof(*numSignatures)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
*numSignatures = ntohl(*numSignatures);
|
||||
|
@ -337,17 +441,19 @@ int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock,
|
|||
|
||||
/* Skip to the first index entry past the index size field
|
||||
We do it in 2 calls because offsetToIndex + sizeof(uint32_t)
|
||||
could oerflow in theory. */
|
||||
if (fseek(fp, offsetToIndex, SEEK_SET)) {
|
||||
could overflow in theory. */
|
||||
*mar_position = 0;
|
||||
if (mar_buffer_seek(mar, mar_position, offsetToIndex) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) {
|
||||
if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the first offset to content field. */
|
||||
if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &offsetToContent, mar_position,
|
||||
sizeof(offsetToContent)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
offsetToContent = ntohl(offsetToContent);
|
||||
|
@ -368,12 +474,14 @@ int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock,
|
|||
}
|
||||
|
||||
/* Skip to the start of the signature block */
|
||||
if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
|
||||
*mar_position = 0;
|
||||
if (mar_buffer_seek(mar, mar_position, SIGNATURE_BLOCK_OFFSET) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the number of signatures */
|
||||
if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &signatureCount, mar_position,
|
||||
sizeof(signatureCount)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
signatureCount = ntohl(signatureCount);
|
||||
|
@ -387,38 +495,50 @@ int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock,
|
|||
/* Skip past the whole signature block */
|
||||
for (i = 0; i < signatureCount; i++) {
|
||||
/* Skip past the signature algorithm ID */
|
||||
if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) {
|
||||
if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the signature length and skip past the signature */
|
||||
if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &signatureLen, mar_position, sizeof(uint32_t)) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
signatureLen = ntohl(signatureLen);
|
||||
if (fseek(fp, signatureLen, SEEK_CUR)) {
|
||||
if (mar_buffer_seek(mar, mar_position, signatureLen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((int64_t)ftell(fp) == (int64_t)offsetToContent) {
|
||||
if (*mar_position <= (size_t)INT64_MAX &&
|
||||
(int64_t)mar_position == (int64_t)offsetToContent) {
|
||||
*hasAdditionalBlocks = 0;
|
||||
} else {
|
||||
if (numAdditionalBlocks) {
|
||||
/* We have an additional block, so read in the number of additional blocks
|
||||
and set the offset. */
|
||||
*hasAdditionalBlocks = 1;
|
||||
if (fread(numAdditionalBlocks, sizeof(uint32_t), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, numAdditionalBlocks, mar_position,
|
||||
sizeof(uint32_t)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
*numAdditionalBlocks = ntohl(*numAdditionalBlocks);
|
||||
if (offsetAdditionalBlocks) {
|
||||
*offsetAdditionalBlocks = ftell(fp);
|
||||
if (*mar_position > (size_t)UINT32_MAX) {
|
||||
return -1;
|
||||
}
|
||||
*offsetAdditionalBlocks = (uint32_t)*mar_position;
|
||||
}
|
||||
} else if (offsetAdditionalBlocks) {
|
||||
/* numAdditionalBlocks is not specified but offsetAdditionalBlocks
|
||||
is, so fill it! */
|
||||
*offsetAdditionalBlocks = ftell(fp) + sizeof(uint32_t);
|
||||
if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (*mar_position > (size_t)UINT32_MAX) {
|
||||
return -1;
|
||||
}
|
||||
*offsetAdditionalBlocks = (uint32_t)*mar_position;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,16 +556,15 @@ int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock,
|
|||
int read_product_info_block(char* path,
|
||||
struct ProductInformationBlock* infoBlock) {
|
||||
int rv;
|
||||
MarFile mar;
|
||||
mar.fp = fopen(path, "rb");
|
||||
if (!mar.fp) {
|
||||
MarFile* mar;
|
||||
MarReadResult result = mar_open(path, &mar);
|
||||
if (result != MAR_READ_SUCCESS) {
|
||||
fprintf(stderr,
|
||||
"ERROR: could not open file in read_product_info_block()\n");
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
rv = mar_read_product_info_block(&mar, infoBlock);
|
||||
fclose(mar.fp);
|
||||
rv = mar_read_product_info_block(mar, infoBlock);
|
||||
mar_close(mar);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -462,12 +581,13 @@ int mar_read_product_info_block(MarFile* mar,
|
|||
uint32_t offsetAdditionalBlocks, numAdditionalBlocks, additionalBlockSize,
|
||||
additionalBlockID;
|
||||
int hasAdditionalBlocks;
|
||||
size_t mar_position = 0;
|
||||
|
||||
/* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and
|
||||
product version < 32 bytes + 3 NULL terminator bytes. */
|
||||
char buf[MAXADDITIONALBLOCKSIZE + 1] = {'\0'};
|
||||
if (get_mar_file_info_fp(mar->fp, NULL, NULL, &hasAdditionalBlocks,
|
||||
&offsetAdditionalBlocks,
|
||||
if (get_open_mar_file_info(mar, &mar_position, NULL, NULL,
|
||||
&hasAdditionalBlocks, &offsetAdditionalBlocks,
|
||||
&numAdditionalBlocks) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -476,8 +596,8 @@ int mar_read_product_info_block(MarFile* mar,
|
|||
in a MAR file so check if any exist and process the first found */
|
||||
if (numAdditionalBlocks > 0) {
|
||||
/* Read the additional block size */
|
||||
if (fread(&additionalBlockSize, sizeof(additionalBlockSize), 1, mar->fp) !=
|
||||
1) {
|
||||
if (mar_read_buffer(mar, &additionalBlockSize, &mar_position,
|
||||
sizeof(additionalBlockSize)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
additionalBlockSize = ntohl(additionalBlockSize) -
|
||||
|
@ -490,7 +610,8 @@ int mar_read_product_info_block(MarFile* mar,
|
|||
}
|
||||
|
||||
/* Read the additional block ID */
|
||||
if (fread(&additionalBlockID, sizeof(additionalBlockID), 1, mar->fp) != 1) {
|
||||
if (mar_read_buffer(mar, &additionalBlockID, &mar_position,
|
||||
sizeof(additionalBlockID)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
additionalBlockID = ntohl(additionalBlockID);
|
||||
|
@ -499,7 +620,7 @@ int mar_read_product_info_block(MarFile* mar,
|
|||
const char* location;
|
||||
int len;
|
||||
|
||||
if (fread(buf, additionalBlockSize, 1, mar->fp) != 1) {
|
||||
if (mar_read_buffer(mar, buf, &mar_position, additionalBlockSize) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -528,7 +649,7 @@ int mar_read_product_info_block(MarFile* mar,
|
|||
return 0;
|
||||
} else {
|
||||
/* This is not the additional block you're looking for. Move along. */
|
||||
if (fseek(mar->fp, additionalBlockSize, SEEK_CUR)) {
|
||||
if (mar_buffer_seek(mar, &mar_position, additionalBlockSize) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -601,6 +722,7 @@ int mar_enum_items(MarFile* mar, MarItemCallback callback, void* closure) {
|
|||
int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf,
|
||||
int bufsize) {
|
||||
int nr;
|
||||
size_t mar_position = 0;
|
||||
|
||||
if (offset == (int)item->length) {
|
||||
return 0;
|
||||
|
@ -614,11 +736,15 @@ int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf,
|
|||
nr = bufsize;
|
||||
}
|
||||
|
||||
if (fseek(mar->fp, item->offset + offset, SEEK_SET)) {
|
||||
// Avoid adding item->offset and offset directly, just in case of overflow.
|
||||
if (mar_buffer_seek(mar, &mar_position, item->offset)) {
|
||||
return -1;
|
||||
}
|
||||
if (mar_buffer_seek(mar, &mar_position, offset)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fread(buf, 1, nr, mar->fp);
|
||||
return mar_read_buffer_max(mar, buf, &mar_position, nr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,17 +770,18 @@ int get_mar_file_info(const char* path, int* hasSignatureBlock,
|
|||
uint32_t* offsetAdditionalBlocks,
|
||||
uint32_t* numAdditionalBlocks) {
|
||||
int rv;
|
||||
FILE* fp = fopen(path, "rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "ERROR: could not open file in get_mar_file_info()\n");
|
||||
perror(path);
|
||||
MarFile* mar;
|
||||
size_t mar_position = 0;
|
||||
MarReadResult result = mar_open(path, &mar);
|
||||
if (result != MAR_READ_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: could not read file in get_mar_file_info()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = get_mar_file_info_fp(fp, hasSignatureBlock, numSignatures,
|
||||
hasAdditionalBlocks, offsetAdditionalBlocks,
|
||||
numAdditionalBlocks);
|
||||
rv = get_open_mar_file_info(mar, &mar_position, hasSignatureBlock,
|
||||
numSignatures, hasAdditionalBlocks,
|
||||
offsetAdditionalBlocks, numAdditionalBlocks);
|
||||
|
||||
fclose(fp);
|
||||
mar_close(mar);
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -111,8 +111,8 @@ static int mar_test_callback(MarFile* mar, const MarItem* item, void* unused) {
|
|||
static int mar_test(const char* path) {
|
||||
MarFile* mar;
|
||||
|
||||
mar = mar_open(path);
|
||||
if (!mar) {
|
||||
MarReadResult result = mar_open(path, &mar);
|
||||
if (result != MAR_READ_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -393,8 +393,9 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
if (!rv) {
|
||||
MarFile* mar = mar_open(argv[2]);
|
||||
if (mar) {
|
||||
MarFile* mar;
|
||||
MarReadResult result = mar_open(argv[2], &mar);
|
||||
if (result == MAR_READ_SUCCESS) {
|
||||
rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount);
|
||||
mar_close(mar);
|
||||
} else {
|
||||
|
|
|
@ -56,35 +56,38 @@ int mar_read_entire_file(const char* filePath, uint32_t maxSize,
|
|||
return result;
|
||||
}
|
||||
|
||||
int mar_extract_and_verify_signatures_fp(FILE* fp,
|
||||
int mar_extract_and_verify_signatures(MarFile* mar,
|
||||
CryptoX_ProviderHandle provider,
|
||||
CryptoX_PublicKey* keys,
|
||||
uint32_t keyCount);
|
||||
int mar_verify_signatures_for_fp(FILE* fp, CryptoX_ProviderHandle provider,
|
||||
int mar_verify_extracted_signatures(MarFile* mar,
|
||||
CryptoX_ProviderHandle provider,
|
||||
CryptoX_PublicKey* keys,
|
||||
const uint8_t* const* extractedSignatures,
|
||||
uint32_t keyCount, uint32_t* numVerified);
|
||||
|
||||
/**
|
||||
* Reads the specified number of bytes from the file pointer and
|
||||
* Reads the specified number of bytes from the MAR buffer and
|
||||
* stores them in the passed buffer.
|
||||
*
|
||||
* @param fp The file pointer to read from.
|
||||
* @param mar An opened MAR
|
||||
* @param mar_position
|
||||
* Our current position within the MAR file buffer.
|
||||
* @param buffer The buffer to store the read results.
|
||||
* @param size The number of bytes to read, buffer must be
|
||||
* at least of this size.
|
||||
* @param ctxs Pointer to the first element in an array of verify context.
|
||||
* @param count The number of elements in ctxs
|
||||
* @param err The name of what is being written to in case of error.
|
||||
* @return 0 on success
|
||||
* -1 on read error
|
||||
* -2 on verify update error
|
||||
* @return CryptoX_Success on success
|
||||
* CryptoX_Error on error
|
||||
*/
|
||||
int ReadAndUpdateVerifyContext(FILE* fp, void* buffer, uint32_t size,
|
||||
CryptoX_SignatureHandle* ctxs, uint32_t count,
|
||||
const char* err) {
|
||||
CryptoX_Result ReadAndUpdateVerifyContext(MarFile* mar, size_t* mar_position,
|
||||
void* buffer, uint32_t size,
|
||||
CryptoX_SignatureHandle* ctxs,
|
||||
uint32_t count, const char* err) {
|
||||
uint32_t k;
|
||||
if (!fp || !buffer || !ctxs || count == 0 || !err) {
|
||||
if (!mar || !mar_position || !buffer || !ctxs || count == 0 || !err) {
|
||||
fprintf(stderr, "ERROR: Invalid parameter specified.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
@ -93,7 +96,7 @@ int ReadAndUpdateVerifyContext(FILE* fp, void* buffer, uint32_t size,
|
|||
return CryptoX_Success;
|
||||
}
|
||||
|
||||
if (fread(buffer, size, 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, buffer, mar_position, size) != 0) {
|
||||
fprintf(stderr, "ERROR: Could not read %s\n", err);
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
@ -101,7 +104,7 @@ int ReadAndUpdateVerifyContext(FILE* fp, void* buffer, uint32_t size,
|
|||
for (k = 0; k < count; k++) {
|
||||
if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) {
|
||||
fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
|
||||
return -2;
|
||||
return CryptoX_Error;
|
||||
}
|
||||
}
|
||||
return CryptoX_Success;
|
||||
|
@ -136,11 +139,6 @@ int mar_verify_signatures(MarFile* mar, const uint8_t* const* certData,
|
|||
goto failure;
|
||||
}
|
||||
|
||||
if (!mar->fp) {
|
||||
fprintf(stderr, "ERROR: MAR file is not open.\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
|
||||
fprintf(stderr, "ERROR: Could not init crytpo library.\n");
|
||||
goto failure;
|
||||
|
@ -154,7 +152,7 @@ int mar_verify_signatures(MarFile* mar, const uint8_t* const* certData,
|
|||
}
|
||||
}
|
||||
|
||||
rv = mar_extract_and_verify_signatures_fp(mar->fp, provider, keys, certCount);
|
||||
rv = mar_extract_and_verify_signatures(mar, provider, keys, certCount);
|
||||
|
||||
failure:
|
||||
|
||||
|
@ -169,15 +167,15 @@ failure:
|
|||
|
||||
/**
|
||||
* Extracts each signature from the specified MAR file,
|
||||
* then calls mar_verify_signatures_for_fp to verify each signature.
|
||||
* then calls mar_verify_extracted_signatures to verify each signature.
|
||||
*
|
||||
* @param fp An opened MAR file handle
|
||||
* @param mar An opened MAR
|
||||
* @param provider A library provider
|
||||
* @param keys The public keys to use to verify the MAR
|
||||
* @param keyCount The number of keys pointed to by keys
|
||||
* @return 0 on success
|
||||
*/
|
||||
int mar_extract_and_verify_signatures_fp(FILE* fp,
|
||||
int mar_extract_and_verify_signatures(MarFile* mar,
|
||||
CryptoX_ProviderHandle provider,
|
||||
CryptoX_PublicKey* keys,
|
||||
uint32_t keyCount) {
|
||||
|
@ -185,34 +183,25 @@ int mar_extract_and_verify_signatures_fp(FILE* fp,
|
|||
uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
|
||||
uint8_t* extractedSignatures[MAX_SIGNATURES];
|
||||
uint32_t i;
|
||||
size_t mar_position = 0;
|
||||
|
||||
memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs));
|
||||
memset(extractedSignatures, 0, sizeof(extractedSignatures));
|
||||
|
||||
if (!fp) {
|
||||
if (!mar) {
|
||||
fprintf(stderr, "ERROR: Invalid file pointer passed.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
/* To protect against invalid MAR files, we assumes that the MAR file
|
||||
size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
|
||||
if (fseeko(fp, 0, SEEK_END)) {
|
||||
fprintf(stderr, "ERROR: Could not seek to the end of the MAR file.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
if (ftello(fp) > MAX_SIZE_OF_MAR_FILE) {
|
||||
fprintf(stderr, "ERROR: MAR file is too large to be verified.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
/* Skip to the start of the signature block */
|
||||
if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
|
||||
if (mar_buffer_seek(mar, &mar_position, SIGNATURE_BLOCK_OFFSET) != 0) {
|
||||
fprintf(stderr, "ERROR: Could not seek to the signature block.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
/* Get the number of signatures */
|
||||
if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &signatureCount, &mar_position,
|
||||
sizeof(signatureCount)) != 0) {
|
||||
fprintf(stderr, "ERROR: Could not read number of signatures.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
@ -228,19 +217,21 @@ int mar_extract_and_verify_signatures_fp(FILE* fp,
|
|||
|
||||
for (i = 0; i < signatureCount; i++) {
|
||||
/* Get the signature algorithm ID */
|
||||
if (fread(&signatureAlgorithmIDs[i], sizeof(uint32_t), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &signatureAlgorithmIDs[i], &mar_position,
|
||||
sizeof(uint32_t)) != 0) {
|
||||
fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]);
|
||||
|
||||
if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, &signatureLen, &mar_position, sizeof(uint32_t)) !=
|
||||
0) {
|
||||
fprintf(stderr, "ERROR: Could not read signatures length.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
signatureLen = ntohl(signatureLen);
|
||||
|
||||
/* To protected against invalid input make sure the signature length
|
||||
/* To protect against invalid input make sure the signature length
|
||||
isn't too big. */
|
||||
if (signatureLen > MAX_SIGNATURE_LENGTH) {
|
||||
fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
|
||||
|
@ -249,10 +240,11 @@ int mar_extract_and_verify_signatures_fp(FILE* fp,
|
|||
|
||||
extractedSignatures[i] = malloc(signatureLen);
|
||||
if (!extractedSignatures[i]) {
|
||||
fprintf(stderr, "ERROR: Could allocate buffer for signature.\n");
|
||||
fprintf(stderr, "ERROR: Could not allocate buffer for signature.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
if (fread(extractedSignatures[i], signatureLen, 1, fp) != 1) {
|
||||
if (mar_read_buffer(mar, extractedSignatures[i], &mar_position,
|
||||
signatureLen) != 0) {
|
||||
fprintf(stderr, "ERROR: Could not read extracted signature.\n");
|
||||
for (i = 0; i < signatureCount; ++i) {
|
||||
free(extractedSignatures[i]);
|
||||
|
@ -270,11 +262,8 @@ int mar_extract_and_verify_signatures_fp(FILE* fp,
|
|||
}
|
||||
}
|
||||
|
||||
if (ftello(fp) == -1) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
if (mar_verify_signatures_for_fp(
|
||||
fp, provider, keys, (const uint8_t* const*)extractedSignatures,
|
||||
if (mar_verify_extracted_signatures(
|
||||
mar, provider, keys, (const uint8_t* const*)extractedSignatures,
|
||||
signatureCount, &numVerified) == CryptoX_Error) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
@ -304,7 +293,7 @@ int mar_extract_and_verify_signatures_fp(FILE* fp,
|
|||
* certificate given, etc. The signature count must exactly match the number of
|
||||
* certificates given, and all signature verifications must succeed.
|
||||
*
|
||||
* @param fp An opened MAR file handle
|
||||
* @param mar An opened MAR
|
||||
* @param provider A library provider
|
||||
* @param keys A pointer to the first element in an
|
||||
* array of keys.
|
||||
|
@ -315,18 +304,18 @@ int mar_extract_and_verify_signatures_fp(FILE* fp,
|
|||
* the number of verified signatures.
|
||||
* This information can be useful for printing
|
||||
* error messages.
|
||||
* @return 0 on success, *numVerified == signatureCount.
|
||||
* @return CryptoX_Success on success, *numVerified == signatureCount.
|
||||
*/
|
||||
int mar_verify_signatures_for_fp(FILE* fp, CryptoX_ProviderHandle provider,
|
||||
CryptoX_PublicKey* keys,
|
||||
const uint8_t* const* extractedSignatures,
|
||||
uint32_t signatureCount,
|
||||
CryptoX_Result mar_verify_extracted_signatures(
|
||||
MarFile* mar, CryptoX_ProviderHandle provider, CryptoX_PublicKey* keys,
|
||||
const uint8_t* const* extractedSignatures, uint32_t signatureCount,
|
||||
uint32_t* numVerified) {
|
||||
CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES];
|
||||
char buf[BLOCKSIZE];
|
||||
uint32_t signatureLengths[MAX_SIGNATURES];
|
||||
uint32_t i;
|
||||
int rv = CryptoX_Error;
|
||||
size_t mar_position = 0;
|
||||
|
||||
memset(signatureHandles, 0, sizeof(signatureHandles));
|
||||
memset(signatureLengths, 0, sizeof(signatureLengths));
|
||||
|
@ -355,19 +344,13 @@ int mar_verify_signatures_for_fp(FILE* fp, CryptoX_ProviderHandle provider,
|
|||
}
|
||||
}
|
||||
|
||||
/* Skip to the start of the file */
|
||||
if (fseeko(fp, 0, SEEK_SET)) {
|
||||
fprintf(stderr, "ERROR: Could not seek to start of the file\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Bytes 0-3: MAR1
|
||||
Bytes 4-7: index offset
|
||||
Bytes 8-15: size of entire MAR
|
||||
*/
|
||||
if (CryptoX_Failed(ReadAndUpdateVerifyContext(
|
||||
fp, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t), signatureHandles,
|
||||
signatureCount, "signature block"))) {
|
||||
mar, &mar_position, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t),
|
||||
signatureHandles, signatureCount, "signature block"))) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
|
@ -375,14 +358,14 @@ int mar_verify_signatures_for_fp(FILE* fp, CryptoX_ProviderHandle provider,
|
|||
for (i = 0; i < signatureCount; i++) {
|
||||
/* Get the signature algorithm ID */
|
||||
if (CryptoX_Failed(ReadAndUpdateVerifyContext(
|
||||
fp, &buf, sizeof(uint32_t), signatureHandles, signatureCount,
|
||||
"signature algorithm ID"))) {
|
||||
mar, &mar_position, &buf, sizeof(uint32_t), signatureHandles,
|
||||
signatureCount, "signature algorithm ID"))) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (CryptoX_Failed(ReadAndUpdateVerifyContext(
|
||||
fp, &signatureLengths[i], sizeof(uint32_t), signatureHandles,
|
||||
signatureCount, "signature length"))) {
|
||||
mar, &mar_position, &signatureLengths[i], sizeof(uint32_t),
|
||||
signatureHandles, signatureCount, "signature length"))) {
|
||||
goto failure;
|
||||
}
|
||||
signatureLengths[i] = ntohl(signatureLengths[i]);
|
||||
|
@ -392,20 +375,15 @@ int mar_verify_signatures_for_fp(FILE* fp, CryptoX_ProviderHandle provider,
|
|||
}
|
||||
|
||||
/* Skip past the signature itself as those are not included */
|
||||
if (fseeko(fp, signatureLengths[i], SEEK_CUR)) {
|
||||
if (mar_buffer_seek(mar, &mar_position, signatureLengths[i]) != 0) {
|
||||
fprintf(stderr, "ERROR: Could not seek past signature.\n");
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the rest of the file after the signature block */
|
||||
while (!feof(fp)) {
|
||||
int numRead = fread(buf, 1, BLOCKSIZE, fp);
|
||||
if (ferror(fp)) {
|
||||
fprintf(stderr, "ERROR: Error reading data block.\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
while (mar_position < mar->data_len) {
|
||||
int numRead = mar_read_buffer_max(mar, buf, &mar_position, BLOCKSIZE);
|
||||
for (i = 0; i < signatureCount; i++) {
|
||||
if (CryptoX_Failed(
|
||||
CryptoX_VerifyUpdate(&signatureHandles[i], buf, numRead))) {
|
||||
|
|
|
@ -203,12 +203,15 @@ int ArchiveReader::Open(const NS_tchar* path) {
|
|||
}
|
||||
}
|
||||
|
||||
MarReadResult result =
|
||||
#ifdef XP_WIN
|
||||
mArchive = mar_wopen(path);
|
||||
mar_wopen(path, &mArchive);
|
||||
#else
|
||||
mArchive = mar_open(path);
|
||||
mar_open(path, &mArchive);
|
||||
#endif
|
||||
if (!mArchive) {
|
||||
if (result == MAR_MEM_ERROR) {
|
||||
return ARCHIVE_READER_MEM_ERROR;
|
||||
} else if (result != MAR_READ_SUCCESS) {
|
||||
return READ_ERROR;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче