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 #endif
#include "nss_secutil.h" #include "nss_secutil.h"
#include "base64.h"
/** /**
* Initializes the NSS context. * Initializes the NSS context.
@ -477,6 +478,119 @@ failure:
return rv; 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. * 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 * The passed in MAR file must not already be signed or an error will

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

@ -16,8 +16,11 @@ extern "C" {
#endif #endif
/* We have a MAX_SIGNATURES limit so that an invalid MAR will never /* We have a MAX_SIGNATURES limit so that an invalid MAR will never
waste too much of either updater's or signmar's time. * waste too much of either updater's or signmar's time.
It is also used at various places internally and will affect memory usage. */ * 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 #define MAX_SIGNATURES 8
PR_STATIC_ASSERT(MAX_SIGNATURES <= 9); PR_STATIC_ASSERT(MAX_SIGNATURES <= 9);

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

@ -108,6 +108,18 @@ refresh_product_info_block(const char *path,
int int
strip_signature_block(const char *src, const char * dest); 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 #ifdef __cplusplus
} }
#endif #endif

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

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