summaryrefslogtreecommitdiffstats
path: root/onlineupdate/source/libmar/sign
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /onlineupdate/source/libmar/sign
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'onlineupdate/source/libmar/sign')
-rw-r--r--onlineupdate/source/libmar/sign/Makefile.in10
-rw-r--r--onlineupdate/source/libmar/sign/mar_sign.c1160
-rw-r--r--onlineupdate/source/libmar/sign/nss_secutil.c238
-rw-r--r--onlineupdate/source/libmar/sign/nss_secutil.h43
4 files changed, 1451 insertions, 0 deletions
diff --git a/onlineupdate/source/libmar/sign/Makefile.in b/onlineupdate/source/libmar/sign/Makefile.in
new file mode 100644
index 000000000..c5eaeb444
--- /dev/null
+++ b/onlineupdate/source/libmar/sign/Makefile.in
@@ -0,0 +1,10 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# This makefile just builds support for reading archives.
+include $(topsrcdir)/config/rules.mk
+
+# The intermediate (.ii/.s) files for host and target can have the same name...
+# disable parallel builds
+.NOTPARALLEL:
diff --git a/onlineupdate/source/libmar/sign/mar_sign.c b/onlineupdate/source/libmar/sign/mar_sign.c
new file mode 100644
index 000000000..161cadc0d
--- /dev/null
+++ b/onlineupdate/source/libmar/sign/mar_sign.c
@@ -0,0 +1,1160 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef _WIN32
+#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 <onlineupdate/mar_private.h>
+#include <onlineupdate/mar_cmdline.h>
+#include <onlineupdate/mar.h>
+#include "cryptox.h"
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include "nss_secutil.h"
+#include "base64.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,
+ uint32_t *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 contexts.
+ *
+ * @param fpDest The file pointer to write to.
+ * @param buffer The buffer to write.
+ * @param size The size of the buffer to write.
+ * @param ctxs Pointer to the first element in an array of signature
+ * contexts to update.
+ * @param ctxCount The number of signature contexts pointed to by ctxs
+ * @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
+WriteAndUpdateSignatures(FILE *fpDest, void *buffer,
+ uint32_t size, SGNContext **ctxs,
+ uint32_t ctxCount,
+ const char *err)
+{
+ uint32_t k;
+ if (!size) {
+ return 0;
+ }
+
+ if (fwrite(buffer, size, 1, fpDest) != 1) {
+ fprintf(stderr, "ERROR: Could not write %s\n", err);
+ return -2;
+ }
+
+ for (k = 0; k < ctxCount; ++k) {
+ if (SGN_Update(ctxs[k], buffer, size) != SECSuccess) {
+ fprintf(stderr, "ERROR: Could not update signature context for %s\n", err);
+ return -3;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Adjusts each entry's content offset in 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, uint32_t indexLength, uint32_t offsetAmount)
+{
+ char *indexBufLoc = indexBuf;
+
+ /* Consume the index and adjust each index by the specified amount */
+ while (indexBufLoc != (indexBuf + indexLength)) {
+ /* Adjust the offset */
+ uint32_t* offsetToContent = (uint32_t *)indexBufLoc;
+ *offsetToContent = ntohl(*offsetToContent);
+ *offsetToContent += offsetAmount;
+ *offsetToContent = htonl(*offsetToContent);
+ /* Skip past the offset, length, and flags */
+ indexBufLoc += 3 * sizeof(uint32_t);
+ indexBufLoc += strlen(indexBufLoc) + 1;
+ }
+}
+
+/**
+ * Reads from fpSrc, writes it to fpDest, and updates the signature contexts.
+ *
+ * @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 ctxs Pointer to the first element in an array of signature
+ * contexts to update.
+ * @param ctxCount The number of signature contexts pointed to by ctxs
+ * @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
+ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer,
+ uint32_t size, SGNContext **ctxs,
+ uint32_t ctxCount,
+ 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 WriteAndUpdateSignatures(fpDest, buffer, size, ctxs, ctxCount, err);
+}
+
+
+/**
+ * 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,
+ uint32_t 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)
+{
+ uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
+ numSignatures = 0, leftOver;
+ int32_t stripAmount = 0;
+ int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR, numBytesToCopy,
+ numChunks, i;
+ FILE *fpSrc = NULL, *fpDest = NULL;
+ int rv = -1, hasSignatureBlock;
+ char buf[BLOCKSIZE];
+ char *indexBuf = NULL;
+
+ 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", src);
+ 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++) {
+ uint32_t signatureLen;
+
+ /* Skip past the signature algorithm ID */
+ if (fseeko(fpSrc, sizeof(uint32_t), 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(uint32_t), 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(uint32_t) + sizeof(uint32_t) + signatureLen;
+ }
+
+ } else {
+ sizeOfEntireMAR = realSizeOfSrcMAR;
+ numSignatures = 0;
+ }
+
+ if (((int64_t)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) > ((int64_t)offsetToIndex)) {
+ fprintf(stderr, "ERROR: Index offset is too small.\n");
+ goto failure;
+ }
+ numBytesToCopy = ((int64_t)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);
+ 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;
+}
+
+/**
+ * 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 = 0;
+ 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++) {
+ /* Avoid leaking while skipping signatures */
+ free(extractedSignature);
+
+ /* 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;
+}
+
+/**
+ * Imports a base64 encoded signature into a MAR file
+ *
+ * @param src The path of the source MAR file
+ * @param sigIndex The index of the signature to import
+ * @param base64SigFile A file which contains the signature to import
+ * @param dest The path of the destination MAR file with replaced signature
+ * @return 0 on success
+ * -1 on error
+*/
+int
+import_signature(const char *src, uint32_t sigIndex,
+ const char *base64SigFile, const char *dest)
+{
+ int rv = -1;
+ FILE *fpSrc = NULL;
+ FILE *fpDest = NULL;
+ FILE *fpSigFile = NULL;
+ uint32_t i;
+ uint32_t signatureCount, signatureLen, signatureAlgorithmID,
+ numChunks, leftOver;
+ char buf[BLOCKSIZE];
+ uint64_t sizeOfSrcMAR, sizeOfBase64EncodedFile;
+ char *passedInSignatureB64 = NULL;
+ uint8_t *passedInSignatureRaw = NULL;
+ uint8_t *extractedMARSignature = NULL;
+ unsigned int passedInSignatureLenRaw;
+
+ 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 open dest file: %s\n", dest);
+ goto failure;
+ }
+
+ fpSigFile = fopen(base64SigFile , "rb");
+ if (!fpSigFile) {
+ fprintf(stderr, "ERROR: could not open sig file: %s\n", base64SigFile);
+ goto failure;
+ }
+
+ /* Get the src file size */
+ if (fseeko(fpSrc, 0, SEEK_END)) {
+ fprintf(stderr, "ERROR: Could not seek to end of src file.\n");
+ goto failure;
+ }
+ sizeOfSrcMAR = ftello(fpSrc);
+ if (fseeko(fpSrc, 0, SEEK_SET)) {
+ fprintf(stderr, "ERROR: Could not seek to start of src file.\n");
+ goto failure;
+ }
+
+ /* Get the sig file size */
+ if (fseeko(fpSigFile, 0, SEEK_END)) {
+ fprintf(stderr, "ERROR: Could not seek to end of sig file.\n");
+ goto failure;
+ }
+ sizeOfBase64EncodedFile= ftello(fpSigFile);
+ if (fseeko(fpSigFile, 0, SEEK_SET)) {
+ fprintf(stderr, "ERROR: Could not seek to start of sig file.\n");
+ goto failure;
+ }
+
+ /* Read in the base64 encoded signature to import */
+ passedInSignatureB64 = malloc(sizeOfBase64EncodedFile + 1);
+ passedInSignatureB64[sizeOfBase64EncodedFile] = '\0';
+ if (fread(passedInSignatureB64, sizeOfBase64EncodedFile, 1, fpSigFile) != 1) {
+ fprintf(stderr, "ERROR: Could read b64 sig file.\n");
+ goto failure;
+ }
+
+ /* Decode the base64 encoded data */
+ passedInSignatureRaw = ATOB_AsciiToData(passedInSignatureB64, &passedInSignatureLenRaw);
+ if (!passedInSignatureRaw) {
+ fprintf(stderr, "ERROR: could not obtain base64 decoded data\n");
+ goto failure;
+ }
+
+ /* Read everything up until the signature block offset and write it out */
+ if (ReadAndWrite(fpSrc, fpDest, buf,
+ SIGNATURE_BLOCK_OFFSET, "signature block offset")) {
+ goto failure;
+ }
+
+ /* Get the number of signatures */
+ if (ReadAndWrite(fpSrc, fpDest, &signatureCount,
+ sizeof(signatureCount), "signature count")) {
+ goto failure;
+ }
+ signatureCount = ntohl(signatureCount);
+ if (signatureCount > MAX_SIGNATURES) {
+ fprintf(stderr, "ERROR: Signature count was out of range\n");
+ goto failure;
+ }
+
+ if (sigIndex >= signatureCount) {
+ fprintf(stderr, "ERROR: Signature index was out of range\n");
+ goto failure;
+ }
+
+ /* Read and write the whole signature block, but if we reach the
+ signature offset, then we should replace it with the specified
+ base64 decoded signature */
+ for (i = 0; i < signatureCount; i++) {
+ /* Read/Write the signature algorithm ID */
+ if (ReadAndWrite(fpSrc, fpDest,
+ &signatureAlgorithmID,
+ sizeof(signatureAlgorithmID), "sig algorithm ID")) {
+ goto failure;
+ }
+
+ /* Read/Write the signature length */
+ if (ReadAndWrite(fpSrc, fpDest,
+ &signatureLen, sizeof(signatureLen), "sig length")) {
+ goto failure;
+ }
+ signatureLen = ntohl(signatureLen);
+
+ /* Get the signature */
+ if (extractedMARSignature) {
+ free(extractedMARSignature);
+ }
+ extractedMARSignature = malloc(signatureLen);
+
+ if (sigIndex == i) {
+ if (passedInSignatureLenRaw != signatureLen) {
+ fprintf(stderr, "ERROR: Signature length must be the same\n");
+ goto failure;
+ }
+
+ if (fread(extractedMARSignature, signatureLen, 1, fpSrc) != 1) {
+ fprintf(stderr, "ERROR: Could not read signature\n");
+ goto failure;
+ }
+
+ if (fwrite(passedInSignatureRaw, passedInSignatureLenRaw,
+ 1, fpDest) != 1) {
+ fprintf(stderr, "ERROR: Could not write signature\n");
+ goto failure;
+ }
+ } else {
+ if (ReadAndWrite(fpSrc, fpDest,
+ extractedMARSignature, signatureLen, "signature")) {
+ goto failure;
+ }
+ }
+ }
+
+ /* We replaced the signature so let's just skip past the rest o the
+ file. */
+ numChunks = (sizeOfSrcMAR - ftello(fpSrc)) / BLOCKSIZE;
+ leftOver = (sizeOfSrcMAR - ftello(fpSrc)) % 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;
+ }
+ }
+
+ if (ReadAndWrite(fpSrc, fpDest, buf, leftOver, "left over content block")) {
+ goto failure;
+ }
+
+ rv = 0;
+
+failure:
+
+ if (fpSrc) {
+ fclose(fpSrc);
+ }
+
+ if (fpDest) {
+ fclose(fpDest);
+ }
+
+ if (fpSigFile) {
+ fclose(fpSigFile);
+ }
+
+ if (rv) {
+ remove(dest);
+ }
+
+ if (extractedMARSignature) {
+ free(extractedMARSignature);
+ }
+
+ if (passedInSignatureB64) {
+ free(passedInSignatureB64);
+ }
+
+ if (passedInSignatureRaw) {
+ PORT_Free(passedInSignatureRaw);
+ }
+
+ 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
+ * be returned.
+ *
+ * @param NSSConfigDir The NSS directory containing the private key for signing
+ * @param certNames The nicknames of the certificate to use for signing
+ * @param certCount The number of certificate names contained in certNames.
+ * One signature will be produced for each certificate.
+ * @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 * const *certNames,
+ uint32_t certCount,
+ const char *src,
+ const char *dest)
+{
+ uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
+ numSignatures = 0, leftOver,
+ signatureAlgorithmID, signatureSectionLength = 0;
+ uint32_t signatureLengths[MAX_SIGNATURES];
+ int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR,
+ signaturePlaceholderOffset, numBytesToCopy,
+ numChunks, i;
+ FILE *fpSrc = NULL, *fpDest = NULL;
+ int rv = -1, hasSignatureBlock;
+ SGNContext *ctxs[MAX_SIGNATURES];
+ SECItem secItems[MAX_SIGNATURES];
+ char buf[BLOCKSIZE];
+ SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
+ CERTCertificate *certs[MAX_SIGNATURES];
+ char *indexBuf = NULL;
+ uint32_t k;
+
+ memset(signatureLengths, 0, sizeof(signatureLengths));
+ memset(ctxs, 0, sizeof(ctxs));
+ memset(secItems, 0, sizeof(secItems));
+ memset(privKeys, 0, sizeof(privKeys));
+ memset(certs, 0, sizeof(certs));
+
+ if (!NSSConfigDir || !certNames || certCount == 0 || !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);
+
+ 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;
+ }
+
+ /* 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;
+ }
+
+ for (k = 0; k < certCount; k++) {
+ if (NSSSignBegin(certNames[k], &ctxs[k], &privKeys[k],
+ &certs[k], &signatureLengths[k])) {
+ fprintf(stderr, "ERROR: NSSSignBegin failed\n");
+ goto failure;
+ }
+ }
+
+ /* MAR ID */
+ if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
+ buf, MAR_ID_SIZE,
+ ctxs, certCount, "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 */
+ 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 you have multiple signatures,
+ you must add them all at the same time. */
+ if (numSignatures) {
+ fprintf(stderr, "ERROR: MAR is already signed\n");
+ goto failure;
+ }
+ } else {
+ sizeOfEntireMAR = realSizeOfSrcMAR;
+ }
+
+ if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
+ fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
+ goto failure;
+ }
+
+ /* Calculate the total signature block length */
+ for (k = 0; k < certCount; k++) {
+ signatureSectionLength += sizeof(signatureAlgorithmID) +
+ sizeof(signatureLengths[k]) +
+ signatureLengths[k];
+ }
+ dstOffsetToIndex = offsetToIndex;
+ if (!hasSignatureBlock) {
+ dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
+ }
+ dstOffsetToIndex += signatureSectionLength;
+
+ /* Write out the index offset */
+ dstOffsetToIndex = htonl(dstOffsetToIndex);
+ if (WriteAndUpdateSignatures(fpDest, &dstOffsetToIndex,
+ sizeof(dstOffsetToIndex), ctxs, certCount,
+ "index offset")) {
+ goto failure;
+ }
+ dstOffsetToIndex = ntohl(dstOffsetToIndex);
+
+ /* Write out the new MAR file size */
+ sizeOfEntireMAR += signatureSectionLength;
+ if (!hasSignatureBlock) {
+ sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
+ }
+
+ /* Write out the MAR size */
+ sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
+ if (WriteAndUpdateSignatures(fpDest, &sizeOfEntireMAR,
+ sizeof(sizeOfEntireMAR), ctxs, certCount,
+ "size of MAR")) {
+ goto failure;
+ }
+ sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
+
+ /* Write out the number of signatures */
+ numSignatures = certCount;
+ numSignatures = htonl(numSignatures);
+ if (WriteAndUpdateSignatures(fpDest, &numSignatures,
+ sizeof(numSignatures), ctxs, certCount,
+ "num signatures")) {
+ goto failure;
+ }
+ numSignatures = ntohl(numSignatures);
+
+ signaturePlaceholderOffset = ftello(fpDest);
+
+ for (k = 0; k < certCount; k++) {
+ /* Write out the signature algorithm ID, Only an ID of 1 is supported */
+ signatureAlgorithmID = htonl(1);
+ if (WriteAndUpdateSignatures(fpDest, &signatureAlgorithmID,
+ sizeof(signatureAlgorithmID),
+ ctxs, certCount, "num signatures")) {
+ goto failure;
+ }
+ signatureAlgorithmID = ntohl(signatureAlgorithmID);
+
+ /* Write out the signature length */
+ signatureLengths[k] = htonl(signatureLengths[k]);
+ if (WriteAndUpdateSignatures(fpDest, &signatureLengths[k],
+ sizeof(signatureLengths[k]),
+ ctxs, certCount, "signature length")) {
+ goto failure;
+ }
+ signatureLengths[k] = ntohl(signatureLengths[k]);
+
+ /* 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));
+ if (fwrite(buf, signatureLengths[k], 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) > ((int64_t)offsetToIndex)) {
+ fprintf(stderr, "ERROR: Index offset is too small.\n");
+ goto failure;
+ }
+ numBytesToCopy = ((int64_t)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 (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
+ BLOCKSIZE, ctxs, certCount,
+ "content block")) {
+ goto failure;
+ }
+ }
+
+ /* Write out the left over */
+ if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
+ leftOver, ctxs, certCount,
+ "left over content block")) {
+ goto failure;
+ }
+
+ /* Length of the index */
+ if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
+ sizeof(indexLength), ctxs, certCount,
+ "index length")) {
+ goto failure;
+ }
+ indexLength = ntohl(indexLength);
+
+ /* Consume the index and adjust each index by signatureSectionLength */
+ indexBuf = malloc(indexLength);
+ 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, signatureSectionLength);
+ } else {
+ AdjustIndexContentOffsets(indexBuf, indexLength,
+ sizeof(sizeOfEntireMAR) +
+ sizeof(numSignatures) +
+ signatureSectionLength);
+ }
+
+ if (WriteAndUpdateSignatures(fpDest, indexBuf,
+ indexLength, ctxs, certCount, "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;
+ }
+
+ for (k = 0; k < certCount; k++) {
+ /* Get the signature */
+ if (SGN_End(ctxs[k], &secItems[k]) != SECSuccess) {
+ fprintf(stderr, "ERROR: Could not end signature context\n");
+ goto failure;
+ }
+ if (signatureLengths[k] != secItems[k].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;
+ }
+
+ for (k = 0; k < certCount; k++) {
+ /* Skip to the position of the next signature */
+ if (fseeko(fpDest, sizeof(signatureAlgorithmID) +
+ sizeof(signatureLengths[k]), SEEK_CUR)) {
+ 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(secItems[k].data, secItems[k].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);
+ }
+
+ /* Cleanup */
+ for (k = 0; k < certCount; k++) {
+ if (ctxs[k]) {
+ SGN_DestroyContext(ctxs[k], PR_TRUE);
+ }
+
+ if (certs[k]) {
+ CERT_DestroyCertificate(certs[k]);
+ }
+
+ if (privKeys[k]) {
+ SECKEY_DestroyPrivateKey(privKeys[k]);
+ }
+
+ SECITEM_FreeItem(&secItems[k], PR_FALSE);
+ }
+
+ if (rv) {
+ remove(dest);
+ }
+
+ return rv;
+}
diff --git a/onlineupdate/source/libmar/sign/nss_secutil.c b/onlineupdate/source/libmar/sign/nss_secutil.c
new file mode 100644
index 000000000..875c14309
--- /dev/null
+++ b/onlineupdate/source/libmar/sign/nss_secutil.c
@@ -0,0 +1,238 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* 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 _WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+static char consoleName[] = {
+#ifdef UNIX
+ "/dev/tty"
+#else
+ "CON:"
+#endif
+};
+
+#if defined(_WINDOWS)
+static char * quiet_fgets (char *buf, int length, FILE *input)
+{
+ char *end = buf;
+
+ /* fflush (input); */
+ memset (buf, 0, length);
+
+ if (!isatty(fileno(input))) {
+ return fgets(buf,length,input);
+ }
+
+ while (1)
+ {
+ int c;
+#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));
+
+ (void) arg; (void) prompt; // avoid warnings
+
+#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;
+ int32_t 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 + 1);
+
+ 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 (i < nb && phrases[i] != '\r' && phrases[i] != '\n') 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 = 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));
+ pw = GetPasswordString(NULL, prompt);
+ if (pw) {
+ memset(pw, 0, PORT_Strlen(pw));
+ PORT_Free(pw);
+ }
+ /* Fall Through */
+ case PW_PLAINTEXT:
+ return strdup(pwdata->data);
+ default:
+ break;
+ }
+
+ PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
+ return NULL;
+}
diff --git a/onlineupdate/source/libmar/sign/nss_secutil.h b/onlineupdate/source/libmar/sign/nss_secutil.h
new file mode 100644
index 000000000..f599fcce5
--- /dev/null
+++ b/onlineupdate/source/libmar/sign/nss_secutil.h
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* 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"
+#include <stdint.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