Blame nss/cmd/signver/signver.c

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