Bug 699700 - Add support for signing and verifying MAR files in libmar and the mar program. r=bsmith

This commit is contained in:
Brian R. Bondy 2012-02-24 16:29:41 -05:00
Родитель 029c03124b
Коммит 3458244776
20 изменённых файлов: 2356 добавлений и 34 удалений

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

@ -43,6 +43,6 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = src tool
DIRS = sign verify src tool
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,69 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mar signing build config.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Brian R. Bondy <netzen@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = signmar
LIBRARY_NAME = signmar
FORCE_STATIC_LIB = 1
ifeq ($(OS_ARCH),WINNT)
USE_STATIC_LIBS = 1
endif
# This makefile just builds support for reading archives.
CSRCS = \
mar_sign.c \
nss_secutil.c \
$(NULL)
LOCAL_INCLUDES += -I$(srcdir)/../src \
-I$(srcdir)/../verify \
-I$(topsrcdir)/dist/include \
$(NULL)
CFLAGS += -DMAR_NSS
include $(topsrcdir)/config/rules.mk
# The intermediate (.ii/.s) files for host and target can have the same name...
# disable parallel builds
.NOTPARALLEL:

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

@ -0,0 +1,525 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Archive signing code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef XP_WIN
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include "mar_private.h"
#include "mar_cmdline.h"
#include "mar.h"
#include "cryptox.h"
#ifndef XP_WIN
#include <unistd.h>
#endif
#include "nss_secutil.h"
/**
* Initializes the NSS context.
*
* @param NSSConfigDir The config dir containing the private key to use
* @return 0 on success
* -1 on error
*/
int
NSSInitCryptoContext(const char *NSSConfigDir)
{
SECStatus status = NSS_Initialize(NSSConfigDir,
"", "", SECMOD_DB, NSS_INIT_READONLY);
if (SECSuccess != status) {
fprintf(stderr, "ERROR: Could not initialize NSS\n");
return -1;
}
return 0;
}
/**
* Obtains a signing context.
*
* @param ctx A pointer to the signing context to fill
* @return 0 on success
* -1 on error
*/
int
NSSSignBegin(const char *certName,
SGNContext **ctx,
SECKEYPrivateKey **privKey,
CERTCertificate **cert,
PRUint32 *signatureLength)
{
secuPWData pwdata = { PW_NONE, 0 };
if (!certName || !ctx || !privKey || !cert || !signatureLength) {
fprintf(stderr, "ERROR: Invalid parameter passed to NSSSignBegin\n");
return -1;
}
/* Get the cert and embedded public key out of the database */
*cert = PK11_FindCertFromNickname(certName, &pwdata);
if (!*cert) {
fprintf(stderr, "ERROR: Could not find cert from nickname\n");
return -1;
}
/* Get the private key out of the database */
*privKey = PK11_FindKeyByAnyCert(*cert, &pwdata);
if (!*privKey) {
fprintf(stderr, "ERROR: Could not find private key\n");
return -1;
}
*signatureLength = PK11_SignatureLen(*privKey);
if (*signatureLength > BLOCKSIZE) {
fprintf(stderr,
"ERROR: Program must be compiled with a larger block size"
" to support signing with signatures this large: %u.\n",
*signatureLength);
return -1;
}
/* Check that the key length is large enough for our requirements */
if (*signatureLength < XP_MIN_SIGNATURE_LEN_IN_BYTES) {
fprintf(stderr, "ERROR: Key length must be >= %d bytes\n",
XP_MIN_SIGNATURE_LEN_IN_BYTES);
return -1;
}
*ctx = SGN_NewContext (SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, *privKey);
if (!*ctx) {
fprintf(stderr, "ERROR: Could not create signature context\n");
return -1;
}
if (SGN_Begin(*ctx) != SECSuccess) {
fprintf(stderr, "ERROR: Could not begin signature\n");
return -1;
}
return 0;
}
/**
* Writes the passed buffer to the file fp and updates the signature context.
*
* @param fpDest The file pointer to write to.
* @param buffer The buffer to write.
* @param size The size of the buffer to write.
* @param ctx The signature context.
* @param err The name of what is being written to in case of error.
* @return 0 on success
* -2 on write error
* -3 on signature update error
*/
int
WriteAndUpdateSignature(FILE *fpDest, void *buffer,
PRUint32 size, SGNContext *ctx,
const char *err)
{
if (!size) {
return 0;
}
if (fwrite(buffer, size, 1, fpDest) != 1) {
fprintf(stderr, "ERROR: Could not write %s\n", err);
return -2;
}
if (SGN_Update(ctx, (const unsigned char *)buffer, size) != SECSuccess) {
fprintf(stderr, "ERROR: Could not update signature context for %s\n", err);
return -3;
}
return 0;
}
/**
* Reads from fpSrc, writes it to fpDest, and updates the signature context.
*
* @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 ctx The signature context.
* @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
* -3 on signature update error
*/
int
ReadWriteAndUpdateSignature(FILE *fpSrc, FILE *fpDest, void *buffer,
PRUint32 size, SGNContext *ctx,
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;
}
return WriteAndUpdateSignature(fpDest, buffer, size, ctx, err);
}
/**
* 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.
*
* @param NSSConfigDir The NSS directory containing the private key for signing
* @param certName The nickname of the certificate to use for signing
* @param src The path of the source MAR file to sign
* @param dest The path of the MAR file to write out that is signed
* @return 0 on success
* -1 on error
*/
int
mar_repackage_and_sign(const char *NSSConfigDir,
const char *certName,
const char *src,
const char *dest)
{
PRUint32 offsetToIndex, dstOffsetToIndex, indexLength,
numSignatures = 0, signatureLength, leftOver,
signatureAlgorithmID, *offsetToContent, signatureSectionLength;
PRInt64 oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR,
signaturePlaceholderOffset, numBytesToCopy,
numChunks, i;
FILE *fpSrc = NULL, *fpDest = NULL;
int rv = -1, oldMar;
SGNContext *ctx = NULL;
SECItem secItem;
char buf[BLOCKSIZE];
SECKEYPrivateKey *privKey = NULL;
CERTCertificate *cert = NULL;
char *indexBuf = NULL, *indexBufLoc;
if (!NSSConfigDir || !certName || !src || !dest) {
fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
return -1;
}
if (NSSInitCryptoContext(NSSConfigDir)) {
fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
goto failure;
}
PK11_SetPasswordFunc(SECU_GetModulePassword);
if (NSSSignBegin(certName, &ctx, &privKey, &cert, &signatureLength)) {
fprintf(stderr, "ERROR: NSSSignBegin failed\n");
goto failure;
}
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 (is_old_mar(src, &oldMar)) {
fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
goto failure;
}
/* MAR ID */
if (ReadWriteAndUpdateSignature(fpSrc, fpDest,
buf, MAR_ID_SIZE,
ctx, "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 (!oldMar) {
/* 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 skip over */
if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: Could read num signatures\n");
goto failure;
}
numSignatures = ntohl(numSignatures);
/* We do not support resigning */
if (numSignatures) {
fprintf(stderr, "ERROR: MAR is already signed\n");
goto failure;
}
} else {
sizeOfEntireMAR = realSizeOfSrcMAR;
}
if (((PRInt64)offsetToIndex) > sizeOfEntireMAR) {
fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
goto failure;
}
/* Write out the new offset to the index */
signatureSectionLength = sizeof(signatureAlgorithmID) +
sizeof(signatureLength) +
signatureLength;
dstOffsetToIndex = offsetToIndex;
if (oldMar) {
dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
}
dstOffsetToIndex += signatureSectionLength;
/* Write out the index offset */
dstOffsetToIndex = htonl(dstOffsetToIndex);
if (WriteAndUpdateSignature(fpDest, &dstOffsetToIndex,
sizeof(dstOffsetToIndex), ctx, "index offset")) {
goto failure;
}
dstOffsetToIndex = ntohl(dstOffsetToIndex);
/* Write out the new MAR file size */
sizeOfEntireMAR += signatureSectionLength;
if (oldMar) {
sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
}
/* Write out the MAR size */
sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
if (WriteAndUpdateSignature(fpDest, &sizeOfEntireMAR,
sizeof(sizeOfEntireMAR), ctx, "size of MAR")) {
goto failure;
}
sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
/* Write out the number of signatures, for now only 1 is supported */
numSignatures = 1;
numSignatures = htonl(numSignatures);
if (WriteAndUpdateSignature(fpDest, &numSignatures,
sizeof(numSignatures), ctx, "num signatures")) {
goto failure;
}
numSignatures = ntohl(numSignatures);
/* Write out the signature ID, for now only an ID of 1 is supported */
signatureAlgorithmID = htonl(1);
if (WriteAndUpdateSignature(fpDest, &signatureAlgorithmID,
sizeof(signatureAlgorithmID),
ctx, "num signatures")) {
goto failure;
}
signatureAlgorithmID = ntohl(signatureAlgorithmID);
/* Write out the signature length */
signatureLength = htonl(signatureLength);
if (WriteAndUpdateSignature(fpDest, &signatureLength,
sizeof(signatureLength),
ctx, "signature length")) {
goto failure;
}
signatureLength = ntohl(signatureLength);
/* Write out a placeholder for the signature, we'll come back to this later
*** THIS IS NOT SIGNED because it is a placeholder that will be replaced
below, plus it is going to be the signature itself. *** */
memset(buf, 0, sizeof(buf));
signaturePlaceholderOffset = ftello(fpDest);
if (fwrite(buf, signatureLength, 1, fpDest) != 1) {
fprintf(stderr, "ERROR: Could not write signature length\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 (ReadWriteAndUpdateSignature(fpSrc, fpDest, buf,
BLOCKSIZE, ctx, "content block")) {
goto failure;
}
}
/* Write out the left over */
if (ReadWriteAndUpdateSignature(fpSrc, fpDest, buf,
leftOver, ctx, "left over content block")) {
goto failure;
}
/* Length of the index */
if (ReadWriteAndUpdateSignature(fpSrc, fpDest, &indexLength,
sizeof(indexLength), ctx, "index length")) {
goto failure;
}
indexLength = ntohl(indexLength);
/* Consume the index and adjust each index by signatureSectionLength */
indexBuf = malloc(indexLength);
indexBufLoc = indexBuf;
if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: Could not read index\n");
goto failure;
}
while (indexBufLoc != (indexBuf + indexLength)) {
/* Adjust the offset */
offsetToContent = (PRUint32 *)indexBufLoc;
*offsetToContent = ntohl(*offsetToContent);
if (oldMar) {
*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;
}
if (WriteAndUpdateSignature(fpDest, indexBuf,
indexLength, ctx, "index")) {
goto failure;
}
/* Ensure that we don't sign a file that is too large to be accepted by
the verification function. */
if (ftello(fpDest) > MAX_SIZE_OF_MAR_FILE) {
goto failure;
}
/* Get the signature */
if (SGN_End(ctx, &secItem) != SECSuccess) {
fprintf(stderr, "ERROR: Could not end signature context\n");
goto failure;
}
if (signatureLength != secItem.len) {
fprintf(stderr, "ERROR: Signature is not the expected length\n");
goto failure;
}
/* Get back to the location of the signature placeholder */
if (fseeko(fpDest, signaturePlaceholderOffset, SEEK_SET)) {
fprintf(stderr, "ERROR: Could not seek to signature offset\n");
goto failure;
}
/* Write out the calculated signature.
*** THIS IS NOT SIGNED because it is the signature itself. *** */
if (fwrite(secItem.data, secItem.len, 1, fpDest) != 1) {
fprintf(stderr, "ERROR: Could not write signature\n");
goto failure;
}
rv = 0;
failure:
if (fpSrc) {
fclose(fpSrc);
}
if (fpDest) {
fclose(fpDest);
}
if (rv) {
remove(dest);
}
if (indexBuf) {
free(indexBuf);
}
if (ctx) {
SGN_DestroyContext(ctx, PR_TRUE);
}
if (cert) {
CERT_DestroyCertificate(cert);
}
if (privKey) {
SECKEY_DestroyPrivateKey(privKey);
}
if (rv) {
remove(dest);
}
return rv;
}

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

