diff options
Diffstat (limited to 'security/nss/cmd/p7verify/p7verify.c')
-rw-r--r-- | security/nss/cmd/p7verify/p7verify.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/security/nss/cmd/p7verify/p7verify.c b/security/nss/cmd/p7verify/p7verify.c new file mode 100644 index 0000000000..5cbb4dcae9 --- /dev/null +++ b/security/nss/cmd/p7verify/p7verify.c @@ -0,0 +1,284 @@ +/* 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 HASH_HashType +AlgorithmToHashType(SECAlgorithmID *digestAlgorithms) +{ + + SECOidTag tag; + + tag = SECOID_GetAlgorithmTag(digestAlgorithms); + + switch (tag) { + case SEC_OID_MD2: + return HASH_AlgMD2; + case SEC_OID_MD5: + return HASH_AlgMD5; + case SEC_OID_SHA1: + return HASH_AlgSHA1; + default: + fprintf(stderr, "should never get here\n"); + return HASH_AlgNULL; + } +} + +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 = AlgorithmToHashType(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(strdup(optstate->value)); + if (usageType < certUsageSSLClient || usageType > certUsageAnyCA) + 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; +} |