|
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 #include "nssb64.h" |
|
16 |
|
17 #include "plgetopt.h" |
|
18 #include "pk11sdr.h" |
|
19 |
|
20 #define DEFAULT_VALUE "Test" |
|
21 |
|
22 static void |
|
23 synopsis (char *program_name) |
|
24 { |
|
25 PRFileDesc *pr_stderr; |
|
26 |
|
27 pr_stderr = PR_STDERR; |
|
28 PR_fprintf (pr_stderr, |
|
29 "Usage:\t%s [-i <input-file>] [-o <output-file>] [-d <dir>]\n" |
|
30 " \t[-l logfile] [-p pwd] [-f pwfile]\n", program_name); |
|
31 } |
|
32 |
|
33 |
|
34 static void |
|
35 short_usage (char *program_name) |
|
36 { |
|
37 PR_fprintf (PR_STDERR, |
|
38 "Type %s -H for more detailed descriptions\n", |
|
39 program_name); |
|
40 synopsis (program_name); |
|
41 } |
|
42 |
|
43 |
|
44 static void |
|
45 long_usage (char *program_name) |
|
46 { |
|
47 PRFileDesc *pr_stderr; |
|
48 |
|
49 pr_stderr = PR_STDERR; |
|
50 synopsis (program_name); |
|
51 PR_fprintf (pr_stderr, "\nDecode encrypted passwords (and other data).\n"); |
|
52 PR_fprintf (pr_stderr, |
|
53 "This program reads in standard configuration files looking\n" |
|
54 "for base 64 encoded data. Data that looks like it's base 64 encode\n" |
|
55 "is decoded an passed to the NSS SDR code. If the decode and decrypt\n" |
|
56 "is successful, then decrypted data is outputted in place of the\n" |
|
57 "original base 64 data. If the decode or decrypt fails, the original\n" |
|
58 "data is written and the reason for failure is logged to the \n" |
|
59 "optional logfile.\n"); |
|
60 PR_fprintf (pr_stderr, |
|
61 " %-13s Read stream including encrypted data from " |
|
62 "\"read_file\"\n", |
|
63 "-i read_file"); |
|
64 PR_fprintf (pr_stderr, |
|
65 " %-13s Write results to \"write_file\"\n", |
|
66 "-o write_file"); |
|
67 PR_fprintf (pr_stderr, |
|
68 " %-13s Find security databases in \"dbdir\"\n", |
|
69 "-d dbdir"); |
|
70 PR_fprintf (pr_stderr, |
|
71 " %-13s Log failed decrypt/decode attempts to \"log_file\"\n", |
|
72 "-l log_file"); |
|
73 PR_fprintf (pr_stderr, |
|
74 " %-13s Token password\n", |
|
75 "-p pwd"); |
|
76 PR_fprintf (pr_stderr, |
|
77 " %-13s Password file\n", |
|
78 "-f pwfile"); |
|
79 } |
|
80 |
|
81 /* |
|
82 * base64 table only used to identify the end of a base64 string |
|
83 */ |
|
84 static unsigned char b64[256] = { |
|
85 /* 00: */ 0, 0, 0, 0, 0, 0, 0, 0, |
|
86 /* 08: */ 0, 0, 0, 0, 0, 0, 0, 0, |
|
87 /* 10: */ 0, 0, 0, 0, 0, 0, 0, 0, |
|
88 /* 18: */ 0, 0, 0, 0, 0, 0, 0, 0, |
|
89 /* 20: */ 0, 0, 0, 0, 0, 0, 0, 0, |
|
90 /* 28: */ 0, 0, 0, 1, 0, 0, 0, 1, |
|
91 /* 30: */ 1, 1, 1, 1, 1, 1, 1, 1, |
|
92 /* 38: */ 1, 1, 0, 0, 0, 0, 0, 0, |
|
93 /* 40: */ 0, 1, 1, 1, 1, 1, 1, 1, |
|
94 /* 48: */ 1, 1, 1, 1, 1, 1, 1, 1, |
|
95 /* 50: */ 1, 1, 1, 1, 1, 1, 1, 1, |
|
96 /* 58: */ 1, 1, 1, 0, 0, 0, 0, 0, |
|
97 /* 60: */ 0, 1, 1, 1, 1, 1, 1, 1, |
|
98 /* 68: */ 1, 1, 1, 1, 1, 1, 1, 1, |
|
99 /* 70: */ 1, 1, 1, 1, 1, 1, 1, 1, |
|
100 /* 78: */ 1, 1, 1, 0, 0, 0, 0, 0, |
|
101 }; |
|
102 |
|
103 enum { |
|
104 false = 0, |
|
105 true = 1 |
|
106 } bool; |
|
107 |
|
108 #define isatobchar(c) (b64[c]) |
|
109 |
|
110 #define MAX_STRING 8192 |
|
111 |
|
112 int |
|
113 isBase64(char *inString) |
|
114 { |
|
115 unsigned int i; |
|
116 unsigned char c; |
|
117 |
|
118 for (i = 0; (c = inString[i]) != 0 && isatobchar(c); ++i) |
|
119 ; |
|
120 if (c == '=') { |
|
121 while ((c = inString[++i]) == '=') |
|
122 ; /* skip trailing '=' characters */ |
|
123 } |
|
124 if (c && c != '\n' && c != '\r') |
|
125 return false; |
|
126 if (i == 0 || i % 4) |
|
127 return false; |
|
128 return true; |
|
129 } |
|
130 |
|
131 void |
|
132 doDecrypt(char * dataString, FILE *outFile, FILE *logFile, secuPWData *pwdata) |
|
133 { |
|
134 int strLen = strlen(dataString); |
|
135 SECItem *decoded = NSSBase64_DecodeBuffer(NULL, NULL, dataString, strLen); |
|
136 SECStatus rv; |
|
137 int err; |
|
138 SECItem result = { siBuffer, NULL, 0 }; |
|
139 |
|
140 if ((decoded == NULL) || (decoded->len == 0)) { |
|
141 if (logFile) { |
|
142 err = PORT_GetError(); |
|
143 fprintf(logFile,"Base 64 decode failed on <%s>\n", dataString); |
|
144 fprintf(logFile," Error %d: %s\n", err, SECU_Strerror(err)); |
|
145 } |
|
146 fputs(dataString, outFile); |
|
147 if (decoded) |
|
148 SECITEM_FreeItem(decoded, PR_TRUE); |
|
149 return; |
|
150 } |
|
151 |
|
152 rv = PK11SDR_Decrypt(decoded, &result, pwdata); |
|
153 SECITEM_ZfreeItem(decoded, PR_TRUE); |
|
154 if (rv == SECSuccess) { |
|
155 /* result buffer has no extra space for a NULL */ |
|
156 fprintf(outFile, "Decrypted: \"%.*s\"\n", result.len, result.data); |
|
157 SECITEM_ZfreeItem(&result, PR_FALSE); |
|
158 return; |
|
159 } |
|
160 /* Encryption failed. output raw input. */ |
|
161 if (logFile) { |
|
162 err = PORT_GetError(); |
|
163 fprintf(logFile,"SDR decrypt failed on <%s>\n", dataString); |
|
164 fprintf(logFile," Error %d: %s\n", err, SECU_Strerror(err)); |
|
165 } |
|
166 fputs(dataString,outFile); |
|
167 } |
|
168 |
|
169 void |
|
170 doDecode(char * dataString, FILE *outFile, FILE *logFile) |
|
171 { |
|
172 int strLen = strlen(dataString + 1); |
|
173 SECItem *decoded; |
|
174 |
|
175 decoded = NSSBase64_DecodeBuffer(NULL, NULL, dataString + 1, strLen); |
|
176 if ((decoded == NULL) || (decoded->len == 0)) { |
|
177 if (logFile) { |
|
178 int err = PORT_GetError(); |
|
179 fprintf(logFile,"Base 64 decode failed on <%s>\n", dataString + 1); |
|
180 fprintf(logFile," Error %d: %s\n", err, SECU_Strerror(err)); |
|
181 } |
|
182 fputs(dataString, outFile); |
|
183 if (decoded) |
|
184 SECITEM_FreeItem(decoded, PR_TRUE); |
|
185 return; |
|
186 } |
|
187 fprintf(outFile, "Decoded: \"%.*s\"\n", decoded->len, decoded->data); |
|
188 SECITEM_ZfreeItem(decoded, PR_TRUE); |
|
189 } |
|
190 |
|
191 char dataString[MAX_STRING + 1]; |
|
192 |
|
193 int |
|
194 main (int argc, char **argv) |
|
195 { |
|
196 int retval = 0; /* 0 - test succeeded. -1 - test failed */ |
|
197 SECStatus rv; |
|
198 PLOptState *optstate; |
|
199 char *program_name; |
|
200 char *input_file = NULL; /* read encrypted data from here (or create) */ |
|
201 char *output_file = NULL; /* write new encrypted data here */ |
|
202 char *log_file = NULL; /* write new encrypted data here */ |
|
203 FILE *inFile = stdin; |
|
204 FILE *outFile = stdout; |
|
205 FILE *logFile = NULL; |
|
206 PLOptStatus optstatus; |
|
207 secuPWData pwdata = { PW_NONE, NULL }; |
|
208 |
|
209 |
|
210 program_name = PL_strrchr(argv[0], '/'); |
|
211 program_name = program_name ? (program_name + 1) : argv[0]; |
|
212 |
|
213 optstate = PL_CreateOptState (argc, argv, "Hd:f:i:o:l:p:?"); |
|
214 if (optstate == NULL) { |
|
215 SECU_PrintError (program_name, "PL_CreateOptState failed"); |
|
216 return 1; |
|
217 } |
|
218 |
|
219 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
|
220 switch (optstate->option) { |
|
221 case '?': |
|
222 short_usage (program_name); |
|
223 return 1; |
|
224 |
|
225 case 'H': |
|
226 long_usage (program_name); |
|
227 return 1; |
|
228 |
|
229 case 'd': |
|
230 SECU_ConfigDirectory(optstate->value); |
|
231 break; |
|
232 |
|
233 case 'i': |
|
234 input_file = PL_strdup(optstate->value); |
|
235 break; |
|
236 |
|
237 case 'o': |
|
238 output_file = PL_strdup(optstate->value); |
|
239 break; |
|
240 |
|
241 case 'l': |
|
242 log_file = PL_strdup(optstate->value); |
|
243 break; |
|
244 |
|
245 case 'f': |
|
246 pwdata.source = PW_FROMFILE; |
|
247 pwdata.data = PL_strdup(optstate->value); |
|
248 break; |
|
249 |
|
250 case 'p': |
|
251 pwdata.source = PW_PLAINTEXT; |
|
252 pwdata.data = PL_strdup(optstate->value); |
|
253 break; |
|
254 |
|
255 } |
|
256 } |
|
257 PL_DestroyOptState(optstate); |
|
258 if (optstatus == PL_OPT_BAD) { |
|
259 short_usage (program_name); |
|
260 return 1; |
|
261 } |
|
262 |
|
263 if (input_file) { |
|
264 inFile = fopen(input_file,"r"); |
|
265 if (inFile == NULL) { |
|
266 perror(input_file); |
|
267 return 1; |
|
268 } |
|
269 PR_Free(input_file); |
|
270 } |
|
271 if (output_file) { |
|
272 outFile = fopen(output_file,"w+"); |
|
273 if (outFile == NULL) { |
|
274 perror(output_file); |
|
275 return 1; |
|
276 } |
|
277 PR_Free(output_file); |
|
278 } |
|
279 if (log_file) { |
|
280 if (log_file[0] == '-') |
|
281 logFile = stderr; |
|
282 else |
|
283 logFile = fopen(log_file,"w+"); |
|
284 if (logFile == NULL) { |
|
285 perror(log_file); |
|
286 return 1; |
|
287 } |
|
288 PR_Free(log_file); |
|
289 } |
|
290 |
|
291 /* |
|
292 * Initialize the Security libraries. |
|
293 */ |
|
294 PK11_SetPasswordFunc(SECU_GetModulePassword); |
|
295 rv = NSS_Init(SECU_ConfigDirectory(NULL)); |
|
296 if (rv != SECSuccess) { |
|
297 SECU_PrintError (program_name, "NSS_Init failed"); |
|
298 retval = 1; |
|
299 goto prdone; |
|
300 } |
|
301 |
|
302 /* Get the encrypted result, either from the input file |
|
303 * or from encrypting the plaintext value |
|
304 */ |
|
305 while (fgets(dataString, sizeof dataString, inFile)) { |
|
306 unsigned char c = dataString[0]; |
|
307 |
|
308 if (c == 'M' && isBase64(dataString)) { |
|
309 doDecrypt(dataString, outFile, logFile, &pwdata); |
|
310 } else if (c == '~' && isBase64(dataString + 1)) { |
|
311 doDecode(dataString, outFile, logFile); |
|
312 } else { |
|
313 fputs(dataString, outFile); |
|
314 } |
|
315 } |
|
316 if (pwdata.data) |
|
317 PR_Free(pwdata.data); |
|
318 |
|
319 fclose(outFile); |
|
320 fclose(inFile); |
|
321 if (logFile && logFile != stderr) { |
|
322 fclose(logFile); |
|
323 } |
|
324 |
|
325 if (NSS_Shutdown() != SECSuccess) { |
|
326 SECU_PrintError (program_name, "NSS_Shutdown failed"); |
|
327 exit(1); |
|
328 } |
|
329 |
|
330 prdone: |
|
331 PR_Cleanup (); |
|
332 return retval; |
|
333 } |