@ -0,0 +1,269 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is code copied from secutil and secpwd.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* With the exception of GetPasswordString, this file was
copied from NSS's cmd/lib/secutil.c hg revision 8f011395145e */
#include "nss_secutil.h"
#include "prprf.h"
#ifdef XP_WIN
#include <io.h>
#else
#include <unistd.h>
#endif
static char consoleName[] = {
#ifdef XP_UNIX
"/dev/tty"
#else
#ifdef XP_OS2
"\\DEV\\CON"
#else
"CON:"
#endif
#endif
};
#if defined(_WINDOWS)
static char * quiet_fgets (char *buf, int length, FILE *input)
{
int c;
char *end = buf;
/* fflush (input); */
memset (buf, 0, length);
if (!isatty(fileno(input))) {
return fgets(buf,length,input);
}
while (1)
{
#if defined (_WIN32_WCE)
c = getchar(); /* gets a character from stdin */
#else
c = getch(); /* getch gets a character from the console */
#endif
if (c == '\b')
{
if (end > buf)
end--;
}
else if (--length > 0)
*end++ = c;
if (!c || c == '\n' || c == '\r')
break;
}
return buf;
}
#endif
char *
GetPasswordString(void *arg, char *prompt)
{
FILE *input = stdin;
char phrase[200] = {'\0'};
int isInputTerminal = isatty(fileno(stdin));
#ifndef _WINDOWS
if (isInputTerminal) {
input = fopen(consoleName, "r");
if (input == NULL) {
fprintf(stderr, "Error opening input terminal for read\n");
return NULL;
}
}
#endif
if (isInputTerminal) {
fprintf(stdout, "Please enter your password:\n");
fflush(stdout);
}
QUIET_FGETS (phrase, sizeof(phrase), input);
if (isInputTerminal) {
fprintf(stdout, "\n");
}
#ifndef _WINDOWS
if (isInputTerminal) {
fclose(input);
}
#endif
/* Strip off the newlines if present */
if (phrase[PORT_Strlen(phrase)-1] == '\n' ||
phrase[PORT_Strlen(phrase)-1] == '\r') {
phrase[PORT_Strlen(phrase)-1] = 0;
}
return (char*) PORT_Strdup(phrase);
}
char *
SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
{
char* phrases, *phrase;
PRFileDesc *fd;
PRInt32 nb;
char *pwFile = arg;
int i;
const long maxPwdFileSize = 4096;
char* tokenName = NULL;
int tokenLen = 0;
if (!pwFile)
return 0;
if (retry) {
return 0; /* no good retrying - the files contents will be the same */
}
phrases = PORT_ZAlloc(maxPwdFileSize);
if (!phrases) {
return 0; /* out of memory */
}
fd = PR_Open(pwFile, PR_RDONLY, 0);
if (!fd) {
fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
PORT_Free(phrases);
return NULL;
}
nb = PR_Read(fd, phrases, maxPwdFileSize);
PR_Close(fd);
if (nb == 0) {
fprintf(stderr,"password file contains no data\n");
PORT_Free(phrases);
return NULL;
}
if (slot) {
tokenName = PK11_GetTokenName(slot);
if (tokenName) {
tokenLen = PORT_Strlen(tokenName);
}
}
i = 0;
do
{
int startphrase = i;
int phraseLen;
/* handle the Windows EOL case */
while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++;
/* terminate passphrase */
phrases[i++] = '\0';
/* clean up any EOL before the start of the next passphrase */
while ( (i<nb) && (phrases[i] == '\r' || phrases[i] == '\n')) {
phrases[i++] = '\0';
}
/* now analyze the current passphrase */
phrase = &phrases[startphrase];
if (!tokenName)
break;
if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue;
phraseLen = PORT_Strlen(phrase);
if (phraseLen < (tokenLen+1)) continue;
if (phrase[tokenLen] != ':') continue;
phrase = &phrase[tokenLen+1];
break;
} while (i<nb);
phrase = PORT_Strdup((char*)phrase);
PORT_Free(phrases);
return phrase;
}
char *
SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg)
{
char prompt[255];
secuPWData *pwdata = (secuPWData *)arg;
secuPWData pwnull = { PW_NONE, 0 };
secuPWData pwxtrn = { PW_EXTERNAL, "external" };
char *pw;
if (pwdata == NULL)
pwdata = &pwnull;
if (PK11_ProtectedAuthenticationPath(slot)) {
pwdata = &pwxtrn;
}
if (retry && pwdata->source != PW_NONE) {
PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
return NULL;
}
switch (pwdata->source) {
case PW_NONE:
sprintf(prompt, "Enter Password or Pin for \"%s\":",
PK11_GetTokenName(slot));
return GetPasswordString(NULL, prompt);
case PW_FROMFILE:
/* Instead of opening and closing the file every time, get the pw
* once, then keep it in memory (duh).
*/
pw = SECU_FilePasswd(slot, retry, pwdata->data);
pwdata->source = PW_PLAINTEXT;
pwdata->data = PL_strdup(pw);
/* it's already been dup'ed */
return pw;
case PW_EXTERNAL:
sprintf(prompt,
"Press Enter, then enter PIN for \"%s\" on external device.\n",
PK11_GetTokenName(slot));
(void) GetPasswordString(NULL, prompt);
/* Fall Through */
case PW_PLAINTEXT:
return PL_strdup(pwdata->data);
default:
break;
}
PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
return NULL;
}

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

