1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/p7verify/p7verify.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,275 @@ 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 +/* 1.9 + * p7verify -- A command to do a verification of a *detached* pkcs7 signature. 1.10 + */ 1.11 + 1.12 +#include "nspr.h" 1.13 +#include "secutil.h" 1.14 +#include "plgetopt.h" 1.15 +#include "secpkcs7.h" 1.16 +#include "cert.h" 1.17 +#include "certdb.h" 1.18 +#include "secoid.h" 1.19 +#include "sechash.h" /* for HASH_GetHashObject() */ 1.20 +#include "nss.h" 1.21 + 1.22 +#if defined(XP_UNIX) 1.23 +#include <unistd.h> 1.24 +#endif 1.25 + 1.26 +#include <stdio.h> 1.27 +#include <string.h> 1.28 + 1.29 +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) 1.30 +extern int fread(char *, size_t, size_t, FILE*); 1.31 +extern int fprintf(FILE *, char *, ...); 1.32 +#endif 1.33 + 1.34 + 1.35 +static HASH_HashType 1.36 +AlgorithmToHashType(SECAlgorithmID *digestAlgorithms) 1.37 +{ 1.38 + 1.39 + SECOidTag tag; 1.40 + 1.41 + tag = SECOID_GetAlgorithmTag(digestAlgorithms); 1.42 + 1.43 + switch (tag) { 1.44 + case SEC_OID_MD2: 1.45 + return HASH_AlgMD2; 1.46 + case SEC_OID_MD5: 1.47 + return HASH_AlgMD5; 1.48 + case SEC_OID_SHA1: 1.49 + return HASH_AlgSHA1; 1.50 + default: 1.51 + fprintf(stderr, "should never get here\n"); 1.52 + return HASH_AlgNULL; 1.53 + } 1.54 +} 1.55 + 1.56 +static int 1.57 +DigestFile(unsigned char *digest, unsigned int *len, unsigned int maxLen, 1.58 + FILE *inFile, HASH_HashType hashType) 1.59 +{ 1.60 + int nb; 1.61 + unsigned char ibuf[4096]; 1.62 + const SECHashObject *hashObj; 1.63 + void *hashcx; 1.64 + 1.65 + hashObj = HASH_GetHashObject(hashType); 1.66 + 1.67 + hashcx = (* hashObj->create)(); 1.68 + if (hashcx == NULL) 1.69 + return -1; 1.70 + 1.71 + (* hashObj->begin)(hashcx); 1.72 + 1.73 + for (;;) { 1.74 + if (feof(inFile)) break; 1.75 + nb = fread(ibuf, 1, sizeof(ibuf), inFile); 1.76 + if (nb != sizeof(ibuf)) { 1.77 + if (nb == 0) { 1.78 + if (ferror(inFile)) { 1.79 + PORT_SetError(SEC_ERROR_IO); 1.80 + (* hashObj->destroy)(hashcx, PR_TRUE); 1.81 + return -1; 1.82 + } 1.83 + /* eof */ 1.84 + break; 1.85 + } 1.86 + } 1.87 + (* hashObj->update)(hashcx, ibuf, nb); 1.88 + } 1.89 + 1.90 + (* hashObj->end)(hashcx, digest, len, maxLen); 1.91 + (* hashObj->destroy)(hashcx, PR_TRUE); 1.92 + 1.93 + return 0; 1.94 +} 1.95 + 1.96 + 1.97 +static void 1.98 +Usage(char *progName) 1.99 +{ 1.100 + fprintf(stderr, 1.101 + "Usage: %s -c content -s signature [-d dbdir] [-u certusage]\n", 1.102 + progName); 1.103 + fprintf(stderr, "%-20s content file that was signed\n", 1.104 + "-c content"); 1.105 + fprintf(stderr, "%-20s file containing signature for that content\n", 1.106 + "-s signature"); 1.107 + fprintf(stderr, 1.108 + "%-20s Key/Cert database directory (default is ~/.netscape)\n", 1.109 + "-d dbdir"); 1.110 + fprintf(stderr, "%-20s Define the type of certificate usage (default is certUsageEmailSigner)\n", 1.111 + "-u certusage"); 1.112 + fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " "); 1.113 + fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " "); 1.114 + fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " "); 1.115 + fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " "); 1.116 + fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " "); 1.117 + fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " "); 1.118 + fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " "); 1.119 + fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " "); 1.120 + fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " "); 1.121 + fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " "); 1.122 + fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " "); 1.123 + fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " "); 1.124 + 1.125 + exit(-1); 1.126 +} 1.127 + 1.128 +static int 1.129 +HashDecodeAndVerify(FILE *out, FILE *content, PRFileDesc *signature, 1.130 + SECCertUsage usage, char *progName) 1.131 +{ 1.132 + SECItem derdata; 1.133 + SEC_PKCS7ContentInfo *cinfo; 1.134 + SEC_PKCS7SignedData *signedData; 1.135 + HASH_HashType digestType; 1.136 + SECItem digest; 1.137 + unsigned char buffer[32]; 1.138 + 1.139 + if (SECU_ReadDERFromFile(&derdata, signature, PR_FALSE, 1.140 + PR_FALSE) != SECSuccess) { 1.141 + SECU_PrintError(progName, "error reading signature file"); 1.142 + return -1; 1.143 + } 1.144 + 1.145 + cinfo = SEC_PKCS7DecodeItem(&derdata, NULL, NULL, NULL, NULL, 1.146 + NULL, NULL, NULL); 1.147 + if (cinfo == NULL) 1.148 + return -1; 1.149 + 1.150 + if (! SEC_PKCS7ContentIsSigned(cinfo)) { 1.151 + fprintf (out, "Signature file is pkcs7 data, but not signed.\n"); 1.152 + return -1; 1.153 + } 1.154 + 1.155 + signedData = cinfo->content.signedData; 1.156 + 1.157 + /* assume that there is only one digest algorithm for now */ 1.158 + digestType = AlgorithmToHashType(signedData->digestAlgorithms[0]); 1.159 + if (digestType == HASH_AlgNULL) { 1.160 + fprintf (out, "Invalid hash algorithmID\n"); 1.161 + return -1; 1.162 + } 1.163 + 1.164 + digest.data = buffer; 1.165 + if (DigestFile (digest.data, &digest.len, 32, content, digestType)) { 1.166 + SECU_PrintError (progName, "problem computing message digest"); 1.167 + return -1; 1.168 + } 1.169 + 1.170 + fprintf(out, "Signature is "); 1.171 + if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage, &digest, digestType, 1.172 + PR_FALSE)) 1.173 + fprintf(out, "valid.\n"); 1.174 + else 1.175 + fprintf(out, "invalid (Reason: %s).\n", 1.176 + SECU_Strerror(PORT_GetError())); 1.177 + 1.178 + SEC_PKCS7DestroyContentInfo(cinfo); 1.179 + return 0; 1.180 +} 1.181 + 1.182 + 1.183 +int 1.184 +main(int argc, char **argv) 1.185 +{ 1.186 + char *progName; 1.187 + FILE *contentFile, *outFile; 1.188 + PRFileDesc *signatureFile; 1.189 + SECCertUsage certUsage = certUsageEmailSigner; 1.190 + PLOptState *optstate; 1.191 + PLOptStatus status; 1.192 + SECStatus rv; 1.193 + 1.194 + progName = strrchr(argv[0], '/'); 1.195 + progName = progName ? progName+1 : argv[0]; 1.196 + 1.197 + contentFile = NULL; 1.198 + signatureFile = NULL; 1.199 + outFile = NULL; 1.200 + 1.201 + /* 1.202 + * Parse command line arguments 1.203 + */ 1.204 + optstate = PL_CreateOptState(argc, argv, "c:d:o:s:u:"); 1.205 + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 1.206 + switch (optstate->option) { 1.207 + case '?': 1.208 + Usage(progName); 1.209 + break; 1.210 + 1.211 + case 'c': 1.212 + contentFile = fopen(optstate->value, "r"); 1.213 + if (!contentFile) { 1.214 + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 1.215 + progName, optstate->value); 1.216 + return -1; 1.217 + } 1.218 + break; 1.219 + 1.220 + case 'd': 1.221 + SECU_ConfigDirectory(optstate->value); 1.222 + break; 1.223 + 1.224 + case 'o': 1.225 + outFile = fopen(optstate->value, "w"); 1.226 + if (!outFile) { 1.227 + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 1.228 + progName, optstate->value); 1.229 + return -1; 1.230 + } 1.231 + break; 1.232 + 1.233 + case 's': 1.234 + signatureFile = PR_Open(optstate->value, PR_RDONLY, 0); 1.235 + if (!signatureFile) { 1.236 + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 1.237 + progName, optstate->value); 1.238 + return -1; 1.239 + } 1.240 + break; 1.241 + 1.242 + case 'u': { 1.243 + int usageType; 1.244 + 1.245 + usageType = atoi (strdup(optstate->value)); 1.246 + if (usageType < certUsageSSLClient || usageType > certUsageAnyCA) 1.247 + return -1; 1.248 + certUsage = (SECCertUsage)usageType; 1.249 + break; 1.250 + } 1.251 + 1.252 + } 1.253 + } 1.254 + 1.255 + if (!contentFile) Usage (progName); 1.256 + if (!signatureFile) Usage (progName); 1.257 + if (!outFile) outFile = stdout; 1.258 + 1.259 + /* Call the NSS initialization routines */ 1.260 + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 1.261 + rv = NSS_Init(SECU_ConfigDirectory(NULL)); 1.262 + if (rv != SECSuccess) { 1.263 + SECU_PrintPRandOSError(progName); 1.264 + return -1; 1.265 + } 1.266 + 1.267 + if (HashDecodeAndVerify(outFile, contentFile, signatureFile, 1.268 + certUsage, progName)) { 1.269 + SECU_PrintError(progName, "problem decoding/verifying signature"); 1.270 + return -1; 1.271 + } 1.272 + 1.273 + if (NSS_Shutdown() != SECSuccess) { 1.274 + exit(1); 1.275 + } 1.276 + 1.277 + return 0; 1.278 +}