Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 * Test program for SDR (Secret Decoder Ring) functions.
7 */
9 #include "nspr.h"
10 #include "string.h"
11 #include "nss.h"
12 #include "secutil.h"
13 #include "cert.h"
14 #include "pk11func.h"
16 #include "plgetopt.h"
17 #include "pk11sdr.h"
18 #include "nssb64.h"
20 #define DEFAULT_VALUE "Test"
21 static const char default_value[] = { DEFAULT_VALUE };
23 PRFileDesc *pr_stderr;
24 PRBool verbose = PR_FALSE;
26 static void
27 synopsis (char *program_name)
28 {
29 PR_fprintf (pr_stderr,
30 "Usage: %s [<common>] -i <input-file>\n"
31 " %s [<common>] -o <output-file>\n"
32 " <common> [-d dir] [-v] [-t text] [-a] [-f pwfile | -p pwd]\n",
33 program_name, program_name);
34 }
36 static void
37 short_usage (char *program_name)
38 {
39 PR_fprintf (pr_stderr,
40 "Type %s -H for more detailed descriptions\n",
41 program_name);
42 synopsis (program_name);
43 }
46 static void
47 long_usage (char *program_name)
48 {
49 synopsis (program_name);
50 PR_fprintf (pr_stderr, "\nSecret Decoder Test:\n");
51 PR_fprintf (pr_stderr,
52 " %-13s Read encrypted data from \"file\"\n",
53 "-i file");
54 PR_fprintf (pr_stderr,
55 " %-13s Write newly generated encrypted data to \"file\"\n",
56 "-o file");
57 PR_fprintf (pr_stderr,
58 " %-13s Use \"text\" as the plaintext for encryption and verification\n",
59 "-t text");
60 PR_fprintf (pr_stderr,
61 " %-13s Find security databases in \"dbdir\"\n",
62 "-d dbdir");
63 PR_fprintf (pr_stderr,
64 " %-13s read the password from \"pwfile\"\n",
65 "-f pwfile");
66 PR_fprintf (pr_stderr,
67 " %-13s supply \"password\" on the command line\n",
68 "-p password");
69 }
71 int
72 readStdin(SECItem * result)
73 {
74 int bufsize = 0;
75 int cc;
76 int wanted = 8192;
78 result->len = 0;
79 result->data = NULL;
80 do {
81 if (bufsize < wanted) {
82 unsigned char * tmpData = (unsigned char *)PR_Realloc(result->data, wanted);
83 if (!tmpData) {
84 if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n");
85 return -1;
86 }
87 result->data = tmpData;
88 bufsize = wanted;
89 }
90 cc = PR_Read(PR_STDIN, result->data + result->len, bufsize - result->len);
91 if (cc > 0) {
92 result->len += (unsigned)cc;
93 if (result->len >= wanted)
94 wanted *= 2;
95 }
96 } while (cc > 0);
97 return cc;
98 }
100 int
101 readInputFile(const char * filename, SECItem * result)
102 {
103 PRFileDesc *file /* = PR_OpenFile(input_file, 0) */;
104 PRFileInfo info;
105 PRStatus s;
106 PRInt32 count;
107 int retval = -1;
109 file = PR_Open(filename, PR_RDONLY, 0);
110 if (!file) {
111 if (verbose) PR_fprintf(pr_stderr, "Open of file %s failed\n", filename);
112 goto loser;
113 }
115 s = PR_GetOpenFileInfo(file, &info);
116 if (s != PR_SUCCESS) {
117 if (verbose) PR_fprintf(pr_stderr, "File info operation failed\n");
118 goto file_loser;
119 }
121 result->len = info.size;
122 result->data = (unsigned char *)PR_Malloc(result->len);
123 if (!result->data) {
124 if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n");
125 goto file_loser;
126 }
128 count = PR_Read(file, result->data, result->len);
129 if (count != result->len) {
130 if (verbose) PR_fprintf(pr_stderr, "Read failed\n");
131 goto file_loser;
132 }
133 retval = 0;
135 file_loser:
136 PR_Close(file);
137 loser:
138 return retval;
139 }
141 int
142 main (int argc, char **argv)
143 {
144 int retval = 0; /* 0 - test succeeded. -1 - test failed */
145 SECStatus rv;
146 PLOptState *optstate;
147 PLOptStatus optstatus;
148 char *program_name;
149 const char *input_file = NULL; /* read encrypted data from here (or create) */
150 const char *output_file = NULL; /* write new encrypted data here */
151 const char *value = default_value; /* Use this for plaintext */
152 SECItem data;
153 SECItem result = {0, 0, 0};
154 SECItem text;
155 PRBool ascii = PR_FALSE;
156 secuPWData pwdata = { PW_NONE, 0 };
158 pr_stderr = PR_STDERR;
159 result.data = 0;
160 text.data = 0; text.len = 0;
162 program_name = PL_strrchr(argv[0], '/');
163 program_name = program_name ? (program_name + 1) : argv[0];
165 optstate = PL_CreateOptState (argc, argv, "?Had:i:o:t:vf:p:");
166 if (optstate == NULL) {
167 SECU_PrintError (program_name, "PL_CreateOptState failed");
168 return -1;
169 }
171 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
172 switch (optstate->option) {
173 case '?':
174 short_usage (program_name);
175 return retval;
177 case 'H':
178 long_usage (program_name);
179 return retval;
181 case 'a':
182 ascii = PR_TRUE;
183 break;
185 case 'd':
186 SECU_ConfigDirectory(optstate->value);
187 break;
189 case 'i':
190 input_file = optstate->value;
191 break;
193 case 'o':
194 output_file = optstate->value;
195 break;
197 case 't':
198 value = optstate->value;
199 break;
201 case 'f':
202 if (pwdata.data) {
203 PORT_Free(pwdata.data);
204 short_usage(program_name);
205 return -1;
206 }
207 pwdata.source = PW_FROMFILE;
208 pwdata.data = PORT_Strdup(optstate->value);
209 break;
211 case 'p':
212 if (pwdata.data) {
213 PORT_Free(pwdata.data);
214 short_usage(program_name);
215 return -1;
216 }
217 pwdata.source = PW_PLAINTEXT;
218 pwdata.data = PORT_Strdup(optstate->value);
219 break;
221 case 'v':
222 verbose = PR_TRUE;
223 break;
224 }
225 }
226 PL_DestroyOptState(optstate);
227 if (optstatus == PL_OPT_BAD) {
228 short_usage (program_name);
229 return -1;
230 }
231 if (!output_file && !input_file && value == default_value) {
232 short_usage (program_name);
233 PR_fprintf (pr_stderr, "Must specify at least one of -t, -i or -o \n");
234 return -1;
235 }
237 /*
238 * Initialize the Security libraries.
239 */
240 PK11_SetPasswordFunc(SECU_GetModulePassword);
242 if (output_file) {
243 rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
244 } else {
245 rv = NSS_Init(SECU_ConfigDirectory(NULL));
246 }
247 if (rv != SECSuccess) {
248 SECU_PrintError(program_name, "NSS_Init failed");
249 retval = -1;
250 goto prdone;
251 }
253 /* Convert value into an item */
254 data.data = (unsigned char *)value;
255 data.len = strlen(value);
257 /* Get the encrypted result, either from the input file
258 * or from encrypting the plaintext value
259 */
260 if (input_file)
261 {
262 if (verbose) printf("Reading data from %s\n", input_file);
264 if (!strcmp(input_file, "-")) {
265 retval = readStdin(&result);
266 ascii = PR_TRUE;
267 } else {
268 retval = readInputFile(input_file, &result);
269 }
270 if (retval != 0)
271 goto loser;
272 if (ascii) {
273 /* input was base64 encoded. Decode it. */
274 SECItem newResult = {0, 0, 0};
275 SECItem *ok = NSSBase64_DecodeBuffer(NULL, &newResult,
276 (const char *)result.data, result.len);
277 if (!ok) {
278 SECU_PrintError(program_name, "Base 64 decode failed");
279 retval = -1;
280 goto loser;
281 }
282 SECITEM_ZfreeItem(&result, PR_FALSE);
283 result = *ok;
284 }
285 }
286 else
287 {
288 SECItem keyid = { 0, 0, 0 };
289 SECItem outBuf = { 0, 0, 0 };
290 PK11SlotInfo *slot = NULL;
292 /* sigh, initialize the key database */
293 slot = PK11_GetInternalKeySlot();
294 if (slot && PK11_NeedUserInit(slot)) {
295 switch (pwdata.source) {
296 case PW_FROMFILE:
297 rv = SECU_ChangePW(slot, 0, pwdata.data);
298 break;
299 case PW_PLAINTEXT:
300 rv = SECU_ChangePW(slot, pwdata.data, 0);
301 break;
302 default:
303 rv = SECU_ChangePW(slot, "", 0);
304 break;
305 }
306 if (rv != SECSuccess) {
307 SECU_PrintError(program_name, "Failed to initialize slot \"%s\"",
308 PK11_GetSlotName(slot));
309 return SECFailure;
310 }
311 }
312 if (slot) {
313 PK11_FreeSlot(slot);
314 }
316 rv = PK11SDR_Encrypt(&keyid, &data, &result, &pwdata);
317 if (rv != SECSuccess) {
318 if (verbose)
319 SECU_PrintError(program_name, "Encrypt operation failed\n");
320 retval = -1;
321 goto loser;
322 }
324 if (verbose) printf("Encrypted result is %d bytes long\n", result.len);
326 if (!strcmp(output_file, "-")) {
327 ascii = PR_TRUE;
328 }
330 if (ascii) {
331 /* base64 encode output. */
332 char * newResult = NSSBase64_EncodeItem(NULL, NULL, 0, &result);
333 if (!newResult) {
334 SECU_PrintError(program_name, "Base 64 encode failed\n");
335 retval = -1;
336 goto loser;
337 }
338 outBuf.data = (unsigned char *)newResult;
339 outBuf.len = strlen(newResult);
340 if (verbose)
341 printf("Base 64 encoded result is %d bytes long\n", outBuf.len);
342 } else {
343 outBuf = result;
344 }
346 /* -v printf("Result is %.*s\n", text.len, text.data); */
347 if (output_file) {
348 PRFileDesc *file;
349 PRInt32 count;
351 if (verbose) printf("Writing result to %s\n", output_file);
352 if (!strcmp(output_file, "-")) {
353 file = PR_STDOUT;
354 } else {
355 /* Write to file */
356 file = PR_Open(output_file, PR_CREATE_FILE|PR_WRONLY, 0666);
357 }
358 if (!file) {
359 if (verbose)
360 SECU_PrintError(program_name,
361 "Open of output file %s failed\n",
362 output_file);
363 retval = -1;
364 goto loser;
365 }
367 count = PR_Write(file, outBuf.data, outBuf.len);
369 if (file == PR_STDOUT) {
370 puts("");
371 } else {
372 PR_Close(file);
373 }
375 if (count != outBuf.len) {
376 if (verbose) SECU_PrintError(program_name, "Write failed\n");
377 retval = -1;
378 goto loser;
379 }
380 if (ascii) {
381 free(outBuf.data);
382 }
383 }
384 }
386 /* Decrypt the value */
387 rv = PK11SDR_Decrypt(&result, &text, &pwdata);
388 if (rv != SECSuccess) {
389 if (verbose) SECU_PrintError(program_name, "Decrypt operation failed\n");
390 retval = -1;
391 goto loser;
392 }
394 if (verbose) printf("Decrypted result is \"%.*s\"\n", text.len, text.data);
396 /* Compare to required value */
397 if (text.len != data.len || memcmp(data.data, text.data, text.len) != 0)
398 {
399 if (verbose) PR_fprintf(pr_stderr, "Comparison failed\n");
400 retval = -1;
401 goto loser;
402 }
404 loser:
405 if (text.data) SECITEM_ZfreeItem(&text, PR_FALSE);
406 if (result.data) SECITEM_ZfreeItem(&result, PR_FALSE);
407 if (NSS_Shutdown() != SECSuccess) {
408 exit(1);
409 }
411 prdone:
412 PR_Cleanup ();
413 if (pwdata.data) {
414 PORT_Free(pwdata.data);
415 }
416 return retval;
417 }