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