зеркало из https://github.com/mozilla/pjs.git
Bug 720688 - Ability to strip MAR signatures in libmar. r=rstrong
This commit is contained in:
Родитель
6a7fe06479
Коммит
d781b5bdff
|
@ -173,6 +173,33 @@ WriteAndUpdateSignature(FILE *fpDest, void *buffer,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts each entry's content offset in the the passed in index by the
|
||||
* specified amount.
|
||||
*
|
||||
* @param indexBuf A buffer containing the MAR index
|
||||
* @param indexLength The length of the MAR index
|
||||
* @param offsetAmount The amount to adjust each index entry by
|
||||
*/
|
||||
void
|
||||
AdjustIndexContentOffsets(char *indexBuf, PRUint32 indexLength, PRUint32 offsetAmount)
|
||||
{
|
||||
PRUint32 *offsetToContent;
|
||||
char *indexBufLoc = indexBuf;
|
||||
|
||||
/* Consume the index and adjust each index by the specified amount */
|
||||
while (indexBufLoc != (indexBuf + indexLength)) {
|
||||
/* Adjust the offset */
|
||||
offsetToContent = (PRUint32 *)indexBufLoc;
|
||||
*offsetToContent = ntohl(*offsetToContent);
|
||||
*offsetToContent += offsetAmount;
|
||||
*offsetToContent = htonl(*offsetToContent);
|
||||
/* Skip past the offset, length, and flags */
|
||||
indexBufLoc += 3 * sizeof(PRUint32);
|
||||
indexBufLoc += strlen(indexBufLoc) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from fpSrc, writes it to fpDest, and updates the signature context.
|
||||
*
|
||||
|
@ -205,7 +232,275 @@ ReadWriteAndUpdateSignature(FILE *fpSrc, FILE *fpDest, void *buffer,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Reads from fpSrc, writes it to fpDest.
|
||||
*
|
||||
* @param fpSrc The file pointer to read from.
|
||||
* @param fpDest The file pointer to write to.
|
||||
* @param buffer The buffer to write.
|
||||
* @param size The size of the buffer to write.
|
||||
* @param err The name of what is being written to in case of error.
|
||||
* @return 0 on success
|
||||
* -1 on read error
|
||||
* -2 on write error
|
||||
*/
|
||||
int
|
||||
ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer,
|
||||
PRUint32 size, const char *err)
|
||||
{
|
||||
if (!size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fread(buffer, size, 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not read %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fwrite(buffer, size, 1, fpDest) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not write %s\n", err);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out a copy of the MAR at src but with the signature block stripped.
|
||||
*
|
||||
* @param src The path of the source MAR file
|
||||
* @param dest The path of the MAR file to write out that
|
||||
has no signature block
|
||||
* @return 0 on success
|
||||
* -1 on error
|
||||
*/
|
||||
int
|
||||
strip_signature_block(const char *src, const char * dest)
|
||||
{
|
||||
PRUint32 offsetToIndex, dstOffsetToIndex, indexLength,
|
||||
numSignatures = 0, leftOver;
|
||||
PRInt32 stripAmount = 0;
|
||||
PRInt64 oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR, numBytesToCopy,
|
||||
numChunks, i;
|
||||
FILE *fpSrc = NULL, *fpDest = NULL;
|
||||
int rv = -1, hasSignatureBlock;
|
||||
char buf[BLOCKSIZE];
|
||||
char *indexBuf = NULL, *indexBufLoc;
|
||||
|
||||
if (!src || !dest) {
|
||||
fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fpSrc = fopen(src, "rb");
|
||||
if (!fpSrc) {
|
||||
fprintf(stderr, "ERROR: could not open source file: %s\n", dest);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
fpDest = fopen(dest, "wb");
|
||||
if (!fpDest) {
|
||||
fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Determine if the source MAR file has the new fields for signing or not */
|
||||
if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
|
||||
fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* MAR ID */
|
||||
if (ReadAndWrite(fpSrc, fpDest, buf, MAR_ID_SIZE, "MAR ID")) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Offset to index */
|
||||
if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not read offset\n");
|
||||
goto failure;
|
||||
}
|
||||
offsetToIndex = ntohl(offsetToIndex);
|
||||
|
||||
/* Get the real size of the MAR */
|
||||
oldPos = ftello(fpSrc);
|
||||
if (fseeko(fpSrc, 0, SEEK_END)) {
|
||||
fprintf(stderr, "ERROR: Could not seek to end of file.\n");
|
||||
goto failure;
|
||||
}
|
||||
realSizeOfSrcMAR = ftello(fpSrc);
|
||||
if (fseeko(fpSrc, oldPos, SEEK_SET)) {
|
||||
fprintf(stderr, "ERROR: Could not seek back to current location.\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (hasSignatureBlock) {
|
||||
/* Get the MAR length and adjust its size */
|
||||
if (fread(&sizeOfEntireMAR,
|
||||
sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could read mar size\n");
|
||||
goto failure;
|
||||
}
|
||||
sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
|
||||
if (sizeOfEntireMAR != realSizeOfSrcMAR) {
|
||||
fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Get the num signatures in the source file so we know what to strip */
|
||||
if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could read num signatures\n");
|
||||
goto failure;
|
||||
}
|
||||
numSignatures = ntohl(numSignatures);
|
||||
|
||||
for (i = 0; i < numSignatures; i++) {
|
||||
PRUint32 signatureLen;
|
||||
|
||||
/* Skip past the signature algorithm ID */
|
||||
if (fseeko(fpSrc, sizeof(PRUint32), SEEK_CUR)) {
|
||||
fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
|
||||
}
|
||||
|
||||
/* Read in the length of the signature so we know how far to skip */
|
||||
if (fread(&signatureLen, sizeof(PRUint32), 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not read signatures length.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
signatureLen = ntohl(signatureLen);
|
||||
|
||||
/* Skip past the signature */
|
||||
if (fseeko(fpSrc, signatureLen, SEEK_CUR)) {
|
||||
fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
|
||||
}
|
||||
|
||||
stripAmount += sizeof(PRUint32) + sizeof(PRUint32) + signatureLen;
|
||||
}
|
||||
|
||||
} else {
|
||||
sizeOfEntireMAR = realSizeOfSrcMAR;
|
||||
numSignatures = 0;
|
||||
}
|
||||
|
||||
if (((PRInt64)offsetToIndex) > sizeOfEntireMAR) {
|
||||
fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
dstOffsetToIndex = offsetToIndex;
|
||||
if (!hasSignatureBlock) {
|
||||
dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
|
||||
}
|
||||
dstOffsetToIndex -= stripAmount;
|
||||
|
||||
/* Write out the index offset */
|
||||
dstOffsetToIndex = htonl(dstOffsetToIndex);
|
||||
if (fwrite(&dstOffsetToIndex, sizeof(dstOffsetToIndex), 1, fpDest) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not write offset to index\n");
|
||||
goto failure;
|
||||
}
|
||||
dstOffsetToIndex = ntohl(dstOffsetToIndex);
|
||||
|
||||
/* Write out the new MAR file size */
|
||||
if (!hasSignatureBlock) {
|
||||
sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
|
||||
}
|
||||
sizeOfEntireMAR -= stripAmount;
|
||||
|
||||
/* Write out the MAR size */
|
||||
sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
|
||||
if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fpDest) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not write size of MAR\n");
|
||||
goto failure;
|
||||
}
|
||||
sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
|
||||
|
||||
/* Write out the number of signatures, which is 0 */
|
||||
numSignatures = 0;
|
||||
if (fwrite(&numSignatures, sizeof(numSignatures), 1, fpDest) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not write out num signatures\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Write out the rest of the MAR excluding the index header and index
|
||||
offsetToIndex unfortunately has to remain 32-bit because for backwards
|
||||
compatibility with the old MAR file format. */
|
||||
if (ftello(fpSrc) > ((PRInt64)offsetToIndex)) {
|
||||
fprintf(stderr, "ERROR: Index offset is too small.\n");
|
||||
goto failure;
|
||||
}
|
||||
numBytesToCopy = ((PRInt64)offsetToIndex) - ftello(fpSrc);
|
||||
numChunks = numBytesToCopy / BLOCKSIZE;
|
||||
leftOver = numBytesToCopy % BLOCKSIZE;
|
||||
|
||||
/* Read each file and write it to the MAR file */
|
||||
for (i = 0; i < numChunks; ++i) {
|
||||
if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write out the left over */
|
||||
if (ReadAndWrite(fpSrc, fpDest, buf,
|
||||
leftOver, "left over content block")) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Length of the index */
|
||||
if (ReadAndWrite(fpSrc, fpDest, &indexLength,
|
||||
sizeof(indexLength), "index length")) {
|
||||
goto failure;
|
||||
}
|
||||
indexLength = ntohl(indexLength);
|
||||
|
||||
/* Consume the index and adjust each index by the difference */
|
||||
indexBuf = malloc(indexLength);
|
||||
indexBufLoc = indexBuf;
|
||||
if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not read index\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Adjust each entry in the index */
|
||||
if (hasSignatureBlock) {
|
||||
AdjustIndexContentOffsets(indexBuf, indexLength, -stripAmount);
|
||||
} else {
|
||||
AdjustIndexContentOffsets(indexBuf, indexLength,
|
||||
sizeof(sizeOfEntireMAR) +
|
||||
sizeof(numSignatures) -
|
||||
stripAmount);
|
||||
}
|
||||
|
||||
if (fwrite(indexBuf, indexLength, 1, fpDest) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not write index\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
failure:
|
||||
if (fpSrc) {
|
||||
fclose(fpSrc);
|
||||
}
|
||||
|
||||
if (fpDest) {
|
||||
fclose(fpDest);
|
||||
}
|
||||
|
||||
if (rv) {
|
||||
remove(dest);
|
||||
}
|
||||
|
||||
if (indexBuf) {
|
||||
free(indexBuf);
|
||||
}
|
||||
|
||||
if (rv) {
|
||||
remove(dest);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out a copy of the MAR at src but with an embedded signature.
|
||||
* The passed in MAR file must not already be signed or an error will
|
||||
* be returned.
|
||||
|
@ -225,7 +520,7 @@ mar_repackage_and_sign(const char *NSSConfigDir,
|
|||
{
|
||||
PRUint32 offsetToIndex, dstOffsetToIndex, indexLength,
|
||||
numSignatures = 0, signatureLength, leftOver,
|
||||
signatureAlgorithmID, *offsetToContent, signatureSectionLength;
|
||||
signatureAlgorithmID, signatureSectionLength;
|
||||
PRInt64 oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR,
|
||||
signaturePlaceholderOffset, numBytesToCopy,
|
||||
numChunks, i;
|
||||
|
@ -441,19 +736,17 @@ mar_repackage_and_sign(const char *NSSConfigDir,
|
|||
fprintf(stderr, "ERROR: Could not read index\n");
|
||||
goto failure;
|
||||
}
|
||||
while (indexBufLoc != (indexBuf + indexLength)) {
|
||||
/* Adjust the offset */
|
||||
offsetToContent = (PRUint32 *)indexBufLoc;
|
||||
*offsetToContent = ntohl(*offsetToContent);
|
||||
if (!hasSignatureBlock) {
|
||||
*offsetToContent += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
|
||||
}
|
||||
*offsetToContent += signatureSectionLength;
|
||||
*offsetToContent = htonl(*offsetToContent);
|
||||
/* Skip past the offset, length, and flags */
|
||||
indexBufLoc += 3 * sizeof(PRUint32);
|
||||
indexBufLoc += strlen(indexBufLoc) + 1;
|
||||
|
||||
/* Adjust each entry in the index */
|
||||
if (hasSignatureBlock) {
|
||||
AdjustIndexContentOffsets(indexBuf, indexLength, signatureSectionLength);
|
||||
} else {
|
||||
AdjustIndexContentOffsets(indexBuf, indexLength,
|
||||
sizeof(sizeOfEntireMAR) +
|
||||
sizeof(numSignatures) +
|
||||
signatureSectionLength);
|
||||
}
|
||||
|
||||
if (WriteAndUpdateSignature(fpDest, indexBuf,
|
||||
indexLength, ctx, "index")) {
|
||||
goto failure;
|
||||
|
|
|
@ -103,6 +103,18 @@ int
|
|||
read_product_info_block(char *path,
|
||||
struct ProductInformationBlock *infoBlock);
|
||||
|
||||
/**
|
||||
* Writes out a copy of the MAR at src but with the signature block stripped.
|
||||
*
|
||||
* @param src The path of the source MAR file
|
||||
* @param dest The path of the MAR file to write out that
|
||||
has no signature block
|
||||
* @return 0 on success
|
||||
* -1 on error
|
||||
*/
|
||||
int
|
||||
strip_signature_block(const char *src, const char * dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -65,7 +65,8 @@ static void print_usage() {
|
|||
#ifndef NO_SIGN_VERIFY
|
||||
printf(" mar [-C workingDir] -d NSSConfigDir -n certname -s "
|
||||
"archive.mar out_signed_archive.mar\n");
|
||||
|
||||
printf(" mar [-C workingDir] -r "
|
||||
"signed_input_archive.mar output_archive.mar\n");
|
||||
#if defined(XP_WIN) && !defined(MAR_NSS)
|
||||
printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
|
||||
#else
|
||||
|
@ -120,7 +121,8 @@ int main(int argc, char **argv) {
|
|||
if (argv[1][0] == '-' && (argv[1][1] == 'c' ||
|
||||
argv[1][1] == 't' || argv[1][1] == 'x' ||
|
||||
argv[1][1] == 'v' || argv[1][1] == 's' ||
|
||||
argv[1][1] == 'i' || argv[1][1] == 'T')) {
|
||||
argv[1][1] == 'i' || argv[1][1] == 'T' ||
|
||||
argv[1][1] == 'r')) {
|
||||
break;
|
||||
/* -C workingdirectory */
|
||||
} else if (argv[1][0] == '-' && argv[1][1] == 'C') {
|
||||
|
@ -289,6 +291,9 @@ int main(int argc, char **argv) {
|
|||
return -1;
|
||||
}
|
||||
return mar_repackage_and_sign(NSSConfigDir, certName, argv[2], argv[3]);
|
||||
|
||||
case 'r':
|
||||
return strip_signature_block(argv[2], argv[3]);
|
||||
#endif /* endif NO_SIGN_VERIFY disabled */
|
||||
|
||||
default:
|
||||
|
|
Загрузка…
Ссылка в новой задаче