Bug 798413 - Export signature from MAR files implementation. r=bsmith, a=blocking-basecamp

This commit is contained in:
Brian R. Bondy 2012-10-17 09:39:44 -04:00
Родитель 766128af2d
Коммит 73f5fc7a03
4 изменённых файлов: 170 добавлений и 6 удалений

Просмотреть файл

@ -22,6 +22,7 @@
#endif
#include "nss_secutil.h"
#include "base64.h"
/**
* Initializes the NSS context.
@ -477,6 +478,119 @@ failure:
return rv;
}
/**
* Extracts a signature from a MAR file, base64 encodes it, and writes it out
*
* @param src The path of the source MAR file
* @param sigIndex The index of the signature to extract
* @param dest The path of file to write the signature to
* @return 0 on success
* -1 on error
*/
int
extract_signature(const char *src, uint32_t sigIndex, const char * dest)
{
FILE *fpSrc = NULL, *fpDest = NULL;
uint32_t i;
uint32_t signatureCount;
uint32_t signatureLen;
uint8_t *extractedSignature = NULL;
char *base64Encoded = NULL;
int rv = -1;
if (!src || !dest) {
fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
goto failure;
}
fpSrc = fopen(src, "rb");
if (!fpSrc) {
fprintf(stderr, "ERROR: could not open source file: %s\n", src);
goto failure;
}
fpDest = fopen(dest, "wb");
if (!fpDest) {
fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
goto failure;
}
/* Skip to the start of the signature block */
if (fseeko(fpSrc, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
fprintf(stderr, "ERROR: could not seek to signature block\n");
goto failure;
}
/* Get the number of signatures */
if (fread(&signatureCount, sizeof(signatureCount), 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: could not read signature count\n");
goto failure;
}
signatureCount = ntohl(signatureCount);
if (sigIndex >= signatureCount) {
fprintf(stderr, "ERROR: Signature index was out of range\n");
goto failure;
}
/* Skip to the correct signature */
for (i = 0; i <= sigIndex; i++) {
/* skip past the signature algorithm ID */
if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
fprintf(stderr, "ERROR: Could not seek past sig algorithm ID.\n");
goto failure;
}
/* Get the signature length */
if (fread(&signatureLen, sizeof(signatureLen), 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: could not read signature length\n");
goto failure;
}
signatureLen = ntohl(signatureLen);
/* Get the signature */
extractedSignature = malloc(signatureLen);
if (fread(extractedSignature, signatureLen, 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: could not read signature\n");
goto failure;
}
}
base64Encoded = BTOA_DataToAscii(extractedSignature, signatureLen);
if (!base64Encoded) {
fprintf(stderr, "ERROR: could not obtain base64 encoded data\n");
goto failure;
}
if (fwrite(base64Encoded, strlen(base64Encoded), 1, fpDest) != 1) {
fprintf(stderr, "ERROR: Could not write base64 encoded string\n");
goto failure;
}
rv = 0;
failure:
if (base64Encoded) {
PORT_Free(base64Encoded);
}
if (extractedSignature) {
free(extractedSignature);
}
if (fpSrc) {
fclose(fpSrc);
}
if (fpDest) {
fclose(fpDest);
}
if (rv) {
remove(dest);
}
return rv;
}
/**
* Writes out a copy of the MAR at src but with embedded signatures.
* The passed in MAR file must not already be signed or an error will

Просмотреть файл

@ -16,8 +16,11 @@ extern "C" {
#endif
/* We have a MAX_SIGNATURES limit so that an invalid MAR will never
waste too much of either updater's or signmar's time.
It is also used at various places internally and will affect memory usage. */
* waste too much of either updater's or signmar's time.
* It is also used at various places internally and will affect memory usage.
* If you want to increase this value above 9 then you need to adjust parsing
* code in tool/mar.c.
*/
#define MAX_SIGNATURES 8
PR_STATIC_ASSERT(MAX_SIGNATURES <= 9);

Просмотреть файл

@ -108,6 +108,18 @@ refresh_product_info_block(const char *path,
int
strip_signature_block(const char *src, const char * dest);
/**
* Extracts a signature from a MAR file, base64 encodes it, and writes it out
*
* @param src The path of the source MAR file
* @param sigIndex The index of the signature to extract
* @param dest The path of file to write the signature to
* @return 0 on success
* -1 on error
*/
int
extract_signature(const char *src, uint32_t sigIndex, const char * dest);
#ifdef __cplusplus
}
#endif

Просмотреть файл

@ -30,18 +30,27 @@ int mar_repackage_and_sign(const char *NSSConfigDir,
static void print_usage() {
printf("usage:\n");
printf("Create a MAR file:\n");
printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
"{-c|-x|-t|-T} archive.mar [files...]\n");
#ifndef NO_SIGN_VERIFY
printf("Sign a MAR file:\n");
printf(" mar [-C workingDir] -d NSSConfigDir -n certname -s "
"archive.mar out_signed_archive.mar\n");
printf("Strip a MAR signature:\n");
printf(" mar [-C workingDir] -r "
"signed_input_archive.mar output_archive.mar\n");
printf("Extract a MAR signature:\n");
printf(" mar [-C workingDir] -n(i) -X "
"signed_input_archive.mar base_64_encoded_signature_file\n");
printf("(i) is the index of the certificate to extract\n");
#if defined(XP_WIN) && !defined(MAR_NSS)
printf("Verify a MAR file:\n");
printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
printf("At most %d signature certificate DER files are specified by "
"-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
#else
printf("Verify a MAR file:\n");
printf(" mar [-C workingDir] -d NSSConfigDir -n certname "
"-v signed_archive.mar\n");
printf("At most %d signature certificate names are specified by "
@ -50,6 +59,7 @@ static void print_usage() {
printf("At most %d verification certificate names are specified by "
"-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
#endif
printf("Print information on a MAR file:\n");
printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
"-i unsigned_archive_to_refresh.mar\n");
printf("This program does not handle unicode file paths properly\n");
@ -84,6 +94,7 @@ int main(int argc, char **argv) {
uint32_t i, k;
int rv = -1;
uint32_t certCount = 0;
int32_t sigIndex = -1;
#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
HANDLE certFile;
/* We use DWORD here instead of uint64_t because it simplifies code with
@ -112,7 +123,7 @@ int main(int argc, char **argv) {
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] == 'r')) {
argv[1][1] == 'r' || argv[1][1] == 'X')) {
break;
/* -C workingdirectory */
} else if (argv[1][0] == '-' && argv[1][1] == 'C') {
@ -146,14 +157,24 @@ int main(int argc, char **argv) {
with the import and export command line arguments. */
} else if (argv[1][0] == '-' &&
argv[1][1] == 'n' &&
(argv[1][2] == '0' + certCount || argv[1][2] == '\0')) {
(argv[1][2] == '0' + certCount ||
argv[1][2] == '\0' ||
!strcmp(argv[2], "-X"))) {
if (certCount >= MAX_SIGNATURES) {
print_usage();
return -1;
}
certNames[certCount++] = argv[2];
argv += 2;
argc -= 2;
if (strlen(argv[1]) > 2 &&
!strcmp(argv[2], "-X") &&
argv[1][2] >= '0' && argv[1][2] <= '9') {
sigIndex = argv[1][2] - '0';
argv++;
argc--;
} else {
argv += 2;
argc -= 2;
}
/* MAR channel ID */
} else if (argv[1][0] == '-' && argv[1][1] == 'H') {
MARChannelID = argv[2];
@ -226,10 +247,24 @@ int main(int argc, char **argv) {
case 't':
return mar_test(argv[2]);
/* Extract a MAR file */
case 'x':
return mar_extract(argv[2]);
#ifndef NO_SIGN_VERIFY
/* Extract a MAR signature */
case 'X':
if (sigIndex == -1) {
fprintf(stderr, "ERROR: Signature index was not passed.\n");
return -1;
}
if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) {
fprintf(stderr, "ERROR: Signature index is out of range: %d.\n",
sigIndex);
return -1;
}
return extract_signature(argv[2], sigIndex, argv[3]);
case 'v':
#if defined(XP_WIN) && !defined(MAR_NSS)