@ -0,0 +1,73 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is code copied from secutil and secpwd.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* With the exception of GetPasswordString, this file was
copied from NSS's cmd/lib/secutil.h hg revision 8f011395145e */
#ifndef NSS_SECUTIL_H_
#define NSS_SECUTIL_H_
#include "nss.h"
#include "pk11pub.h"
#include "cryptohi.h"
#include "hasht.h"
#include "cert.h"
#include "key.h"
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
#if( defined(_WINDOWS) && !defined(_WIN32_WCE))
#include <conio.h>
#include <io.h>
#define QUIET_FGETS quiet_fgets
static char * quiet_fgets (char *buf, int length, FILE *input);
#else
#define QUIET_FGETS fgets
#endif
char *
SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg);
#endif

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

@ -53,15 +53,20 @@ endif
# This makefile just builds support for reading archives.
CSRCS = \
HOST_CSRCS = \
mar_create.c \
mar_extract.c \
mar_read.c \
$(NULL)
HOST_CSRCS = $(CSRCS)
CSRCS = \
$(HOST_CSRCS) \
$(NULL)
EXPORTS = \
mar.h \
mar_cmdline.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -57,6 +57,13 @@ typedef struct MarItem_ {
char name[1]; /* file path */
} MarItem;
#define TABLESIZE 256
struct MarFile_ {
FILE *fp;
MarItem *item_table[TABLESIZE];
};
typedef struct MarFile_ MarFile;
/**
@ -137,6 +144,25 @@ int mar_create(const char *dest, int numfiles, char **files);
*/
int mar_extract(const char *path);
/**
* Verifies the embedded signature for the specified mar file.
* We do not check that the certificate was issued by any trusted authority.
* We assume it to be self-signed. We do not check whether the certificate
* is valid for this usage.
*
* @param mar The already opened MAR file.
* @param certData The certificate file data.
* @param sizeOfCertData The size of the cert data.
* @return 0 on success
* a negative number if there was an error
* a positive number if the signature does not verify
*/
#ifdef XP_WIN
int mar_verify_signatureW(MarFile *mar,
const char *certData,
PRUint32 sizeOfCertData);
#endif
#ifdef __cplusplus
}
#endif

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

@ -0,0 +1,82 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is command line utility function declarations.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef MAR_CMDLINE_H__
#define MAR_CMDLINE_H__
/* We use NSPR here just to import the definition of PRUint32 */
#include "prtypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Determines if the MAR file is new or old.
*
* @param path The path of the MAR file to check.
* @param oldMar An out parameter specifying if the MAR file is new or old.
* @return A non-zero value if an error occurred and the information
cannot be determined.
*/
int is_old_mar(const char *path, int *oldMar);
/**
* Verifies the embedded signature of the specified file path.
* This is only used by the signmar program when used with arguments to verify
* a MAR. This should not be used to verify a MAR that will be extracted in the
* same operation by updater code. This function prints the error message if
* verification fails.
*
* @param pathToMAR The path of the MAR file who's signature should be checked
* @param certData The certificate file data.
* @param sizeOfCertData The size of the cert data.
* @param certName Used only if compiled as NSS, specifies the certName
* @return 0 on success
* a negative number if there was an error
* a positive number if the signature does not verify
*/
int mar_verify_signature(const char *pathToMAR,
const char *certData,
PRUint32 sizeOfCertData,
const char *certName);
#ifdef __cplusplus
}
#endif
#endif /* MAR_CMDLINE_H__ */

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

