security/nss/cmd/signver/signver.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/cmd/signver/signver.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,315 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "secutil.h"
     1.9 +#include "secmod.h"
    1.10 +#include "cert.h"
    1.11 +#include "secoid.h"
    1.12 +#include "nss.h"
    1.13 +
    1.14 +/* NSPR 2.0 header files */
    1.15 +#include "prinit.h"
    1.16 +#include "prprf.h"
    1.17 +#include "prsystem.h"
    1.18 +#include "prmem.h"
    1.19 +/* Portable layer header files */
    1.20 +#include "plstr.h"
    1.21 +#include "sechash.h"	/* for HASH_GetHashObject() */
    1.22 +
    1.23 +static PRBool debugInfo;
    1.24 +static PRBool verbose;
    1.25 +static PRBool doVerify;
    1.26 +static PRBool displayAll;
    1.27 +
    1.28 +static const char * const usageInfo[] = {
    1.29 +    "signver - verify a detached PKCS7 signature - Version " NSS_VERSION,
    1.30 +    "Commands:",
    1.31 +    " -A		    display all information from pkcs #7",
    1.32 +    " -V		    verify the signed object and display result",
    1.33 +    "Options:",
    1.34 +    " -a		    signature file is ASCII",
    1.35 +    " -d certdir	    directory containing cert database",
    1.36 +    " -i dataFileName	    input file containing signed data (default stdin)",
    1.37 +    " -o outputFileName     output file name, default stdout",
    1.38 +    " -s signatureFileName  input file for signature (default stdin)",
    1.39 +    " -v		    display verbose reason for failure"
    1.40 +};
    1.41 +static int nUsageInfo = sizeof(usageInfo)/sizeof(char *);
    1.42 +
    1.43 +extern int SV_PrintPKCS7ContentInfo(FILE *, SECItem *);
    1.44 +
    1.45 +static void Usage(char *progName, FILE *outFile)
    1.46 +{
    1.47 +    int i;
    1.48 +    fprintf(outFile, "Usage:  %s [ commands ] options\n", progName);
    1.49 +    for (i = 0; i < nUsageInfo; i++)
    1.50 +	fprintf(outFile, "%s\n", usageInfo[i]);
    1.51 +    exit(-1);
    1.52 +}
    1.53 +
    1.54 +static HASH_HashType
    1.55 +AlgorithmToHashType(SECAlgorithmID *digestAlgorithms)
    1.56 +{
    1.57 +    SECOidTag	  tag  = SECOID_GetAlgorithmTag(digestAlgorithms);
    1.58 +    HASH_HashType hash = HASH_GetHashTypeByOidTag(tag);
    1.59 +    return hash;
    1.60 +}
    1.61 +
    1.62 +
    1.63 +static SECStatus
    1.64 +DigestContent (SECItem * digest, SECItem * content, HASH_HashType hashType)
    1.65 +{
    1.66 +    unsigned int maxLen = digest->len;
    1.67 +    unsigned int len	= HASH_ResultLen(hashType);
    1.68 +    SECStatus	 rv;
    1.69 +
    1.70 +    if (len > maxLen) {
    1.71 +	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    1.72 +	return SECFailure;
    1.73 +    }
    1.74 +
    1.75 +    rv = HASH_HashBuf(hashType, digest->data, content->data, content->len);
    1.76 +    if (rv == SECSuccess)
    1.77 +	digest->len = len;
    1.78 +    return rv;
    1.79 +}
    1.80 +
    1.81 +enum {
    1.82 +    cmd_DisplayAllPCKS7Info = 0,
    1.83 +    cmd_VerifySignedObj
    1.84 +};
    1.85 +
    1.86 +enum {
    1.87 +    opt_ASCII,
    1.88 +    opt_CertDir,
    1.89 +    opt_InputDataFile,
    1.90 +    opt_ItemNumber,
    1.91 +    opt_OutputFile,
    1.92 +    opt_InputSigFile,
    1.93 +    opt_PrintWhyFailure,
    1.94 +    opt_DebugInfo
    1.95 +};
    1.96 +
    1.97 +static secuCommandFlag signver_commands[] =
    1.98 +{
    1.99 +    { /* cmd_DisplayAllPCKS7Info*/  'A', PR_FALSE, 0, PR_FALSE },
   1.100 +    { /* cmd_VerifySignedObj	*/  'V', PR_FALSE, 0, PR_FALSE }
   1.101 +};
   1.102 +
   1.103 +static secuCommandFlag signver_options[] =
   1.104 +{
   1.105 +    { /* opt_ASCII		*/  'a', PR_FALSE, 0, PR_FALSE },
   1.106 +    { /* opt_CertDir		*/  'd', PR_TRUE,  0, PR_FALSE },
   1.107 +    { /* opt_InputDataFile	*/  'i', PR_TRUE,  0, PR_FALSE },
   1.108 +    { /* opt_OutputFile 	*/  'o', PR_TRUE,  0, PR_FALSE },
   1.109 +    { /* opt_InputSigFile	*/  's', PR_TRUE,  0, PR_FALSE },
   1.110 +    { /* opt_PrintWhyFailure	*/  'v', PR_FALSE, 0, PR_FALSE },
   1.111 +    { /* opt_DebugInfo		*/    0, PR_FALSE, 0, PR_FALSE, "debug" }
   1.112 +};
   1.113 +
   1.114 +int main(int argc, char **argv)
   1.115 +{
   1.116 +    PRFileDesc *contentFile = NULL;
   1.117 +    PRFileDesc *signFile = PR_STDIN;
   1.118 +    FILE *	outFile  = stdout;
   1.119 +    char *	progName;
   1.120 +    SECStatus	rv;
   1.121 +    int 	result	 = 1;
   1.122 +    SECItem	pkcs7der, content;
   1.123 +    secuCommand signver;
   1.124 +
   1.125 +    pkcs7der.data  = NULL;
   1.126 +    content.data = NULL;
   1.127 +
   1.128 +    signver.numCommands = sizeof(signver_commands) /sizeof(secuCommandFlag);
   1.129 +    signver.numOptions = sizeof(signver_options) / sizeof(secuCommandFlag);
   1.130 +    signver.commands = signver_commands;
   1.131 +    signver.options = signver_options;
   1.132 +
   1.133 +#ifdef XP_PC
   1.134 +    progName = strrchr(argv[0], '\\');
   1.135 +#else
   1.136 +    progName = strrchr(argv[0], '/');
   1.137 +#endif
   1.138 +    progName = progName ? progName+1 : argv[0];
   1.139 +
   1.140 +    rv = SECU_ParseCommandLine(argc, argv, progName, &signver);
   1.141 +    if (SECSuccess != rv) {
   1.142 +	Usage(progName, outFile);
   1.143 +    }
   1.144 +    debugInfo = signver.options[opt_DebugInfo	    ].activated;
   1.145 +    verbose   = signver.options[opt_PrintWhyFailure ].activated;
   1.146 +    doVerify  = signver.commands[cmd_VerifySignedObj].activated;
   1.147 +    displayAll= signver.commands[cmd_DisplayAllPCKS7Info].activated;
   1.148 +    if (!doVerify && !displayAll)
   1.149 +	doVerify = PR_TRUE;
   1.150 +
   1.151 +    /*	Set the certdb directory (default is ~/.netscape) */
   1.152 +    rv = NSS_Init(SECU_ConfigDirectory(signver.options[opt_CertDir].arg));
   1.153 +    if (rv != SECSuccess) {
   1.154 +	SECU_PrintPRandOSError(progName);
   1.155 +	return result;
   1.156 +    }
   1.157 +    /* below here, goto cleanup */
   1.158 +    SECU_RegisterDynamicOids();
   1.159 +
   1.160 +    /*	Open the input content file. */
   1.161 +    if (signver.options[opt_InputDataFile].activated &&
   1.162 +	signver.options[opt_InputDataFile].arg) {
   1.163 +	if (PL_strcmp("-", signver.options[opt_InputDataFile].arg)) {
   1.164 +	    contentFile = PR_Open(signver.options[opt_InputDataFile].arg,
   1.165 +			       PR_RDONLY, 0);
   1.166 +	    if (!contentFile) {
   1.167 +		PR_fprintf(PR_STDERR,
   1.168 +			   "%s: unable to open \"%s\" for reading.\n",
   1.169 +			   progName, signver.options[opt_InputDataFile].arg);
   1.170 +		goto cleanup;
   1.171 +	    }
   1.172 +	} else
   1.173 +	    contentFile = PR_STDIN;
   1.174 +    }
   1.175 +
   1.176 +    /*	Open the input signature file.	*/
   1.177 +    if (signver.options[opt_InputSigFile].activated &&
   1.178 +	signver.options[opt_InputSigFile].arg) {
   1.179 +	if (PL_strcmp("-", signver.options[opt_InputSigFile].arg)) {
   1.180 +	    signFile = PR_Open(signver.options[opt_InputSigFile].arg,
   1.181 +			       PR_RDONLY, 0);
   1.182 +	    if (!signFile) {
   1.183 +		PR_fprintf(PR_STDERR,
   1.184 +			   "%s: unable to open \"%s\" for reading.\n",
   1.185 +			   progName, signver.options[opt_InputSigFile].arg);
   1.186 +		goto cleanup;
   1.187 +	    }
   1.188 +	}
   1.189 +    }
   1.190 +
   1.191 +    if (contentFile == PR_STDIN && signFile == PR_STDIN && doVerify) {
   1.192 +	PR_fprintf(PR_STDERR,
   1.193 +	    "%s: cannot read both content and signature from standard input\n",
   1.194 +		   progName);
   1.195 +	goto cleanup;
   1.196 +    }
   1.197 +
   1.198 +    /*	Open|Create the output file.  */
   1.199 +    if (signver.options[opt_OutputFile].activated) {
   1.200 +	outFile = fopen(signver.options[opt_OutputFile].arg, "w");
   1.201 +	if (!outFile) {
   1.202 +	    PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for writing.\n",
   1.203 +		       progName, signver.options[opt_OutputFile].arg);
   1.204 +	    goto cleanup;
   1.205 +	}
   1.206 +    }
   1.207 +
   1.208 +    /* read in the input files' contents */
   1.209 +    rv = SECU_ReadDERFromFile(&pkcs7der, signFile,
   1.210 +			      signver.options[opt_ASCII].activated, PR_FALSE);
   1.211 +    if (signFile != PR_STDIN)
   1.212 +	PR_Close(signFile);
   1.213 +    if (rv != SECSuccess) {
   1.214 +	SECU_PrintError(progName, "problem reading PKCS7 input");
   1.215 +	goto cleanup;
   1.216 +    }
   1.217 +    if (contentFile) {
   1.218 +	rv = SECU_FileToItem(&content, contentFile);
   1.219 +	if (contentFile != PR_STDIN)
   1.220 +	    PR_Close(contentFile);
   1.221 +	if (rv != SECSuccess)
   1.222 +	    content.data = NULL;
   1.223 +    }
   1.224 +
   1.225 +    /* Signature Verification */
   1.226 +    if (doVerify) {
   1.227 +	SEC_PKCS7ContentInfo *cinfo;
   1.228 +	SEC_PKCS7SignedData *signedData;
   1.229 +	HASH_HashType digestType;
   1.230 +	PRBool contentIsSigned;
   1.231 +
   1.232 +	cinfo = SEC_PKCS7DecodeItem(&pkcs7der, NULL, NULL, NULL, NULL,
   1.233 +				    NULL, NULL, NULL);
   1.234 +	if (cinfo == NULL) {
   1.235 +	    PR_fprintf(PR_STDERR, "Unable to decode PKCS7 data\n");
   1.236 +	    goto cleanup;
   1.237 +	}
   1.238 +	/* below here, goto done */
   1.239 +
   1.240 +	contentIsSigned = SEC_PKCS7ContentIsSigned(cinfo);
   1.241 +	if (debugInfo) {
   1.242 +	    PR_fprintf(PR_STDERR, "Content is%s encrypted.\n",
   1.243 +		       SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not");
   1.244 +	}
   1.245 +	if (debugInfo || !contentIsSigned) {
   1.246 +	    PR_fprintf(PR_STDERR, "Content is%s signed.\n",
   1.247 +		       contentIsSigned ? "" : " not");
   1.248 +	}
   1.249 +
   1.250 +	if (!contentIsSigned)
   1.251 +	    goto done;
   1.252 +
   1.253 +	signedData = cinfo->content.signedData;
   1.254 +
   1.255 +	/* assume that there is only one digest algorithm for now */
   1.256 +	digestType = AlgorithmToHashType(signedData->digestAlgorithms[0]);
   1.257 +	if (digestType == HASH_AlgNULL) {
   1.258 +	    PR_fprintf(PR_STDERR, "Invalid hash algorithmID\n");
   1.259 +	    goto done;
   1.260 +	}
   1.261 +	if (content.data) {
   1.262 +	    SECCertUsage   usage = certUsageEmailSigner;
   1.263 +	    SECItem	   digest;
   1.264 +	    unsigned char  digestBuffer[HASH_LENGTH_MAX];
   1.265 +
   1.266 +	    if (debugInfo)
   1.267 +		PR_fprintf(PR_STDERR, "contentToVerify=%s\n", content.data);
   1.268 +
   1.269 +	    digest.data = digestBuffer;
   1.270 +	    digest.len	= sizeof digestBuffer;
   1.271 +
   1.272 +	    if (DigestContent(&digest, &content, digestType)) {
   1.273 +		SECU_PrintError(progName, "Message digest computation failure");
   1.274 +		goto done;
   1.275 +	    }
   1.276 +
   1.277 +	    if (debugInfo) {
   1.278 +		unsigned int i;
   1.279 +		PR_fprintf(PR_STDERR, "Data Digest=:");
   1.280 +		for (i = 0; i < digest.len; i++)
   1.281 +		    PR_fprintf(PR_STDERR, "%02x:", digest.data[i]);
   1.282 +		PR_fprintf(PR_STDERR, "\n");
   1.283 +	    }
   1.284 +
   1.285 +	    fprintf(outFile, "signatureValid=");
   1.286 +	    PORT_SetError(0);
   1.287 +	    if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage,
   1.288 +				   &digest, digestType, PR_FALSE)) {
   1.289 +		fprintf(outFile, "yes");
   1.290 +	    } else {
   1.291 +		fprintf(outFile, "no");
   1.292 +		if (verbose) {
   1.293 +		    fprintf(outFile, ":%s",
   1.294 +			    SECU_Strerror(PORT_GetError()));
   1.295 +		}
   1.296 +	    }
   1.297 +	    fprintf(outFile, "\n");
   1.298 +	    result = 0;
   1.299 +	}
   1.300 +done:
   1.301 +	SEC_PKCS7DestroyContentInfo(cinfo);
   1.302 +    }
   1.303 +
   1.304 +    if (displayAll) {
   1.305 +	if (SV_PrintPKCS7ContentInfo(outFile, &pkcs7der))
   1.306 +	    result = 1;
   1.307 +    }
   1.308 +
   1.309 +cleanup:
   1.310 +    SECITEM_FreeItem(&pkcs7der, PR_FALSE);
   1.311 +    SECITEM_FreeItem(&content, PR_FALSE);
   1.312 +
   1.313 +    if (NSS_Shutdown() != SECSuccess) {
   1.314 +	result = 1;
   1.315 +    }
   1.316 +
   1.317 +    return result;
   1.318 +}

mercurial