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