@ -40,10 +40,9 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mar.h"
#include "mar_private.h"
#include "mar.h"
#ifdef XP_WIN
#include <winsock2.h>
@ -127,7 +126,8 @@ static int mar_concat_file(FILE *fp, const char *path) {
int mar_create(const char *dest, int num_files, char **files) {
struct MarItemStack stack;
PRUint32 offset_to_index = 0, size_of_index;
PRUint32 offset_to_index = 0, size_of_index, num_signatures;
PRUint64 size_of_entire_MAR = 0;
struct stat st;
FILE *fp;
int i, rv = -1;
@ -145,7 +145,21 @@ int mar_create(const char *dest, int num_files, char **files) {
if (fwrite(&offset_to_index, sizeof(PRUint32), 1, fp) != 1)
goto failure;
stack.last_offset = MAR_ID_SIZE + sizeof(PRUint32);
stack.last_offset = MAR_ID_SIZE +
sizeof(num_signatures) +
sizeof(offset_to_index) +
sizeof(size_of_entire_MAR);
/* We will circle back on this at the end of the MAR creation to fill it */
if (fwrite(&size_of_entire_MAR, sizeof(size_of_entire_MAR), 1, fp) != 1) {
goto failure;
}
/* Write out the number of signatures, for now only at most 1 is supported */
num_signatures = 0;
if (fwrite(&num_signatures, sizeof(num_signatures), 1, fp) != 1) {
goto failure;
}
for (i = 0; i < num_files; ++i) {
if (stat(files[i], &st)) {
@ -168,12 +182,27 @@ int mar_create(const char *dest, int num_files, char **files) {
if (fwrite(stack.head, stack.size_used, 1, fp) != 1)
goto failure;
/* 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 (ftell(fp) > MAX_SIZE_OF_MAR_FILE) {
goto failure;
}
/* write out offset to index file in network byte order */
offset_to_index = htonl(stack.last_offset);
if (fseek(fp, MAR_ID_SIZE, SEEK_SET))
goto failure;
if (fwrite(&offset_to_index, sizeof(offset_to_index), 1, fp) != 1)
goto failure;
offset_to_index = ntohl(stack.last_offset);
size_of_entire_MAR = ((PRUint64)stack.last_offset) +
stack.size_used +
sizeof(size_of_index);
size_of_entire_MAR = HOST_TO_NETWORK64(size_of_entire_MAR);
if (fwrite(&size_of_entire_MAR, sizeof(size_of_entire_MAR), 1, fp) != 1)
goto failure;
size_of_entire_MAR = NETWORK_TO_HOST64(size_of_entire_MAR);
rv = 0;
failure:

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

@ -41,9 +41,8 @@
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mar.h"
#include "mar_private.h"
#include "mar.h"
#ifdef XP_WIN
#include <io.h>

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

@ -39,12 +39,71 @@
#ifndef MAR_PRIVATE_H__
#define MAR_PRIVATE_H__
#include "prtypes.h"
#include "limits.h"
/* Code in this module requires a guarantee that the size
of PRUint32 and PRUint64 are 4 and 8 bytes respectively. */
PR_STATIC_ASSERT(sizeof(PRUint32) == 4);
PR_STATIC_ASSERT(sizeof(PRUint64) == 8);
#define BLOCKSIZE 4096
#define ROUND_UP(n, incr) (((n) / (incr) + 1) * (incr))
#define MAR_ID "MAR1"
#define MAR_ID_SIZE 4
/* The signature block comes directly after the header block
which is 16 bytes */
#define SIGNATURE_BLOCK_OFFSET 16
/* We have a MAX_SIGNATURES limit so that an invalid MAR will never
waste too much of either updater's or signmar's time. */
#define MAX_SIGNATURES 8
/* Make sure the file is less than 500MB. We do this to protect against
invalid MAR files. */
#define MAX_SIZE_OF_MAR_FILE ((PRInt64)524288000)
/* Existing code makes assumptions that the file size is
smaller than LONG_MAX. */
PR_STATIC_ASSERT(MAX_SIZE_OF_MAR_FILE < ((PRInt64)LONG_MAX));
/* We store at most the size up to the signature block + 4
bytes per BLOCKSIZE bytes */
PR_STATIC_ASSERT(sizeof(BLOCKSIZE) < \
(SIGNATURE_BLOCK_OFFSET + sizeof(PRUint32)));
/* The maximum size of any signature supported by current and future
implementations of the signmar program. */
#define MAX_SIGNATURE_LENGTH 2048
#define MAR_ITEM_SIZE(namelen) (3*sizeof(PRUint32) + (namelen) + 1)
/* The mar program is compiled as a host bin so we don't have access to NSPR at
runtime. For that reason we use ntohl, htonl, and define HOST_TO_NETWORK64
instead of the NSPR equivalents. */
#ifdef XP_WIN
#include <winsock2.h>
#define ftello _ftelli64
#define fseeko _fseeki64
#else
#define _FILE_OFFSET_BITS 64
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <stdio.h>
#define HOST_TO_NETWORK64(x) ( \
((((PRUint64) x) & 0xFF) << 56) | \
((((PRUint64) x) >> 8) & 0xFF) << 48) | \
(((((PRUint64) x) >> 16) & 0xFF) << 40) | \
(((((PRUint64) x) >> 24) & 0xFF) << 32) | \
(((((PRUint64) x) >> 32) & 0xFF) << 24) | \
(((((PRUint64) x) >> 40) & 0xFF) << 16) | \
(((((PRUint64) x) >> 48) & 0xFF) << 8) | \
(((PRUint64) x) >> 56)
#define NETWORK_TO_HOST64 HOST_TO_NETWORK64
#endif /* MAR_PRIVATE_H__ */

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

@ -39,10 +39,9 @@
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mar.h"
#include "mar_private.h"
#include "mar.h"
#ifdef XP_WIN
#include <winsock2.h>
@ -50,13 +49,6 @@
#include <netinet/in.h>
#endif
#define TABLESIZE 256
struct MarFile_ {
FILE *fp;
MarItem *item_table[TABLESIZE];
};
/* this is the same hash algorithm used by nsZipArchive.cpp */
static PRUint32 mar_hash_name(const char *name) {
PRUint32 val = 0;
@ -291,3 +283,68 @@ int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf,
return fread(buf, 1, nr, mar->fp);
}
/**
* Determines if the MAR file is new or old.
*
* @param path The path of the MAR file to check.
* @param oldMar An out parameter specifying if the MAR file is new or old.
* @return A non-zero value if an error occurred and the information
cannot be determined.
*/
int is_old_mar(const char *path, int *oldMar)
{
PRUint32 offsetToIndex, offsetToContent, oldPos;
FILE *fp;
if (!oldMar) {
return -1;
}
fp = fopen(path, "rb");
if (!fp) {
return -1;
}
oldPos = ftell(fp);
/* Skip to the start of the offset index */
if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) {
return -1;
}
/* Read the offset to the index. */
if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1)
return -1;
offsetToIndex = ntohl(offsetToIndex);
/* Skip to the first index entry past the index size field
We do it in 2 calls because offsetToIndex + sizeof(PRUint32)
could oerflow in theory. */
if (fseek(fp, offsetToIndex, SEEK_SET)) {
return -1;
}
if (fseek(fp, sizeof(PRUint32), SEEK_CUR)) {
return -1;
}
/* Read the offset to content field. */
if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1)
return -1;
offsetToContent = ntohl(offsetToContent);
/* Check if we have a new or old MAR file */
if (offsetToContent == MAR_ID_SIZE + sizeof(PRUint32)) {
*oldMar = 1;
} else {
*oldMar = 0;
}
/* Restore back our old position */
if (fseek(fp, oldPos, SEEK_SET)) {
return -1;
}
return 0;
}

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

@ -51,23 +51,37 @@ endif
# The mar executable is output into dist/host/bin since it is something that
# would only be used by our build system and should not itself be included in a
# Mozilla distribution.
HOST_PROGRAM = mar$(HOST_BIN_SUFFIX)
HOST_PROGRAM = mar$(HOST_BIN_SUFFIX)
PROGRAM = signmar$(BIN_SUFFIX)
HOST_CFLAGS += -DNO_SIGN_VERIFY
HOST_CSRCS = \
mar.c \
$(NULL)
HOST_CSRCS = \
mar.c \
$(NULL)
CSRCS = $(HOST_CSRCS)
HOST_LIBS = $(DIST)/host/lib/$(LIB_PREFIX)hostmar.$(LIB_SUFFIX)
HOST_LIBS = $(DIST)/host/lib/$(LIB_PREFIX)hostmar.$(LIB_SUFFIX)
LIBS = $(DEPTH)/modules/libmar/src/$(LIB_PREFIX)mar.$(LIB_SUFFIX) \
$(DEPTH)/modules/libmar/sign/$(LIB_PREFIX)signmar.$(LIB_SUFFIX) \
$(DEPTH)/modules/libmar/verify/$(LIB_PREFIX)verifymar.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nss3.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
$(NSPR_LIBS) \
$(NULL)
ifeq ($(HOST_OS_ARCH),WINNT)
HOST_EXTRA_LIBS += $(call EXPAND_LIBNAME,ws2_32)
EXTRA_LIBS += $(call EXPAND_LIBNAME,ws2_32)
EXTRA_LIBS += $(call EXPAND_LIBNAME,crypt32)
EXTRA_LIBS += $(call EXPAND_LIBNAME,advapi32)
endif
include $(topsrcdir)/config/rules.mk
ifdef CROSS_COMPILE
ifdef HOST_NSPR_MDCPUCFG
HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG)
HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG)
CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG)
endif
endif

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

