Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "secutil.h"
6 #include "secmod.h"
7 #include "cert.h"
8 #include "secoid.h"
9 #include "nss.h"
11 /* NSPR 2.0 header files */
12 #include "prinit.h"
13 #include "prprf.h"
14 #include "prsystem.h"
15 #include "prmem.h"
16 /* Portable layer header files */
17 #include "plstr.h"
18 #include "sechash.h" /* for HASH_GetHashObject() */
20 static PRBool debugInfo;
21 static PRBool verbose;
22 static PRBool doVerify;
23 static PRBool displayAll;
25 static const char * const usageInfo[] = {
26 "signver - verify a detached PKCS7 signature - Version " NSS_VERSION,
27 "Commands:",
28 " -A display all information from pkcs #7",
29 " -V verify the signed object and display result",
30 "Options:",
31 " -a signature file is ASCII",
32 " -d certdir directory containing cert database",
33 " -i dataFileName input file containing signed data (default stdin)",
34 " -o outputFileName output file name, default stdout",
35 " -s signatureFileName input file for signature (default stdin)",
36 " -v display verbose reason for failure"
37 };
38 static int nUsageInfo = sizeof(usageInfo)/sizeof(char *);
40 extern int SV_PrintPKCS7ContentInfo(FILE *, SECItem *);
42 static void Usage(char *progName, FILE *outFile)
43 {
44 int i;
45 fprintf(outFile, "Usage: %s [ commands ] options\n", progName);
46 for (i = 0; i < nUsageInfo; i++)
47 fprintf(outFile, "%s\n", usageInfo[i]);
48 exit(-1);
49 }
51 static HASH_HashType
52 AlgorithmToHashType(SECAlgorithmID *digestAlgorithms)
53 {
54 SECOidTag tag = SECOID_GetAlgorithmTag(digestAlgorithms);
55 HASH_HashType hash = HASH_GetHashTypeByOidTag(tag);
56 return hash;
57 }
60 static SECStatus
61 DigestContent (SECItem * digest, SECItem * content, HASH_HashType hashType)
62 {
63 unsigned int maxLen = digest->len;
64 unsigned int len = HASH_ResultLen(hashType);
65 SECStatus rv;
67 if (len > maxLen) {
68 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
69 return SECFailure;
70 }
72 rv = HASH_HashBuf(hashType, digest->data, content->data, content->len);
73 if (rv == SECSuccess)
74 digest->len = len;
75 return rv;
76 }
78 enum {
79 cmd_DisplayAllPCKS7Info = 0,
80 cmd_VerifySignedObj
81 };
83 enum {
84 opt_ASCII,
85 opt_CertDir,
86 opt_InputDataFile,
87 opt_ItemNumber,
88 opt_OutputFile,
89 opt_InputSigFile,
90 opt_PrintWhyFailure,
91 opt_DebugInfo
92 };
94 static secuCommandFlag signver_commands[] =
95 {
96 { /* cmd_DisplayAllPCKS7Info*/ 'A', PR_FALSE, 0, PR_FALSE },
97 { /* cmd_VerifySignedObj */ 'V', PR_FALSE, 0, PR_FALSE }
98 };
100 static secuCommandFlag signver_options[] =
101 {
102 { /* opt_ASCII */ 'a', PR_FALSE, 0, PR_FALSE },
103 { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
104 { /* opt_InputDataFile */ 'i', PR_TRUE, 0, PR_FALSE },
105 { /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE },
106 { /* opt_InputSigFile */ 's', PR_TRUE, 0, PR_FALSE },
107 { /* opt_PrintWhyFailure */ 'v', PR_FALSE, 0, PR_FALSE },
108 { /* opt_DebugInfo */ 0, PR_FALSE, 0, PR_FALSE, "debug" }
109 };
111 int main(int argc, char **argv)
112 {
113 PRFileDesc *contentFile = NULL;
114 PRFileDesc *signFile = PR_STDIN;
115 FILE * outFile = stdout;
116 char * progName;
117 SECStatus rv;
118 int result = 1;
119 SECItem pkcs7der, content;
120 secuCommand signver;
122 pkcs7der.data = NULL;
123 content.data = NULL;
125 signver.numCommands = sizeof(signver_commands) /sizeof(secuCommandFlag);
126 signver.numOptions = sizeof(signver_options) / sizeof(secuCommandFlag);
127 signver.commands = signver_commands;
128 signver.options = signver_options;
130 #ifdef XP_PC
131 progName = strrchr(argv[0], '\\');
132 #else
133 progName = strrchr(argv[0], '/');
134 #endif
135 progName = progName ? progName+1 : argv[0];
137 rv = SECU_ParseCommandLine(argc, argv, progName, &signver);
138 if (SECSuccess != rv) {
139 Usage(progName, outFile);
140 }
141 debugInfo = signver.options[opt_DebugInfo ].activated;
142 verbose = signver.options[opt_PrintWhyFailure ].activated;
143 doVerify = signver.commands[cmd_VerifySignedObj].activated;
144 displayAll= signver.commands[cmd_DisplayAllPCKS7Info].activated;
145 if (!doVerify && !displayAll)
146 doVerify = PR_TRUE;
148 /* Set the certdb directory (default is ~/.netscape) */
149 rv = NSS_Init(SECU_ConfigDirectory(signver.options[opt_CertDir].arg));
150 if (rv != SECSuccess) {
151 SECU_PrintPRandOSError(progName);
152 return result;
153 }
154 /* below here, goto cleanup */
155 SECU_RegisterDynamicOids();
157 /* Open the input content file. */
158 if (signver.options[opt_InputDataFile].activated &&
159 signver.options[opt_InputDataFile].arg) {
160 if (PL_strcmp("-", signver.options[opt_InputDataFile].arg)) {
161 contentFile = PR_Open(signver.options[opt_InputDataFile].arg,
162 PR_RDONLY, 0);
163 if (!contentFile) {
164 PR_fprintf(PR_STDERR,
165 "%s: unable to open \"%s\" for reading.\n",
166 progName, signver.options[opt_InputDataFile].arg);
167 goto cleanup;
168 }
169 } else
170 contentFile = PR_STDIN;
171 }
173 /* Open the input signature file. */
174 if (signver.options[opt_InputSigFile].activated &&
175 signver.options[opt_InputSigFile].arg) {
176 if (PL_strcmp("-", signver.options[opt_InputSigFile].arg)) {
177 signFile = PR_Open(signver.options[opt_InputSigFile].arg,
178 PR_RDONLY, 0);
179 if (!signFile) {
180 PR_fprintf(PR_STDERR,
181 "%s: unable to open \"%s\" for reading.\n",
182 progName, signver.options[opt_InputSigFile].arg);
183 goto cleanup;
184 }
185 }
186 }
188 if (contentFile == PR_STDIN && signFile == PR_STDIN && doVerify) {
189 PR_fprintf(PR_STDERR,
190 "%s: cannot read both content and signature from standard input\n",
191 progName);
192 goto cleanup;
193 }
195 /* Open|Create the output file. */
196 if (signver.options[opt_OutputFile].activated) {
197 outFile = fopen(signver.options[opt_OutputFile].arg, "w");
198 if (!outFile) {
199 PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for writing.\n",
200 progName, signver.options[opt_OutputFile].arg);
201 goto cleanup;
202 }
203 }
205 /* read in the input files' contents */
206 rv = SECU_ReadDERFromFile(&pkcs7der, signFile,
207 signver.options[opt_ASCII].activated, PR_FALSE);
208 if (signFile != PR_STDIN)
209 PR_Close(signFile);
210 if (rv != SECSuccess) {
211 SECU_PrintError(progName, "problem reading PKCS7 input");
212 goto cleanup;
213 }
214 if (contentFile) {
215 rv = SECU_FileToItem(&content, contentFile);
216 if (contentFile != PR_STDIN)
217 PR_Close(contentFile);
218 if (rv != SECSuccess)
219 content.data = NULL;
220 }
222 /* Signature Verification */
223 if (doVerify) {
224 SEC_PKCS7ContentInfo *cinfo;
225 SEC_PKCS7SignedData *signedData;
226 HASH_HashType digestType;
227 PRBool contentIsSigned;
229 cinfo = SEC_PKCS7DecodeItem(&pkcs7der, NULL, NULL, NULL, NULL,
230 NULL, NULL, NULL);
231 if (cinfo == NULL) {
232 PR_fprintf(PR_STDERR, "Unable to decode PKCS7 data\n");
233 goto cleanup;
234 }
235 /* below here, goto done */
237 contentIsSigned = SEC_PKCS7ContentIsSigned(cinfo);
238 if (debugInfo) {
239 PR_fprintf(PR_STDERR, "Content is%s encrypted.\n",
240 SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not");
241 }
242 if (debugInfo || !contentIsSigned) {
243 PR_fprintf(PR_STDERR, "Content is%s signed.\n",
244 contentIsSigned ? "" : " not");
245 }
247 if (!contentIsSigned)
248 goto done;
250 signedData = cinfo->content.signedData;
252 /* assume that there is only one digest algorithm for now */
253 digestType = AlgorithmToHashType(signedData->digestAlgorithms[0]);
254 if (digestType == HASH_AlgNULL) {
255 PR_fprintf(PR_STDERR, "Invalid hash algorithmID\n");
256 goto done;
257 }
258 if (content.data) {
259 SECCertUsage usage = certUsageEmailSigner;
260 SECItem digest;
261 unsigned char digestBuffer[HASH_LENGTH_MAX];
263 if (debugInfo)
264 PR_fprintf(PR_STDERR, "contentToVerify=%s\n", content.data);
266 digest.data = digestBuffer;
267 digest.len = sizeof digestBuffer;
269 if (DigestContent(&digest, &content, digestType)) {
270 SECU_PrintError(progName, "Message digest computation failure");
271 goto done;
272 }
274 if (debugInfo) {
275 unsigned int i;
276 PR_fprintf(PR_STDERR, "Data Digest=:");
277 for (i = 0; i < digest.len; i++)
278 PR_fprintf(PR_STDERR, "%02x:", digest.data[i]);
279 PR_fprintf(PR_STDERR, "\n");
280 }
282 fprintf(outFile, "signatureValid=");
283 PORT_SetError(0);
284 if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage,
285 &digest, digestType, PR_FALSE)) {
286 fprintf(outFile, "yes");
287 } else {
288 fprintf(outFile, "no");
289 if (verbose) {
290 fprintf(outFile, ":%s",
291 SECU_Strerror(PORT_GetError()));
292 }
293 }
294 fprintf(outFile, "\n");
295 result = 0;
296 }
297 done:
298 SEC_PKCS7DestroyContentInfo(cinfo);
299 }
301 if (displayAll) {
302 if (SV_PrintPKCS7ContentInfo(outFile, &pkcs7der))
303 result = 1;
304 }
306 cleanup:
307 SECITEM_FreeItem(&pkcs7der, PR_FALSE);
308 SECITEM_FreeItem(&content, PR_FALSE);
310 if (NSS_Shutdown() != SECSuccess) {
311 result = 1;
312 }
314 return result;
315 }