diff options
Diffstat (limited to 'security/nss/cmd/signver/signver.c')
-rw-r--r-- | security/nss/cmd/signver/signver.c | 315 |
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; +} |