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 /*
6 * p7sign -- A command to create a *detached* pkcs7 signature (over a given
7 * input file).
8 */
10 #include "nspr.h"
11 #include "plgetopt.h"
12 #include "secutil.h"
13 #include "secpkcs7.h"
14 #include "cert.h"
15 #include "certdb.h"
16 #include "sechash.h" /* for HASH_GetHashObject() */
17 #include "nss.h"
18 #include "pk11func.h"
20 #if defined(XP_UNIX)
21 #include <unistd.h>
22 #endif
24 #include <stdio.h>
25 #include <string.h>
27 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
28 extern int fread(char *, size_t, size_t, FILE*);
29 extern int fwrite(char *, size_t, size_t, FILE*);
30 extern int fprintf(FILE *, char *, ...);
31 #endif
33 static secuPWData pwdata = { PW_NONE, 0 };
35 static void
36 Usage(char *progName)
37 {
38 fprintf(stderr,
39 "Usage: %s -k keyname [-d keydir] [-i input] [-o output]\n",
40 progName);
41 fprintf(stderr, "%-20s Nickname of key to use for signature\n",
42 "-k keyname");
43 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
44 "-d keydir");
45 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
46 "-i input");
47 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
48 "-o output");
49 fprintf(stderr, "%-20s Encapsulate content in signature message\n",
50 "-e");
51 fprintf(stderr, "%-20s Password to the key databse\n", "-p");
52 fprintf(stderr, "%-20s password file\n", "-f");
53 exit(-1);
54 }
56 static void
57 SignOut(void *arg, const char *buf, unsigned long len)
58 {
59 FILE *out;
61 out = (FILE*) arg;
62 fwrite (buf, len, 1, out);
63 }
65 static int
66 CreateDigest(SECItem *data, char *digestdata, unsigned int *len, unsigned int maxlen)
67 {
68 const SECHashObject *hashObj;
69 void *hashcx;
71 /* XXX probably want to extend interface to allow other hash algorithms */
72 hashObj = HASH_GetHashObject(HASH_AlgSHA1);
74 hashcx = (* hashObj->create)();
75 if (hashcx == NULL)
76 return -1;
78 (* hashObj->begin)(hashcx);
79 (* hashObj->update)(hashcx, data->data, data->len);
80 (* hashObj->end)(hashcx, (unsigned char *)digestdata, len, maxlen);
81 (* hashObj->destroy)(hashcx, PR_TRUE);
82 return 0;
83 }
85 static int
86 SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert,
87 PRBool encapsulated)
88 {
89 char digestdata[32];
90 unsigned int len;
91 SECItem digest, data2sign;
92 SEC_PKCS7ContentInfo *cinfo;
93 SECStatus rv;
95 if (outFile == NULL || inFile == NULL || cert == NULL)
96 return -1;
98 /* suck the file in */
99 if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE,
100 PR_FALSE) != SECSuccess)
101 return -1;
103 if (!encapsulated) {
104 /* unfortunately, we must create the digest ourselves */
105 /* SEC_PKCS7CreateSignedData should have a flag to not include */
106 /* the content for non-encapsulated content at encode time, but */
107 /* should always compute the hash itself */
108 if (CreateDigest(&data2sign, digestdata, &len, 32) < 0)
109 return -1;
110 digest.data = (unsigned char *)digestdata;
111 digest.len = len;
112 }
114 /* XXX Need a better way to handle that usage stuff! */
115 cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL,
116 SEC_OID_SHA1,
117 encapsulated ? NULL : &digest,
118 NULL, NULL);
119 if (cinfo == NULL)
120 return -1;
122 if (encapsulated) {
123 SEC_PKCS7SetContent(cinfo, (char *)data2sign.data, data2sign.len);
124 }
126 rv = SEC_PKCS7IncludeCertChain (cinfo, NULL);
127 if (rv != SECSuccess) {
128 SEC_PKCS7DestroyContentInfo (cinfo);
129 return -1;
130 }
132 rv = SEC_PKCS7Encode (cinfo, SignOut, outFile, NULL,
133 NULL, &pwdata);
135 SEC_PKCS7DestroyContentInfo (cinfo);
137 if (rv != SECSuccess)
138 return -1;
140 return 0;
141 }
143 int
144 main(int argc, char **argv)
145 {
146 char *progName;
147 FILE *outFile;
148 PRFileDesc *inFile;
149 char *keyName = NULL;
150 CERTCertDBHandle *certHandle;
151 CERTCertificate *cert = NULL;
152 PRBool encapsulated = PR_FALSE;
153 PLOptState *optstate;
154 PLOptStatus status;
155 SECStatus rv;
157 progName = strrchr(argv[0], '/');
158 progName = progName ? progName+1 : argv[0];
160 inFile = NULL;
161 outFile = NULL;
162 keyName = NULL;
164 /*
165 * Parse command line arguments
166 */
167 optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:f:");
168 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
169 switch (optstate->option) {
170 case '?':
171 Usage(progName);
172 break;
174 case 'e':
175 /* create a message with the signed content encapsulated */
176 encapsulated = PR_TRUE;
177 break;
179 case 'd':
180 SECU_ConfigDirectory(optstate->value);
181 break;
183 case 'i':
184 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
185 if (!inFile) {
186 fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
187 progName, optstate->value);
188 return -1;
189 }
190 break;
192 case 'k':
193 keyName = strdup(optstate->value);
194 break;
196 case 'o':
197 outFile = fopen(optstate->value, "wb");
198 if (!outFile) {
199 fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
200 progName, optstate->value);
201 return -1;
202 }
203 break;
204 case 'p':
205 pwdata.source = PW_PLAINTEXT;
206 pwdata.data = strdup (optstate->value);
207 break;
209 case 'f':
210 pwdata.source = PW_FROMFILE;
211 pwdata.data = PORT_Strdup (optstate->value);
212 break;
213 }
214 }
216 if (!keyName) Usage(progName);
218 if (!inFile) inFile = PR_STDIN;
219 if (!outFile) outFile = stdout;
221 /* Call the initialization routines */
222 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
223 rv = NSS_Init(SECU_ConfigDirectory(NULL));
224 if (rv != SECSuccess) {
225 SECU_PrintPRandOSError(progName);
226 goto loser;
227 }
229 PK11_SetPasswordFunc(SECU_GetModulePassword);
231 /* open cert database */
232 certHandle = CERT_GetDefaultCertDB();
233 if (certHandle == NULL) {
234 rv = SECFailure;
235 goto loser;
236 }
238 /* find cert */
239 cert = CERT_FindCertByNickname(certHandle, keyName);
240 if (cert == NULL) {
241 SECU_PrintError(progName,
242 "the corresponding cert for key \"%s\" does not exist",
243 keyName);
244 rv = SECFailure;
245 goto loser;
246 }
248 if (SignFile(outFile, inFile, cert, encapsulated)) {
249 SECU_PrintError(progName, "problem signing data");
250 rv = SECFailure;
251 goto loser;
252 }
254 loser:
255 if (pwdata.data) {
256 PORT_Free(pwdata.data);
257 }
258 if (keyName) {
259 PORT_Free(keyName);
260 }
261 if (cert) {
262 CERT_DestroyCertificate(cert);
263 }
264 if (inFile && inFile != PR_STDIN) {
265 PR_Close(inFile);
266 }
267 if (outFile && outFile != stdout) {
268 fclose(outFile);
269 }
270 if (NSS_Shutdown() != SECSuccess) {
271 SECU_PrintError(progName, "NSS shutdown:");
272 exit(1);
273 }
275 return (rv != SECSuccess);
276 }