diff --git a/modules/libmar/src/mar.h b/modules/libmar/src/mar.h index 74ab7657f8db..4f9ae487e7a2 100644 --- a/modules/libmar/src/mar.h +++ b/modules/libmar/src/mar.h @@ -55,8 +55,7 @@ typedef struct SeenIndex_ { * Mozilla ARchive (MAR) file data structure */ struct MarFile_ { - unsigned char* buffer; /* file buffer containing the entire MAR */ - size_t data_len; /* byte count of the data in the buffer */ + FILE* fp; /* file pointer to the archive */ 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 */ @@ -73,29 +72,16 @@ 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. */ -MarReadResult mar_open(const char* path, MarFile** out_mar); +MarFile* mar_open(const char* path); #ifdef XP_WIN -MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar); +MarFile* mar_wopen(const wchar_t* path); #endif /** @@ -104,49 +90,6 @@ MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar); */ 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. diff --git a/modules/libmar/src/mar_extract.c b/modules/libmar/src/mar_extract.c index 9b4a3fa26d23..28693e24b05a 100644 --- a/modules/libmar/src/mar_extract.c +++ b/modules/libmar/src/mar_extract.c @@ -75,8 +75,8 @@ int mar_extract(const char* path) { MarFile* mar; int rv; - MarReadResult result = mar_open(path, &mar); - if (result != MAR_READ_SUCCESS) { + mar = mar_open(path); + if (!mar) { return -1; } diff --git a/modules/libmar/src/mar_read.c b/modules/libmar/src/mar_read.c index 61b326bd5048..883760903d45 100644 --- a/modules/libmar/src/mar_read.c +++ b/modules/libmar/src/mar_read.c @@ -112,28 +112,25 @@ 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 */ - if (mar_read_buffer(mar, id, &mar_position, MAR_ID_SIZE) != 0) { + fseek(mar->fp, 0, SEEK_SET); + if (fread(id, MAR_ID_SIZE, 1, mar->fp) != 1) { return -1; } if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) { return -1; } - if (mar_read_buffer(mar, &offset_to_index, &mar_position, sizeof(uint32_t)) != - 0) { + if (fread(&offset_to_index, sizeof(uint32_t), 1, mar->fp) != 1) { return -1; } offset_to_index = ntohl(offset_to_index); - mar_position = 0; - if (mar_buffer_seek(mar, &mar_position, offset_to_index) != 0) { + if (fseek(mar->fp, offset_to_index, SEEK_SET)) { return -1; } - if (mar_read_buffer(mar, &size_of_index, &mar_position, sizeof(uint32_t)) != - 0) { + if (fread(&size_of_index, sizeof(uint32_t), 1, mar->fp) != 1) { return -1; } size_of_index = ntohl(size_of_index); @@ -142,7 +139,7 @@ static int mar_read_index(MarFile* mar) { if (!buf) { return -1; } - if (mar_read_buffer(mar, buf, &mar_position, size_of_index) != 0) { + if (fread(buf, size_of_index, 1, mar->fp) != 1) { free(buf); return -1; } @@ -213,94 +210,50 @@ static int mar_insert_offset(MarFile* mar, uint32_t offset, uint32_t length) { /** * Internal shared code for mar_open and mar_wopen. - * Reads the entire MAR into memory. Fails if it is bigger than - * MAX_SIZE_OF_MAR_FILE bytes. + * On failure, will fclose(fp). */ -static MarReadResult mar_fpopen(FILE* fp, MarFile** out_mar) { - *out_mar = NULL; +static MarFile* mar_fpopen(FILE* fp) { MarFile* mar; mar = (MarFile*)malloc(sizeof(*mar)); if (!mar) { - 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 (%li)\n", 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 (%li)\n", 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; + fclose(fp); + return NULL; } + mar->fp = fp; mar->item_table_is_valid = 0; memset(mar->item_table, 0, sizeof(mar->item_table)); mar->index_list = NULL; - *out_mar = mar; - return MAR_READ_SUCCESS; + return mar; } -MarReadResult mar_open(const char* path, MarFile** out_mar) { - *out_mar = NULL; - +MarFile* mar_open(const char* path) { FILE* fp; fp = fopen(path, "rb"); if (!fp) { fprintf(stderr, "ERROR: could not open file in mar_open()\n"); perror(path); - return MAR_IO_ERROR; + return NULL; } - MarReadResult result = mar_fpopen(fp, out_mar); - fclose(fp); - return result; + return mar_fpopen(fp); } #ifdef XP_WIN -MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar) { - *out_mar = NULL; - +MarFile* mar_wopen(const wchar_t* path) { FILE* fp; _wfopen_s(&fp, path, L"rb"); if (!fp) { fprintf(stderr, "ERROR: could not open file in mar_wopen()\n"); _wperror(path); - return MAR_IO_ERROR; + return NULL; } - MarReadResult result = mar_fpopen(fp, out_mar); - fclose(fp); - return result; + return mar_fpopen(fp); } #endif @@ -309,7 +262,7 @@ void mar_close(MarFile* mar) { SeenIndex* index; int i; - free(mar->buffer); + fclose(mar->fp); for (i = 0; i < TABLESIZE; ++i) { item = mar->item_table[i]; @@ -329,61 +282,10 @@ 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 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 fp An opened MAR file in read mode. * @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 @@ -398,11 +300,10 @@ int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance) { * hasAdditionalBlocks is not equal to 0. * @return 0 on success and non-zero on failure. */ -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) { +int get_mar_file_info_fp(FILE* fp, int* hasSignatureBlock, + uint32_t* numSignatures, int* hasAdditionalBlocks, + uint32_t* offsetAdditionalBlocks, + uint32_t* numAdditionalBlocks) { uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i; /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */ @@ -411,27 +312,24 @@ int get_open_mar_file_info(MarFile* mar, size_t* mar_position, } /* Skip to the start of the offset index */ - *mar_position = 0; - if (mar_buffer_seek(mar, mar_position, MAR_ID_SIZE) != 0) { + if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) { return -1; } /* Read the offset to the index. */ - if (mar_read_buffer(mar, &offsetToIndex, mar_position, - sizeof(offsetToIndex)) != 0) { + if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1) { return -1; } offsetToIndex = ntohl(offsetToIndex); if (numSignatures) { /* Skip past the MAR file size field */ - if (mar_buffer_seek(mar, mar_position, sizeof(uint64_t)) != 0) { + if (fseek(fp, sizeof(uint64_t), SEEK_CUR)) { return -1; } /* Read the number of signatures field */ - if (mar_read_buffer(mar, numSignatures, mar_position, - sizeof(*numSignatures)) != 0) { + if (fread(numSignatures, sizeof(*numSignatures), 1, fp) != 1) { return -1; } *numSignatures = ntohl(*numSignatures); @@ -439,19 +337,17 @@ int get_open_mar_file_info(MarFile* mar, size_t* mar_position, /* Skip to the first index entry past the index size field We do it in 2 calls because offsetToIndex + sizeof(uint32_t) - could overflow in theory. */ - *mar_position = 0; - if (mar_buffer_seek(mar, mar_position, offsetToIndex) != 0) { + could oerflow in theory. */ + if (fseek(fp, offsetToIndex, SEEK_SET)) { return -1; } - if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) { + if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) { return -1; } /* Read the first offset to content field. */ - if (mar_read_buffer(mar, &offsetToContent, mar_position, - sizeof(offsetToContent)) != 0) { + if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1) { return -1; } offsetToContent = ntohl(offsetToContent); @@ -472,14 +368,12 @@ int get_open_mar_file_info(MarFile* mar, size_t* mar_position, } /* Skip to the start of the signature block */ - *mar_position = 0; - if (mar_buffer_seek(mar, mar_position, SIGNATURE_BLOCK_OFFSET) != 0) { + if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) { return -1; } /* Get the number of signatures */ - if (mar_read_buffer(mar, &signatureCount, mar_position, - sizeof(signatureCount)) != 0) { + if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) { return -1; } signatureCount = ntohl(signatureCount); @@ -493,50 +387,38 @@ int get_open_mar_file_info(MarFile* mar, size_t* mar_position, /* Skip past the whole signature block */ for (i = 0; i < signatureCount; i++) { /* Skip past the signature algorithm ID */ - if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) { + if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) { return -1; } /* Read the signature length and skip past the signature */ - if (mar_read_buffer(mar, &signatureLen, mar_position, sizeof(uint32_t)) != - 0) { + if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) { return -1; } signatureLen = ntohl(signatureLen); - if (mar_buffer_seek(mar, mar_position, signatureLen) != 0) { + if (fseek(fp, signatureLen, SEEK_CUR)) { return -1; } } - if (*mar_position <= (size_t)INT64_MAX && - (int64_t)mar_position == (int64_t)offsetToContent) { + if ((int64_t)ftell(fp) == (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 (mar_read_buffer(mar, numAdditionalBlocks, mar_position, - sizeof(uint32_t)) != 0) { + if (fread(numAdditionalBlocks, sizeof(uint32_t), 1, fp) != 1) { return -1; } *numAdditionalBlocks = ntohl(*numAdditionalBlocks); if (offsetAdditionalBlocks) { - if (*mar_position > (size_t)UINT32_MAX) { - return -1; - } - *offsetAdditionalBlocks = (uint32_t)*mar_position; + *offsetAdditionalBlocks = ftell(fp); } } else if (offsetAdditionalBlocks) { /* numAdditionalBlocks is not specified but offsetAdditionalBlocks is, so fill it! */ - 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; + *offsetAdditionalBlocks = ftell(fp) + sizeof(uint32_t); } } @@ -554,15 +436,16 @@ int get_open_mar_file_info(MarFile* mar, size_t* mar_position, int read_product_info_block(char* path, struct ProductInformationBlock* infoBlock) { int rv; - MarFile* mar; - MarReadResult result = mar_open(path, &mar); - if (result != MAR_READ_SUCCESS) { + MarFile mar; + mar.fp = fopen(path, "rb"); + if (!mar.fp) { 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); - mar_close(mar); + rv = mar_read_product_info_block(&mar, infoBlock); + fclose(mar.fp); return rv; } @@ -579,14 +462,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_open_mar_file_info(mar, &mar_position, NULL, NULL, - &hasAdditionalBlocks, &offsetAdditionalBlocks, - &numAdditionalBlocks) != 0) { + if (get_mar_file_info_fp(mar->fp, NULL, NULL, &hasAdditionalBlocks, + &offsetAdditionalBlocks, + &numAdditionalBlocks) != 0) { return -1; } @@ -594,8 +476,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 (mar_read_buffer(mar, &additionalBlockSize, &mar_position, - sizeof(additionalBlockSize)) != 0) { + if (fread(&additionalBlockSize, sizeof(additionalBlockSize), 1, mar->fp) != + 1) { return -1; } additionalBlockSize = ntohl(additionalBlockSize) - @@ -608,8 +490,7 @@ int mar_read_product_info_block(MarFile* mar, } /* Read the additional block ID */ - if (mar_read_buffer(mar, &additionalBlockID, &mar_position, - sizeof(additionalBlockID)) != 0) { + if (fread(&additionalBlockID, sizeof(additionalBlockID), 1, mar->fp) != 1) { return -1; } additionalBlockID = ntohl(additionalBlockID); @@ -618,7 +499,7 @@ int mar_read_product_info_block(MarFile* mar, const char* location; int len; - if (mar_read_buffer(mar, buf, &mar_position, additionalBlockSize) != 0) { + if (fread(buf, additionalBlockSize, 1, mar->fp) != 1) { return -1; } @@ -647,7 +528,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 (mar_buffer_seek(mar, &mar_position, additionalBlockSize) != 0) { + if (fseek(mar->fp, additionalBlockSize, SEEK_CUR)) { return -1; } } @@ -720,7 +601,6 @@ 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; @@ -734,15 +614,11 @@ int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf, nr = bufsize; } - // 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)) { + if (fseek(mar->fp, item->offset + offset, SEEK_SET)) { return -1; } - return mar_read_buffer_max(mar, buf, &mar_position, nr); + return fread(buf, 1, nr, mar->fp); } /** @@ -768,18 +644,17 @@ int get_mar_file_info(const char* path, int* hasSignatureBlock, uint32_t* offsetAdditionalBlocks, uint32_t* numAdditionalBlocks) { int rv; - 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"); + FILE* fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: could not open file in get_mar_file_info()\n"); + perror(path); return -1; } - rv = get_open_mar_file_info(mar, &mar_position, hasSignatureBlock, - numSignatures, hasAdditionalBlocks, - offsetAdditionalBlocks, numAdditionalBlocks); + rv = get_mar_file_info_fp(fp, hasSignatureBlock, numSignatures, + hasAdditionalBlocks, offsetAdditionalBlocks, + numAdditionalBlocks); - mar_close(mar); + fclose(fp); return rv; } diff --git a/modules/libmar/tool/mar.c b/modules/libmar/tool/mar.c index 449c9f7efc20..0bf2cb4bd1d4 100644 --- a/modules/libmar/tool/mar.c +++ b/modules/libmar/tool/mar.c @@ -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; - MarReadResult result = mar_open(path, &mar); - if (result != MAR_READ_SUCCESS) { + mar = mar_open(path); + if (!mar) { return -1; } @@ -393,9 +393,8 @@ int main(int argc, char** argv) { } if (!rv) { - MarFile* mar; - MarReadResult result = mar_open(argv[2], &mar); - if (result == MAR_READ_SUCCESS) { + MarFile* mar = mar_open(argv[2]); + if (mar) { rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount); mar_close(mar); } else { diff --git a/modules/libmar/verify/mar_verify.c b/modules/libmar/verify/mar_verify.c index 5272bb585bec..2ec17bbf7f61 100644 --- a/modules/libmar/verify/mar_verify.c +++ b/modules/libmar/verify/mar_verify.c @@ -56,38 +56,35 @@ int mar_read_entire_file(const char* filePath, uint32_t maxSize, return result; } -int mar_extract_and_verify_signatures(MarFile* mar, - CryptoX_ProviderHandle provider, - CryptoX_PublicKey* keys, - uint32_t keyCount); -int mar_verify_extracted_signatures(MarFile* mar, - CryptoX_ProviderHandle provider, - CryptoX_PublicKey* keys, - const uint8_t* const* extractedSignatures, - uint32_t keyCount, uint32_t* numVerified); +int mar_extract_and_verify_signatures_fp(FILE* fp, + CryptoX_ProviderHandle provider, + CryptoX_PublicKey* keys, + uint32_t keyCount); +int mar_verify_signatures_for_fp(FILE* fp, 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 MAR buffer and + * Reads the specified number of bytes from the file pointer and * stores them in the passed buffer. * - * @param mar An opened MAR - * @param mar_position - * Our current position within the MAR file buffer. + * @param fp The file pointer to read from. * @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 CryptoX_Success on success - * CryptoX_Error on error + * @return 0 on success + * -1 on read error + * -2 on verify update error */ -CryptoX_Result ReadAndUpdateVerifyContext(MarFile* mar, size_t* mar_position, - void* buffer, uint32_t size, - CryptoX_SignatureHandle* ctxs, - uint32_t count, const char* err) { +int ReadAndUpdateVerifyContext(FILE* fp, void* buffer, uint32_t size, + CryptoX_SignatureHandle* ctxs, uint32_t count, + const char* err) { uint32_t k; - if (!mar || !mar_position || !buffer || !ctxs || count == 0 || !err) { + if (!fp || !buffer || !ctxs || count == 0 || !err) { fprintf(stderr, "ERROR: Invalid parameter specified.\n"); return CryptoX_Error; } @@ -96,7 +93,7 @@ CryptoX_Result ReadAndUpdateVerifyContext(MarFile* mar, size_t* mar_position, return CryptoX_Success; } - if (mar_read_buffer(mar, buffer, mar_position, size) != 0) { + if (fread(buffer, size, 1, fp) != 1) { fprintf(stderr, "ERROR: Could not read %s\n", err); return CryptoX_Error; } @@ -104,7 +101,7 @@ CryptoX_Result ReadAndUpdateVerifyContext(MarFile* mar, size_t* mar_position, 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 CryptoX_Error; + return -2; } } return CryptoX_Success; @@ -139,6 +136,11 @@ 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; @@ -152,7 +154,7 @@ int mar_verify_signatures(MarFile* mar, const uint8_t* const* certData, } } - rv = mar_extract_and_verify_signatures(mar, provider, keys, certCount); + rv = mar_extract_and_verify_signatures_fp(mar->fp, provider, keys, certCount); failure: @@ -167,41 +169,50 @@ failure: /** * Extracts each signature from the specified MAR file, - * then calls mar_verify_extracted_signatures to verify each signature. + * then calls mar_verify_signatures_for_fp to verify each signature. * - * @param mar An opened MAR + * @param fp An opened MAR file handle * @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(MarFile* mar, - CryptoX_ProviderHandle provider, - CryptoX_PublicKey* keys, - uint32_t keyCount) { +int mar_extract_and_verify_signatures_fp(FILE* fp, + CryptoX_ProviderHandle provider, + CryptoX_PublicKey* keys, + uint32_t keyCount) { uint32_t signatureCount, signatureLen, numVerified = 0; 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 (!mar) { + if (!fp) { 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 (mar_buffer_seek(mar, &mar_position, SIGNATURE_BLOCK_OFFSET) != 0) { + if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) { fprintf(stderr, "ERROR: Could not seek to the signature block.\n"); return CryptoX_Error; } /* Get the number of signatures */ - if (mar_read_buffer(mar, &signatureCount, &mar_position, - sizeof(signatureCount)) != 0) { + if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) { fprintf(stderr, "ERROR: Could not read number of signatures.\n"); return CryptoX_Error; } @@ -217,21 +228,19 @@ int mar_extract_and_verify_signatures(MarFile* mar, for (i = 0; i < signatureCount; i++) { /* Get the signature algorithm ID */ - if (mar_read_buffer(mar, &signatureAlgorithmIDs[i], &mar_position, - sizeof(uint32_t)) != 0) { + if (fread(&signatureAlgorithmIDs[i], sizeof(uint32_t), 1, fp) != 1) { fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n"); return CryptoX_Error; } signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]); - if (mar_read_buffer(mar, &signatureLen, &mar_position, sizeof(uint32_t)) != - 0) { + if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) { fprintf(stderr, "ERROR: Could not read signatures length.\n"); return CryptoX_Error; } signatureLen = ntohl(signatureLen); - /* To protect against invalid input make sure the signature length + /* To protected 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"); @@ -240,11 +249,10 @@ int mar_extract_and_verify_signatures(MarFile* mar, extractedSignatures[i] = malloc(signatureLen); if (!extractedSignatures[i]) { - fprintf(stderr, "ERROR: Could not allocate buffer for signature.\n"); + fprintf(stderr, "ERROR: Could allocate buffer for signature.\n"); return CryptoX_Error; } - if (mar_read_buffer(mar, extractedSignatures[i], &mar_position, - signatureLen) != 0) { + if (fread(extractedSignatures[i], signatureLen, 1, fp) != 1) { fprintf(stderr, "ERROR: Could not read extracted signature.\n"); for (i = 0; i < signatureCount; ++i) { free(extractedSignatures[i]); @@ -262,8 +270,11 @@ int mar_extract_and_verify_signatures(MarFile* mar, } } - if (mar_verify_extracted_signatures( - mar, provider, keys, (const uint8_t* const*)extractedSignatures, + if (ftello(fp) == -1) { + return CryptoX_Error; + } + if (mar_verify_signatures_for_fp( + fp, provider, keys, (const uint8_t* const*)extractedSignatures, signatureCount, &numVerified) == CryptoX_Error) { return CryptoX_Error; } @@ -293,7 +304,7 @@ int mar_extract_and_verify_signatures(MarFile* mar, * certificate given, etc. The signature count must exactly match the number of * certificates given, and all signature verifications must succeed. * - * @param mar An opened MAR + * @param fp An opened MAR file handle * @param provider A library provider * @param keys A pointer to the first element in an * array of keys. @@ -304,18 +315,18 @@ int mar_extract_and_verify_signatures(MarFile* mar, * the number of verified signatures. * This information can be useful for printing * error messages. - * @return CryptoX_Success on success, *numVerified == signatureCount. + * @return 0 on success, *numVerified == 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) { +int mar_verify_signatures_for_fp(FILE* fp, 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)); @@ -344,13 +355,19 @@ CryptoX_Result mar_verify_extracted_signatures( } } + /* 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( - mar, &mar_position, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t), - signatureHandles, signatureCount, "signature block"))) { + fp, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t), signatureHandles, + signatureCount, "signature block"))) { goto failure; } @@ -358,14 +375,14 @@ CryptoX_Result mar_verify_extracted_signatures( for (i = 0; i < signatureCount; i++) { /* Get the signature algorithm ID */ if (CryptoX_Failed(ReadAndUpdateVerifyContext( - mar, &mar_position, &buf, sizeof(uint32_t), signatureHandles, - signatureCount, "signature algorithm ID"))) { + fp, &buf, sizeof(uint32_t), signatureHandles, signatureCount, + "signature algorithm ID"))) { goto failure; } if (CryptoX_Failed(ReadAndUpdateVerifyContext( - mar, &mar_position, &signatureLengths[i], sizeof(uint32_t), - signatureHandles, signatureCount, "signature length"))) { + fp, &signatureLengths[i], sizeof(uint32_t), signatureHandles, + signatureCount, "signature length"))) { goto failure; } signatureLengths[i] = ntohl(signatureLengths[i]); @@ -375,15 +392,20 @@ CryptoX_Result mar_verify_extracted_signatures( } /* Skip past the signature itself as those are not included */ - if (mar_buffer_seek(mar, &mar_position, signatureLengths[i]) != 0) { + if (fseeko(fp, signatureLengths[i], SEEK_CUR)) { fprintf(stderr, "ERROR: Could not seek past signature.\n"); goto failure; } } /* Read the rest of the file after the signature block */ - while (mar_position < mar->data_len) { - int numRead = mar_read_buffer_max(mar, buf, &mar_position, BLOCKSIZE); + while (!feof(fp)) { + int numRead = fread(buf, 1, BLOCKSIZE, fp); + if (ferror(fp)) { + fprintf(stderr, "ERROR: Error reading data block.\n"); + goto failure; + } + for (i = 0; i < signatureCount; i++) { if (CryptoX_Failed( CryptoX_VerifyUpdate(&signatureHandles[i], buf, numRead))) { diff --git a/toolkit/mozapps/update/updater/archivereader.cpp b/toolkit/mozapps/update/updater/archivereader.cpp index e72df8d66ced..534ed2d176bd 100644 --- a/toolkit/mozapps/update/updater/archivereader.cpp +++ b/toolkit/mozapps/update/updater/archivereader.cpp @@ -203,15 +203,12 @@ int ArchiveReader::Open(const NS_tchar* path) { } } - MarReadResult result = #ifdef XP_WIN - mar_wopen(path, &mArchive); + mArchive = mar_wopen(path); #else - mar_open(path, &mArchive); + mArchive = mar_open(path); #endif - if (result == MAR_MEM_ERROR) { - return ARCHIVE_READER_MEM_ERROR; - } else if (result != MAR_READ_SUCCESS) { + if (!mArchive) { return READ_ERROR; }