Source code

Revision control

Copy as Markdown

Other Tools

/* 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/. */
/*
* p7verify -- A command to do a verification of a *detached* pkcs7 signature.
*/
#include "nspr.h"
#include "secutil.h"
#include "plgetopt.h"
#include "secpkcs7.h"
#include "cert.h"
#include "certdb.h"
#include "secoid.h"
#include "sechash.h" /* for HASH_GetHashObject() */
#include "nss.h"
#if defined(XP_UNIX)
#include <unistd.h>
#endif
#include <stdio.h>
#include <string.h>
#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
extern int fread(char *, size_t, size_t, FILE *);
extern int fprintf(FILE *, char *, ...);
#endif
static int
DigestFile(unsigned char *digest, unsigned int *len, unsigned int maxLen,
FILE *inFile, HASH_HashType hashType)
{
int nb;
unsigned char ibuf[4096];
const SECHashObject *hashObj;
void *hashcx;
hashObj = HASH_GetHashObject(hashType);
hashcx = (*hashObj->create)();
if (hashcx == NULL)
return -1;
(*hashObj->begin)(hashcx);
for (;;) {
if (feof(inFile))
break;
nb = fread(ibuf, 1, sizeof(ibuf), inFile);
if (nb != sizeof(ibuf)) {
if (nb == 0) {
if (ferror(inFile)) {
PORT_SetError(SEC_ERROR_IO);
(*hashObj->destroy)(hashcx, PR_TRUE);
return -1;
}
/* eof */
break;
}
}
(*hashObj->update)(hashcx, ibuf, nb);
}
(*hashObj->end)(hashcx, digest, len, maxLen);
(*hashObj->destroy)(hashcx, PR_TRUE);
return 0;
}
static void
Usage(char *progName)
{
fprintf(stderr,
"Usage: %s -c content -s signature [-d dbdir] [-u certusage]\n",
progName);
fprintf(stderr, "%-20s content file that was signed\n",
"-c content");
fprintf(stderr, "%-20s file containing signature for that content\n",
"-s signature");
fprintf(stderr,
"%-20s Key/Cert database directory (default is ~/.netscape)\n",
"-d dbdir");
fprintf(stderr, "%-20s Define the type of certificate usage (default is certUsageEmailSigner)\n",
"-u certusage");
fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " ");
fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " ");
fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " ");
fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " ");
fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " ");
fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " ");
fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " ");
fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " ");
fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " ");
fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " ");
fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
fprintf(stderr, "%-25s 12 - certUsageIPsec\n", " ");
exit(-1);
}
static int
HashDecodeAndVerify(FILE *out, FILE *content, PRFileDesc *signature,
SECCertUsage usage, char *progName)
{
SECItem derdata;
SEC_PKCS7ContentInfo *cinfo;
SEC_PKCS7SignedData *signedData;
HASH_HashType digestType;
SECItem digest;
unsigned char buffer[32];
if (SECU_ReadDERFromFile(&derdata, signature, PR_FALSE,
PR_FALSE) != SECSuccess) {
SECU_PrintError(progName, "error reading signature file");
return -1;
}
cinfo = SEC_PKCS7DecodeItem(&derdata, NULL, NULL, NULL, NULL,
NULL, NULL, NULL);
if (cinfo == NULL)
return -1;
if (!SEC_PKCS7ContentIsSigned(cinfo)) {
fprintf(out, "Signature file is pkcs7 data, but not signed.\n");
return -1;
}
signedData = cinfo->content.signedData;
/* assume that there is only one digest algorithm for now */
digestType = HASH_GetHashTypeByOidTag(
SECOID_GetAlgorithmTag(signedData->digestAlgorithms[0]));
if (digestType == HASH_AlgNULL) {
fprintf(out, "Invalid hash algorithmID\n");
return -1;
}
digest.data = buffer;
if (DigestFile(digest.data, &digest.len, 32, content, digestType)) {
SECU_PrintError(progName, "problem computing message digest");
return -1;
}
fprintf(out, "Signature is ");
if (SEC_PKCS7VerifyDetachedSignature(cinfo, usage, &digest, digestType,
PR_FALSE))
fprintf(out, "valid.\n");
else
fprintf(out, "invalid (Reason: %s).\n",
SECU_Strerror(PORT_GetError()));
SECITEM_FreeItem(&derdata, PR_FALSE);
SEC_PKCS7DestroyContentInfo(cinfo);
return 0;
}
int
main(int argc, char **argv)
{
char *progName;
FILE *contentFile, *outFile;
PRFileDesc *signatureFile;
SECCertUsage certUsage = certUsageEmailSigner;
PLOptState *optstate;
PLOptStatus status;
SECStatus rv;
progName = strrchr(argv[0], '/');
progName = progName ? progName + 1 : argv[0];
contentFile = NULL;
signatureFile = NULL;
outFile = NULL;
/*
* Parse command line arguments
*/
optstate = PL_CreateOptState(argc, argv, "c:d:o:s:u:");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
Usage(progName);
break;
case 'c':
contentFile = fopen(optstate->value, "r");
if (!contentFile) {
fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
progName, optstate->value);
return -1;
}
break;
case 'd':
SECU_ConfigDirectory(optstate->value);
break;
case 'o':
outFile = fopen(optstate->value, "w");
if (!outFile) {
fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
progName, optstate->value);
return -1;
}
break;
case 's':
signatureFile = PR_Open(optstate->value, PR_RDONLY, 0);
if (!signatureFile) {
fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
progName, optstate->value);
return -1;
}
break;
case 'u': {
int usageType;
usageType = atoi(optstate->value);
if (usageType < certUsageSSLClient || usageType > certUsageIPsec)
return -1;
certUsage = (SECCertUsage)usageType;
break;
}
}
}
PL_DestroyOptState(optstate);
if (!contentFile)
Usage(progName);
if (!signatureFile)
Usage(progName);
if (!outFile)
outFile = stdout;
/* Call the NSS initialization routines */
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
rv = NSS_Init(SECU_ConfigDirectory(NULL));
if (rv != SECSuccess) {
SECU_PrintPRandOSError(progName);
return -1;
}
if (HashDecodeAndVerify(outFile, contentFile, signatureFile,
certUsage, progName)) {
SECU_PrintError(progName, "problem decoding/verifying signature");
return -1;
}
fclose(contentFile);
PR_Close(signatureFile);
if (outFile && outFile != stdout) {
fclose(outFile);
}
if (NSS_Shutdown() != SECSuccess) {
exit(1);
}
return 0;
}