@ -37,20 +37,46 @@
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include <stdlib.h>
#include "mar.h"
#include "mar_cmdline.h"
#ifdef XP_WIN
#include <windows.h>
#include <direct.h>
#define chdir _chdir
#else
#include <unistd.h>
#endif
#if !defined(NO_SIGN_VERIFY) && (!defined(XP_WIN) || defined(MAR_NSS))
int NSSInitCryptoContext(const char *NSSConfigDir);
#endif
int mar_repackage_and_sign(const char *NSSConfigDir,
const char *certName,
const char *src,
const char * dest);
static void print_usage() {
printf("usage: mar [-C dir] {-c|-x|-t} archive.mar [files...]\n");
printf("usage:\n");
printf(" mar [-C workingDir] {-c|-x|-t} archive.mar [files...]\n");
#ifndef NO_SIGN_VERIFY
printf(" mar [-C workingDir] -d NSSConfigDir -n certname -s "
"archive.mar out_signed_archive.mar\n");
#if defined(XP_WIN) && !defined(MAR_NSS)
printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
#else
printf(" mar [-C workingDir] -d NSSConfigDir -n certname "
"-v signed_archive.mar\n");
#endif
#endif
}
static int mar_test_callback(MarFile *mar, const MarItem *item, void *unused) {
static int mar_test_callback(MarFile *mar,
const MarItem *item,
void *unused) {
printf("%u\t0%o\t%s\n", item->length, item->flags, item->name);
return 0;
}
@ -70,17 +96,59 @@ static int mar_test(const char *path) {
}
int main(int argc, char **argv) {
int command;
char *NSSConfigDir = NULL;
char *certName = NULL;
#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
HANDLE certFile;
DWORD fileSize;
DWORD read;
char *certBuffer;
char *DERFilePath = NULL;
#endif
if (argc < 3) {
print_usage();
return -1;
}
if (argv[1][1] == 'C') {
chdir(argv[2]);
argv += 2;
argc -= 2;
while (argc > 0) {
if (argv[1][0] == '-' && (argv[1][1] == 'c' ||
argv[1][1] == 't' || argv[1][1] == 'x' ||
argv[1][1] == 'v' || argv[1][1] == 's')) {
break;
/* -C workingdirectory */
} else if (argv[1][0] == '-' && argv[1][1] == 'C') {
chdir(argv[2]);
argv += 2;
argc -= 2;
}
#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
/* -D DERFilePath */
else if (argv[1][0] == '-' && argv[1][1] == 'D') {
DERFilePath = argv[2];
argv += 2;
argc -= 2;
}
#endif
/* -d NSSConfigdir */
else if (argv[1][0] == '-' && argv[1][1] == 'd') {
NSSConfigDir = argv[2];
argv += 2;
argc -= 2;
/* -n certName */
} else if (argv[1][0] == '-' && argv[1][1] == 'n') {
certName = argv[2];
argv += 2;
argc -= 2;
} else {
print_usage();
return -1;
}
}
if (argv[1][0] != '-') {
print_usage();
return -1;
}
switch (argv[1][1]) {
@ -90,6 +158,76 @@ int main(int argc, char **argv) {
return mar_test(argv[2]);
case 'x':
return mar_extract(argv[2]);
#ifndef NO_SIGN_VERIFY
case 'v':
#if defined(XP_WIN) && !defined(MAR_NSS)
if (!DERFilePath) {
print_usage();
return -1;
}
/* If the mar program was built using CryptoAPI, then read in the buffer
containing the cert from disk. */
certFile = CreateFileA(DERFilePath, GENERIC_READ,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0, NULL);
if (INVALID_HANDLE_VALUE == certFile) {
return -1;
}
fileSize = GetFileSize(certFile, NULL);
certBuffer = malloc(fileSize);
if (!ReadFile(certFile, certBuffer, fileSize, &read, NULL) ||
fileSize != read) {
CloseHandle(certFile);
free(certBuffer);
return -1;
}
CloseHandle(certFile);
if (mar_verify_signature(argv[2], certBuffer, fileSize, NULL)) {
int oldMar = 0;
free(certBuffer);
/* Determine if the source MAR file has the new fields for signing or not */
if (is_old_mar(argv[2], &oldMar)) {
fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
} else if (oldMar) {
fprintf(stderr, "ERROR: The MAR file is in the old format so has"
" no signature to verify.\n");
}
return -1;
}
free(certBuffer);
return 0;
#else
if (!NSSConfigDir || !certName) {
print_usage();
return -1;
}
if (NSSInitCryptoContext(NSSConfigDir)) {
fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
return -1;
}
return mar_verify_signature(argv[2], NULL, 0,
certName);
#endif /* defined(XP_WIN) && !defined(MAR_NSS) */
case 's':
if (!NSSConfigDir || !certName || argc < 4) {
print_usage();
return -1;
}
return mar_repackage_and_sign(NSSConfigDir, certName, argv[2], argv[3]);
#endif /* endif NO_SIGN_VERIFY disabled */
default:
print_usage();
return -1;

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

@ -0,0 +1,69 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mar verify build config.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Brian R. Bondy <netzen@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = verifymar
LIBRARY_NAME = verifymar
FORCE_STATIC_LIB = 1
ifeq ($(OS_ARCH),WINNT)
USE_STATIC_LIBS = 1
endif
# This makefile just builds support for reading archives.
CSRCS = \
mar_verify.c \
cryptox.c \
$(NULL)
LOCAL_INCLUDES += -I$(srcdir)/../src
ifneq ($(OS_ARCH),WINNT)
DEFINES += -DMAR_NSS
LOCAL_INCLUDES += -I$(srcdir)/../sign
endif
include $(topsrcdir)/config/rules.mk
# The intermediate (.ii/.s) files for host and target can have the same name...
# disable parallel builds
.NOTPARALLEL:

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

@ -0,0 +1,304 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is cryptographic wrappers for Mozilla archive code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef XP_WIN
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif
#include <stdlib.h>
#include "cryptox.h"
#if defined(MAR_NSS)
/**
* Loads the public key for the specified cert name from the NSS store.
*
* @param certName The cert name to find.
* @param publicKey Out parameter for the public key to use.
* @param cert Out parameter for the certificate to use.
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
NSS_LoadPublicKey(const char *certNickname,
SECKEYPublicKey **publicKey,
CERTCertificate **cert)
{
secuPWData pwdata = { PW_NONE, 0 };
if (!cert || !publicKey || !cert) {
return CryptoX_Error;
}
/* Get the cert and embedded public key out of the database */
*cert = PK11_FindCertFromNickname(certNickname, &pwdata);
if (!*cert) {
return CryptoX_Error;
}
*publicKey = CERT_ExtractPublicKey(*cert);
if (!*publicKey) {
CERT_DestroyCertificate(*cert);
return CryptoX_Error;
}
return CryptoX_Success;
}
CryptoX_Result
NSS_VerifyBegin(VFYContext **ctx,
SECKEYPublicKey * const *publicKey)
{
SECStatus status;
if (!ctx || !publicKey || !*publicKey) {
return CryptoX_Error;
}
/* Check that the key length is large enough for our requirements */
if ((SECKEY_PublicKeyStrength(*publicKey) * 8) <
XP_MIN_SIGNATURE_LEN_IN_BYTES) {
fprintf(stderr, "ERROR: Key length must be >= %d bytes\n",
XP_MIN_SIGNATURE_LEN_IN_BYTES);
return CryptoX_Error;
}
*ctx = VFY_CreateContext(*publicKey, NULL,
SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL);
if (*ctx == NULL) {
return CryptoX_Error;
}
status = VFY_Begin(*ctx);
return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
}
/**
* Verifies if a verify context matches the passed in signature.
*
* @param ctx The verify context that the signature should match.
* @param signature The signature to match.
* @param signatureLen The length of the signature.
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
NSS_VerifySignature(VFYContext * const *ctx,
const unsigned char *signature,
unsigned int signatureLen)
{
SECItem signedItem;
SECStatus status;
if (!ctx || !signature || !*ctx) {
return CryptoX_Error;
}
signedItem.len = signatureLen;
signedItem.data = (unsigned char*)signature;
status = VFY_EndWithSignature(*ctx, &signedItem);
return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
}
#elif defined(XP_WIN)
/**
* Verifies if a signature + public key matches a hash context.
*
* @param hash The hash context that the signature should match.
* @param pubKey The public key to use on the signature.
* @param signature The signature to check.
* @param signatureLen The length of the signature.
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
HCRYPTKEY *pubKey,
const BYTE *signature,
DWORD signatureLen)
{
DWORD i;
BOOL result;
/* Windows APIs expect the bytes in the signature to be in little-endian
* order, but we write the signature in big-endian order. Other APIs like
* NSS and OpenSSL expect big-endian order.
*/
BYTE *signatureReversed;
if (!hash || !pubKey || !signature || signatureLen < 1) {
return CryptoX_Error;
}
signatureReversed = malloc(signatureLen);
if (!signatureReversed) {
return CryptoX_Error;
}
for (i = 0; i < signatureLen; i++) {
signatureReversed[i] = signature[signatureLen - 1 - i];
}
result = CryptVerifySignature(*hash, signatureReversed,
signatureLen, *pubKey, NULL, 0);
free(signatureReversed);
return result ? CryptoX_Success : CryptoX_Error;
}
/**
* Obtains the public key for the passed in cert data
*
* @param provider The cyrto provider
* @param certData Data of the certificate to extract the public key from
* @param sizeOfCertData The size of the certData buffer
* @param certStore Pointer to the handle of the certificate store to use
* @param CryptoX_Success on success
*/
CryptoX_Result
CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
BYTE *certData,
DWORD sizeOfCertData,
HCRYPTKEY *publicKey,
HCERTSTORE *certStore)
{
CRYPT_DATA_BLOB blob;
CERT_CONTEXT *context;
if (!provider || !certData || !publicKey || !certStore) {
return CryptoX_Error;
}
blob.cbData = sizeOfCertData;
blob.pbData = certData;
if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
CERT_QUERY_CONTENT_FLAG_CERT,
CERT_QUERY_FORMAT_FLAG_BINARY,
0, NULL, NULL, NULL,
certStore, NULL, (const void **)&context)) {
return CryptoX_Error;
}
if (!CryptImportPublicKeyInfo(provider,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
&context->pCertInfo->SubjectPublicKeyInfo,
publicKey)) {
CertFreeCertificateContext(context);
return CryptoX_Error;
}
CertFreeCertificateContext(context);
return CryptoX_Success;
}
/* Try to acquire context in this way:
* 1. Enhanced provider without creating a new key set
* 2. Enhanced provider with creating a new key set
* 3. Default provider without creating a new key set
* 4. Default provider without creating a new key set
* #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT,
* but we add it just in case.
*
* @param provider Out parameter containing the provider handle.
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
CryptoAPI_InitCryptoContext(HCRYPTPROV *provider)
{
if (!CryptAcquireContext(provider,
NULL,
MS_ENHANCED_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if (!CryptAcquireContext(provider,
NULL,
MS_ENHANCED_PROV,
PROV_RSA_FULL,
CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) {
if (!CryptAcquireContext(provider,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if (!CryptAcquireContext(provider,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) {
*provider = CryptoX_InvalidHandleValue;
return CryptoX_Error;
}
}
}
}
return CryptoX_Success;
}
/**
* Begins a signature verification hash context
*
* @param provider The crypt provider to use
* @param hash Out parameter for a handle to the hash context
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash)
{
BOOL result;
if (!provider || !hash) {
return CryptoX_Error;
}
*hash = (HCRYPTHASH)NULL;
result = CryptCreateHash(provider, CALG_SHA1,
0, 0, hash);
return result ? CryptoX_Success : CryptoX_Error;
}
/**
* Updates a signature verification hash context
*
* @param hash The hash context to udpate
* @param buf The buffer to update the hash context with
* @param len The size of the passed in buffer
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, BYTE *buf, DWORD len)
{
BOOL result;
if (!hash || !buf) {
return CryptoX_Error;
}
result = CryptHashData(*hash, buf, len, 0);
return result ? CryptoX_Success : CryptoX_Error;
}
#endif

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

@ -0,0 +1,150 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is cryptographic wrappers for Mozilla archive code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef CRYPTOX_H
#define CRYPTOX_H
#define XP_MIN_SIGNATURE_LEN_IN_BYTES 256
#define CryptoX_Result int
#define CryptoX_Success 0
#define CryptoX_Error (-1)
#define CryptoX_Succeeded(X) ((X) == CryptoX_Success)
#define CryptoX_Failed(X) ((X) != CryptoX_Success)
#if defined(MAR_NSS)
#include "nss_secutil.h"
CryptoX_Result NSS_LoadPublicKey(const char *certNickname,
SECKEYPublicKey **publicKey,
CERTCertificate **cert);
CryptoX_Result NSS_VerifyBegin(VFYContext **ctx,
SECKEYPublicKey * const *publicKey);
CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
const unsigned char *signature,
unsigned int signatureLen);
#define CryptoX_InvalidHandleValue NULL
#define CryptoX_ProviderHandle void*
#define CryptoX_SignatureHandle VFYContext *
#define CryptoX_PublicKey SECKEYPublicKey *
#define CryptoX_Certificate CERTCertificate *
#define CryptoX_InitCryptoProvider(CryptoHandle) \
CryptoX_Success
#define CryptoX_VerifyBegin(CryptoHandle, SignatureHandle, PublicKey) \
NSS_VerifyBegin(SignatureHandle, PublicKey)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
VFY_Update(*SignatureHandle, (const unsigned char*)(buf), len)
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
publicKey, certName, cert) \
NSS_LoadPublicKey(certName, publicKey, cert)
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
NSS_VerifySignature(hash, (const unsigned char *)(signedData), len)
#define CryptoX_FreePublicKey(key) \
SECKEY_DestroyPublicKey(*key)
#define CryptoX_FreeCertificate(cert) \
CERT_DestroyCertificate(*cert)
#elif defined(XP_WIN)
#include <windows.h>
#include <wincrypt.h>
CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV *provider);
CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV hProv,
BYTE *certData,
DWORD sizeOfCertData,
HCRYPTKEY *publicKey,
HCERTSTORE *cert);
CryptoX_Result CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash);
CryptoX_Result CryptoAPI_VerifyUpdate(HCRYPTHASH* hash,
BYTE *buf, DWORD len);
CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
HCRYPTKEY *pubKey,
const BYTE *signature,
DWORD signatureLen);
#define CryptoX_InvalidHandleValue ((ULONG_PTR)NULL)
#define CryptoX_ProviderHandle HCRYPTPROV
#define CryptoX_SignatureHandle HCRYPTHASH
#define CryptoX_PublicKey HCRYPTKEY
#define CryptoX_Certificate HCERTSTORE
#define CryptoX_InitCryptoProvider(CryptoHandle) \
CryptoAPI_InitCryptoContext(CryptoHandle)
#define CryptoX_VerifyBegin(CryptoHandle, SignatureHandle, PublicKey) \
CryptoAPI_VerifyBegin(CryptoHandle, SignatureHandle)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
CryptoAPI_VerifyUpdate(SignatureHandle, (BYTE *)(buf), len)
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
publicKey, certName, cert) \
CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), \
dataSize, publicKey, cert)
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
CyprtoAPI_VerifySignature(hash, publicKey, signedData, len)
#define CryptoX_FreePublicKey(key) \
CryptDestroyKey(*(key))
#define CryptoX_FreeCertificate(cert) \
CertCloseStore(*(cert), CERT_CLOSE_STORE_FORCE_FLAG);
#else
/* This default implementation is necessary because we don't want to
* link to NSS from updater code on non Windows platforms. On Windows
* we use CyrptoAPI instead of NSS. We don't call any function as they
* would just fail, but this simplifies linking.
*/
#define CryptoX_InvalidHandleValue NULL
#define CryptoX_ProviderHandle void*
#define CryptoX_SignatureHandle void*
#define CryptoX_PublicKey void*
#define CryptoX_Certificate void*
#define CryptoX_InitCryptoProvider(CryptoHandle) \
CryptoX_Error
#define CryptoX_VerifyBegin(CryptoHandle, SignatureHandle, PublicKey) \
CryptoX_Error
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) CryptoX_Error
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
publicKey, certName, cert) \
CryptoX_Error
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) CryptoX_Error
#define CryptoX_FreePublicKey(key) CryptoX_Error
#endif
#endif

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

