|
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/. */ |
|
4 |
|
5 /* |
|
6 * Test program for SDR (Secret Decoder Ring) functions. |
|
7 */ |
|
8 |
|
9 #include "nspr.h" |
|
10 #include "string.h" |
|
11 #include "nss.h" |
|
12 #include "secutil.h" |
|
13 #include "cert.h" |
|
14 #include "pk11func.h" |
|
15 |
|
16 #include "plgetopt.h" |
|
17 #include "pk11sdr.h" |
|
18 #include "nssb64.h" |
|
19 |
|
20 #define DEFAULT_VALUE "Test" |
|
21 static const char default_value[] = { DEFAULT_VALUE }; |
|
22 |
|
23 PRFileDesc *pr_stderr; |
|
24 PRBool verbose = PR_FALSE; |
|
25 |
|
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 } |
|
35 |
|
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 } |
|
44 |
|
45 |
|
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 } |
|
70 |
|
71 int |
|
72 readStdin(SECItem * result) |
|
73 { |
|
74 int bufsize = 0; |
|
75 int cc; |
|
76 int wanted = 8192; |
|
77 |
|
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 } |
|
99 |
|
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; |
|
108 |
|
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 } |
|
114 |
|
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 } |
|
120 |
|
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 } |
|
127 |
|
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; |
|
134 |
|
135 file_loser: |
|
136 PR_Close(file); |
|
137 loser: |
|
138 return retval; |
|
139 } |
|
140 |
|
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 }; |
|
157 |
|
158 pr_stderr = PR_STDERR; |
|
159 result.data = 0; |
|
160 text.data = 0; text.len = 0; |
|
161 |
|
162 program_name = PL_strrchr(argv[0], '/'); |
|
163 program_name = program_name ? (program_name + 1) : argv[0]; |
|
164 |
|
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 } |
|
170 |
|
171 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
|
172 switch (optstate->option) { |
|
173 case '?': |
|
174 short_usage (program_name); |
|
175 return retval; |
|
176 |
|
177 case 'H': |
|
178 long_usage (program_name); |
|
179 return retval; |
|
180 |
|
181 case 'a': |
|
182 ascii = PR_TRUE; |
|
183 break; |
|
184 |
|
185 case 'd': |
|
186 SECU_ConfigDirectory(optstate->value); |
|
187 break; |
|
188 |
|
189 case 'i': |
|
190 input_file = optstate->value; |
|
191 break; |
|
192 |
|
193 case 'o': |
|
194 output_file = optstate->value; |
|
195 break; |
|
196 |
|
197 case 't': |
|
198 value = optstate->value; |
|
199 break; |
|
200 |
|
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; |
|
210 |
|
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; |
|
220 |
|
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 } |
|
236 |
|
237 /* |
|
238 * Initialize the Security libraries. |
|
239 */ |
|
240 PK11_SetPasswordFunc(SECU_GetModulePassword); |
|
241 |
|
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 } |
|
252 |
|
253 /* Convert value into an item */ |
|
254 data.data = (unsigned char *)value; |
|
255 data.len = strlen(value); |
|
256 |
|
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); |
|
263 |
|
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; |
|
291 |
|
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 } |
|
315 |
|
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 } |
|
323 |
|
324 if (verbose) printf("Encrypted result is %d bytes long\n", result.len); |
|
325 |
|
326 if (!strcmp(output_file, "-")) { |
|
327 ascii = PR_TRUE; |
|
328 } |
|
329 |
|
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 } |
|
345 |
|
346 /* -v printf("Result is %.*s\n", text.len, text.data); */ |
|
347 if (output_file) { |
|
348 PRFileDesc *file; |
|
349 PRInt32 count; |
|
350 |
|
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 } |
|
366 |
|
367 count = PR_Write(file, outBuf.data, outBuf.len); |
|
368 |
|
369 if (file == PR_STDOUT) { |
|
370 puts(""); |
|
371 } else { |
|
372 PR_Close(file); |
|
373 } |
|
374 |
|
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 } |
|
385 |
|
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 } |
|
393 |
|
394 if (verbose) printf("Decrypted result is \"%.*s\"\n", text.len, text.data); |
|
395 |
|
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 } |
|
403 |
|
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 } |
|
410 |
|
411 prdone: |
|
412 PR_Cleanup (); |
|
413 if (pwdata.data) { |
|
414 PORT_Free(pwdata.data); |
|
415 } |
|
416 return retval; |
|
417 } |