summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/signver/signver.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/signver/signver.c')
-rw-r--r--security/nss/cmd/signver/signver.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/security/nss/cmd/signver/signver.c b/security/nss/cmd/signver/signver.c
new file mode 100644
index 000000000..4e89e9d0e
--- /dev/null
+++ b/security/nss/cmd/signver/signver.c
@@ -0,0 +1,315 @@
+/* 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/. */
+
+#include "secutil.h"
+#include "secmod.h"
+#include "cert.h"
+#include "secoid.h"
+#include "nss.h"
+
+/* NSPR 2.0 header files */
+#include "prinit.h"
+#include "prprf.h"
+#include "prsystem.h"
+#include "prmem.h"
+/* Portable layer header files */
+#include "plstr.h"
+#include "sechash.h" /* for HASH_GetHashObject() */
+
+static PRBool debugInfo;
+static PRBool verbose;
+static PRBool doVerify;
+static PRBool displayAll;
+
+static const char *const usageInfo[] = {
+ "signver - verify a detached PKCS7 signature - Version " NSS_VERSION,
+ "Commands:",
+ " -A display all information from pkcs #7",
+ " -V verify the signed object and display result",
+ "Options:",
+ " -a signature file is ASCII",
+ " -d certdir directory containing cert database",
+ " -i dataFileName input file containing signed data (default stdin)",
+ " -o outputFileName output file name, default stdout",
+ " -s signatureFileName input file for signature (default stdin)",
+ " -v display verbose reason for failure"
+};
+static int nUsageInfo = sizeof(usageInfo) / sizeof(char *);
+
+extern int SV_PrintPKCS7ContentInfo(FILE *, SECItem *);
+
+static void
+Usage(char *progName, FILE *outFile)
+{
+ int i;
+ fprintf(outFile, "Usage: %s [ commands ] options\n", progName);
+ for (i = 0; i < nUsageInfo; i++)
+ fprintf(outFile, "%s\n", usageInfo[i]);
+ exit(-1);
+}
+
+static HASH_HashType
+AlgorithmToHashType(SECAlgorithmID *digestAlgorithms)
+{
+ SECOidTag tag = SECOID_GetAlgorithmTag(digestAlgorithms);
+ HASH_HashType hash = HASH_GetHashTypeByOidTag(tag);
+ return hash;
+}
+
+static SECStatus
+DigestContent(SECItem *digest, SECItem *content, HASH_HashType hashType)
+{
+ unsigned int maxLen = digest->len;
+ unsigned int len = HASH_ResultLen(hashType);
+ SECStatus rv;
+
+ if (len > maxLen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+
+ rv = HASH_HashBuf(hashType, digest->data, content->data, content->len);
+ if (rv == SECSuccess)
+ digest->len = len;
+ return rv;
+}
+
+enum {
+ cmd_DisplayAllPCKS7Info = 0,
+ cmd_VerifySignedObj
+};
+
+enum {
+ opt_ASCII,
+ opt_CertDir,
+ opt_InputDataFile,
+ opt_OutputFile,
+ opt_InputSigFile,
+ opt_PrintWhyFailure,
+ opt_DebugInfo
+};
+
+static secuCommandFlag signver_commands[] =
+ {
+ { /* cmd_DisplayAllPCKS7Info*/ 'A', PR_FALSE, 0, PR_FALSE },
+ { /* cmd_VerifySignedObj */ 'V', PR_FALSE, 0, PR_FALSE }
+ };
+
+static secuCommandFlag signver_options[] =
+ {
+ { /* opt_ASCII */ 'a', PR_FALSE, 0, PR_FALSE },
+ { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
+ { /* opt_InputDataFile */ 'i', PR_TRUE, 0, PR_FALSE },
+ { /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE },
+ { /* opt_InputSigFile */ 's', PR_TRUE, 0, PR_FALSE },
+ { /* opt_PrintWhyFailure */ 'v', PR_FALSE, 0, PR_FALSE },
+ { /* opt_DebugInfo */ 0, PR_FALSE, 0, PR_FALSE, "debug" }
+ };
+
+int
+main(int argc, char **argv)
+{
+ PRFileDesc *contentFile = NULL;
+ PRFileDesc *signFile = PR_STDIN;
+ FILE *outFile = stdout;
+ char *progName;
+ SECStatus rv;
+ int result = 1;
+ SECItem pkcs7der, content;
+ secuCommand signver;
+
+ pkcs7der.data = NULL;
+ content.data = NULL;
+
+ signver.numCommands = sizeof(signver_commands) / sizeof(secuCommandFlag);
+ signver.numOptions = sizeof(signver_options) / sizeof(secuCommandFlag);
+ signver.commands = signver_commands;
+ signver.options = signver_options;
+
+#ifdef XP_PC
+ progName = strrchr(argv[0], '\\');
+#else
+ progName = strrchr(argv[0], '/');
+#endif
+ progName = progName ? progName + 1 : argv[0];
+
+ rv = SECU_ParseCommandLine(argc, argv, progName, &signver);
+ if (SECSuccess != rv) {
+ Usage(progName, outFile);
+ }
+ debugInfo = signver.options[opt_DebugInfo].activated;
+ verbose = signver.options[opt_PrintWhyFailure].activated;
+ doVerify = signver.commands[cmd_VerifySignedObj].activated;
+ displayAll = signver.commands[cmd_DisplayAllPCKS7Info].activated;
+ if (!doVerify && !displayAll)
+ doVerify = PR_TRUE;
+
+ /* Set the certdb directory (default is ~/.netscape) */
+ rv = NSS_Init(SECU_ConfigDirectory(signver.options[opt_CertDir].arg));
+ if (rv != SECSuccess) {
+ SECU_PrintPRandOSError(progName);
+ return result;
+ }
+ /* below here, goto cleanup */
+ SECU_RegisterDynamicOids();
+
+ /* Open the input content file. */
+ if (signver.options[opt_InputDataFile].activated &&
+ signver.options[opt_InputDataFile].arg) {
+ if (PL_strcmp("-", signver.options[opt_InputDataFile].arg)) {
+ contentFile = PR_Open(signver.options[opt_InputDataFile].arg,
+ PR_RDONLY, 0);
+ if (!contentFile) {
+ PR_fprintf(PR_STDERR,
+ "%s: unable to open \"%s\" for reading.\n",
+ progName, signver.options[opt_InputDataFile].arg);
+ goto cleanup;
+ }
+ } else
+ contentFile = PR_STDIN;
+ }
+
+ /* Open the input signature file. */
+ if (signver.options[opt_InputSigFile].activated &&
+ signver.options[opt_InputSigFile].arg) {
+ if (PL_strcmp("-", signver.options[opt_InputSigFile].arg)) {
+ signFile = PR_Open(signver.options[opt_InputSigFile].arg,
+ PR_RDONLY, 0);
+ if (!signFile) {
+ PR_fprintf(PR_STDERR,
+ "%s: unable to open \"%s\" for reading.\n",
+ progName, signver.options[opt_InputSigFile].arg);
+ goto cleanup;
+ }
+ }
+ }
+
+ if (contentFile == PR_STDIN && signFile == PR_STDIN && doVerify) {
+ PR_fprintf(PR_STDERR,
+ "%s: cannot read both content and signature from standard input\n",
+ progName);
+ goto cleanup;
+ }
+
+ /* Open|Create the output file. */
+ if (signver.options[opt_OutputFile].activated) {
+ outFile = fopen(signver.options[opt_OutputFile].arg, "w");
+ if (!outFile) {
+ PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for writing.\n",
+ progName, signver.options[opt_OutputFile].arg);
+ goto cleanup;
+ }
+ }
+
+ /* read in the input files' contents */
+ rv = SECU_ReadDERFromFile(&pkcs7der, signFile,
+ signver.options[opt_ASCII].activated, PR_FALSE);
+ if (signFile != PR_STDIN)
+ PR_Close(signFile);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "problem reading PKCS7 input");
+ goto cleanup;
+ }
+ if (contentFile) {
+ rv = SECU_FileToItem(&content, contentFile);
+ if (contentFile != PR_STDIN)
+ PR_Close(contentFile);
+ if (rv != SECSuccess)
+ content.data = NULL;
+ }
+
+ /* Signature Verification */
+ if (doVerify) {
+ SEC_PKCS7ContentInfo *cinfo;
+ SEC_PKCS7SignedData *signedData;
+ HASH_HashType digestType;
+ PRBool contentIsSigned;
+
+ cinfo = SEC_PKCS7DecodeItem(&pkcs7der, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (cinfo == NULL) {
+ PR_fprintf(PR_STDERR, "Unable to decode PKCS7 data\n");
+ goto cleanup;
+ }
+ /* below here, goto done */
+
+ contentIsSigned = SEC_PKCS7ContentIsSigned(cinfo);
+ if (debugInfo) {
+ PR_fprintf(PR_STDERR, "Content is%s encrypted.\n",
+ SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not");
+ }
+ if (debugInfo || !contentIsSigned) {
+ PR_fprintf(PR_STDERR, "Content is%s signed.\n",
+ contentIsSigned ? "" : " not");
+ }
+
+ if (!contentIsSigned)
+ goto done;
+
+ signedData = cinfo->content.signedData;
+
+ /* assume that there is only one digest algorithm for now */
+ digestType = AlgorithmToHashType(signedData->digestAlgorithms[0]);
+ if (digestType == HASH_AlgNULL) {
+ PR_fprintf(PR_STDERR, "Invalid hash algorithmID\n");
+ goto done;
+ }
+ if (content.data) {
+ SECCertUsage usage = certUsageEmailSigner;
+ SECItem digest;
+ unsigned char digestBuffer[HASH_LENGTH_MAX];
+
+ if (debugInfo)
+ PR_fprintf(PR_STDERR, "contentToVerify=%s\n", content.data);
+
+ digest.data = digestBuffer;
+ digest.len = sizeof digestBuffer;
+
+ if (DigestContent(&digest, &content, digestType)) {
+ SECU_PrintError(progName, "Message digest computation failure");
+ goto done;
+ }
+
+ if (debugInfo) {
+ unsigned int i;
+ PR_fprintf(PR_STDERR, "Data Digest=:");
+ for (i = 0; i < digest.len; i++)
+ PR_fprintf(PR_STDERR, "%02x:", digest.data[i]);
+ PR_fprintf(PR_STDERR, "\n");
+ }
+
+ fprintf(outFile, "signatureValid=");
+ PORT_SetError(0);
+ if (SEC_PKCS7VerifyDetachedSignature(cinfo, usage,
+ &digest, digestType, PR_FALSE)) {
+ fprintf(outFile, "yes");
+ } else {
+ fprintf(outFile, "no");
+ if (verbose) {
+ fprintf(outFile, ":%s",
+ SECU_Strerror(PORT_GetError()));
+ }
+ }
+ fprintf(outFile, "\n");
+ result = 0;
+ }
+ done:
+ SEC_PKCS7DestroyContentInfo(cinfo);
+ }
+
+ if (displayAll) {
+ if (SV_PrintPKCS7ContentInfo(outFile, &pkcs7der))
+ result = 1;
+ }
+
+cleanup:
+ SECITEM_FreeItem(&pkcs7der, PR_FALSE);
+ SECITEM_FreeItem(&content, PR_FALSE);
+
+ if (NSS_Shutdown() != SECSuccess) {
+ result = 1;
+ }
+
+ return result;
+}