@ -0,0 +1,445 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Archive verify code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef XP_WIN
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include "mar_private.h"
#include "mar.h"
#include "cryptox.h"
int mar_verify_signature_fp(FILE *fp,
CryptoX_ProviderHandle provider,
CryptoX_PublicKey key);
int mar_verify_signature_for_fp(FILE *fp,
CryptoX_ProviderHandle provider,
CryptoX_PublicKey key,
PRUint32 signatureCount,
char *extractedSignature);
/**
* Reads the specified number of bytes from the file pointer and
* stores them in the passed 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 ctx The verify context.
* @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
*/
int
ReadAndUpdateVerifyContext(FILE *fp,
void *buffer,
PRUint32 size,
CryptoX_SignatureHandle *ctx,
const char *err)
{
if (!fp || !buffer || !ctx || !err) {
fprintf(stderr, "ERROR: Invalid parameter specified.\n");
return CryptoX_Error;
}
if (!size) {
return CryptoX_Success;
}
if (fread(buffer, size, 1, fp) != 1) {
fprintf(stderr, "ERROR: Could not read %s\n", err);
return CryptoX_Error;
}
if (CryptoX_Failed(CryptoX_VerifyUpdate(ctx, buffer, size))) {
fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
return -2;
}
return CryptoX_Success;
}
/**
* Verifies the embedded signature of the specified file path.
* This is only used by the signmar program when used with arguments to verify
* a MAR. This should not be used to verify a MAR that will be extracted in the
* same operation by updater code. This function prints the error message if
* verification fails.
*
* @param pathToMAR The path of the MAR file who's signature should be checked
* @param certData The certificate file data.
* @param sizeOfCertData The size of the cert data.
* @param certName Used only if compiled as NSS, specifies the certName
* @return 0 on success
* a negative number if there was an error
* a positive number if the signature does not verify
*/
int
mar_verify_signature(const char *pathToMARFile,
const char *certData,
PRUint32 sizeOfCertData,
const char *certName) {
int rv;
CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
CryptoX_Certificate cert;
CryptoX_PublicKey key;
FILE *fp;
if (!pathToMARFile || (!certData && !certName)) {
fprintf(stderr, "ERROR: Invalid parameter specified.\n");
return CryptoX_Error;
}
fp = fopen(pathToMARFile, "rb");
if (!fp) {
fclose(fp);
fprintf(stderr, "ERROR: Could not open MAR file.\n");
return CryptoX_Error;
}
if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
fclose(fp);
fprintf(stderr, "ERROR: Could not init crytpo library.\n");
return CryptoX_Error;
}
if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData, sizeOfCertData,
&key, certName, &cert))) {
fclose(fp);
fprintf(stderr, "ERROR: Could not load public key.\n");
return CryptoX_Error;
}
rv = mar_verify_signature_fp(fp, provider, key);
fclose(fp);
if (key) {
CryptoX_FreePublicKey(&key);
}
if (cert) {
CryptoX_FreeCertificate(&cert);
}
return rv;
}
#ifdef XP_WIN
/**
* Verifies a MAR file's signature by making sure at least one
* signature verifies.
*
* @param pathToMARFile The path of the MAR file who's signature
* should be calculated
* @param certData The certificate data
* @param sizeOfCertData The size of the data stored in certData
* @return 0 on success
*/
int
mar_verify_signatureW(MarFile *mar,
const char *certData,
PRUint32 sizeOfCertData) {
int rv;
CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
CryptoX_Certificate cert;
CryptoX_PublicKey key;
if (!mar || !certData) {
fprintf(stderr, "ERROR: Invalid parameter specified.\n");
return CryptoX_Error;
}
if (!mar->fp) {
fprintf(stderr, "ERROR: MAR file is not open.\n");
return CryptoX_Error;
}
if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
fprintf(stderr, "ERROR: Could not init crytpo library.\n");
return CryptoX_Error;
}
if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData, sizeOfCertData,
&key, "", &cert))) {
fprintf(stderr, "ERROR: Could not load public key.\n");
return CryptoX_Error;
}
rv = mar_verify_signature_fp(mar->fp, provider, key);
if (key) {
CryptoX_FreePublicKey(&key);
}
if (cert) {
CryptoX_FreeCertificate(&cert);
}
return rv;
}
#endif
/**
* Verifies a MAR file's signature by making sure at least one
* signature verifies.
*
* @param fp An opened MAR file handle
* @param provider A library provider
* @param key The public key to use to verify the MAR
* @return 0 on success
*/
int
mar_verify_signature_fp(FILE *fp,
CryptoX_ProviderHandle provider,
CryptoX_PublicKey key) {
char buf[5] = {0};
PRUint32 signatureAlgorithmID, signatureCount, signatureLen, numVerified = 0;
int rv = -1;
PRInt64 curPos;
char *extractedSignature;
PRUint32 i;
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 (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 (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
fprintf(stderr, "ERROR: Could not read number of signatures.\n");
return CryptoX_Error;
}
signatureCount = ntohl(signatureCount);
/* Check that we have less than the max amount of signatures so we don't
waste too much of either updater's or signmar's time. */
if (signatureCount > MAX_SIGNATURES) {
fprintf(stderr, "ERROR: At most %d signatures can be specified.\n",
MAX_SIGNATURES);
return CryptoX_Error;
}
for (i = 0; i < signatureCount && numVerified == 0; i++) {
/* Get the signature algorithm ID */
if (fread(&signatureAlgorithmID, sizeof(PRUint32), 1, fp) != 1) {
fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
return CryptoX_Error;
}
signatureAlgorithmID = ntohl(signatureAlgorithmID);
if (fread(&signatureLen, sizeof(PRUint32), 1, fp) != 1) {
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
isn't too big. */
if (signatureLen > MAX_SIGNATURE_LENGTH) {
fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
return CryptoX_Error;
}
extractedSignature = malloc(signatureLen);
if (!extractedSignature) {
fprintf(stderr, "ERROR: Could allocate buffer for signature.\n");
return CryptoX_Error;
}
if (fread(extractedSignature, signatureLen, 1, fp) != 1) {
fprintf(stderr, "ERROR: Could not read extracted signature.\n");
free(extractedSignature);
return CryptoX_Error;
}
/* We don't try to verify signatures we don't know about */
if (1 == signatureAlgorithmID) {
curPos = ftello(fp);
rv = mar_verify_signature_for_fp(fp,
provider,
key,
signatureCount,
extractedSignature);
if (CryptoX_Succeeded(rv)) {
numVerified++;
}
free(extractedSignature);
if (fseeko(fp, curPos, SEEK_SET)) {
fprintf(stderr, "ERROR: Could not seek back to last signature.\n");
return CryptoX_Error;
}
} else {
free(extractedSignature);
}
}
/* If we reached here and we verified at least one
signature, return success. */
if (numVerified > 0) {
return CryptoX_Success;
} else {
fprintf(stderr, "ERROR: No signatures were verified.\n");
return CryptoX_Error;
}
}
/**
* Verifies if a specific signature ID matches the extracted signature.
*
* @param fp An opened MAR file handle
* @param provider A library provider
* @param key The public key to use to verify the MAR
* @param signatureCount The number of signatures in the MAR file
* @param extractedSignature The signature that should be verified
* @return 0 on success
*/
int
mar_verify_signature_for_fp(FILE *fp,
CryptoX_ProviderHandle provider,
CryptoX_PublicKey key,
PRUint32 signatureCount,
char *extractedSignature) {
CryptoX_SignatureHandle signatureHandle;
char buf[BLOCKSIZE];
PRUint32 signatureLen;
PRUint32 i;
if (!extractedSignature) {
fprintf(stderr, "ERROR: Invalid parameter specified.\n");
return CryptoX_Error;
}
/* This function is only called when we have at least one signature,
but to protected against future people who call this function we
make sure a non zero value is passed in.
*/
if (!signatureCount) {
fprintf(stderr, "ERROR: There must be at least one signature.\n");
return CryptoX_Error;
}
CryptoX_VerifyBegin(provider, &signatureHandle, &key);
/* 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");
return CryptoX_Error;
}
/* 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(PRUint32),
&signatureHandle,
"signature block"))) {
return CryptoX_Error;
}
for (i = 0; i < signatureCount; i++) {
/* Get the signature algorithm ID */
if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
&buf,
sizeof(PRUint32),
&signatureHandle,
"signature algorithm ID"))) {
return CryptoX_Error;
}
if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
&signatureLen,
sizeof(PRUint32),
&signatureHandle,
"signature length"))) {
return CryptoX_Error;
}
signatureLen = ntohl(signatureLen);
/* Skip past the signature itself as those are not included */
if (fseeko(fp, signatureLen, SEEK_CUR)) {
fprintf(stderr, "ERROR: Could not seek past signature.\n");
return CryptoX_Error;
}
}
while (!feof(fp)) {
int numRead = fread(buf, 1, BLOCKSIZE , fp);
if (ferror(fp)) {
fprintf(stderr, "ERROR: Error reading data block.\n");
return CryptoX_Error;
}
if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandle,
buf, numRead))) {
fprintf(stderr, "ERROR: Error updating verify context with"
" data block.\n");
return CryptoX_Error;
}
}
if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandle,
&key,
extractedSignature,
signatureLen))) {
fprintf(stderr, "ERROR: Error verifying signature.\n");
return CryptoX_Error;
}
return CryptoX_Success;
}

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

@ -66,6 +66,7 @@ LIBS += \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
LIBS += $(DEPTH)/modules/libmar/verify/$(LIB_PREFIX)verifymar.$(LIB_SUFFIX)
USE_STATIC_LIBS = 1
HAVE_PROGRESSUI = 1
RCINCLUDE = updater.rc
@ -139,4 +140,9 @@ ifeq (,$(filter-out WINNT,$(OS_ARCH)))
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
endif
ifeq ($(OS_ARCH),WINNT)
EXTRA_LIBS += $(call EXPAND_LIBNAME,crypt32)
EXTRA_LIBS += $(call EXPAND_LIBNAME,advapi32)
endif
CXXFLAGS += $(BZ2_CFLAGS)

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

@ -80,7 +80,6 @@ ifdef MOZ_UPDATER
ifndef MOZ_NATIVE_BZ2
tier_platform_dirs += modules/libbz2
endif
tier_platform_dirs += modules/libmar
tier_platform_dirs += other-licenses/bsdiff
endif
@ -212,14 +211,18 @@ ifdef MOZ_SPELLCHECK
tier_platform_dirs += extensions/spellcheck
endif
tier_platform_dirs += toolkit
ifdef MOZ_PSM
tier_platform_dirs += security/manager
else
tier_platform_dirs += security/manager/boot/public security/manager/ssl/public
endif
ifdef MOZ_UPDATER
tier_platform_dirs += modules/libmar
endif
tier_platform_dirs += toolkit
ifdef MOZ_PREF_EXTENSIONS
tier_platform_dirs += extensions/pref
endif