michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * Test program for SDR (Secret Decoder Ring) functions. michael@0: */ michael@0: michael@0: #include "nspr.h" michael@0: #include "string.h" michael@0: #include "nss.h" michael@0: #include "secutil.h" michael@0: #include "cert.h" michael@0: #include "pk11func.h" michael@0: #include "nssb64.h" michael@0: michael@0: #include "plgetopt.h" michael@0: #include "pk11sdr.h" michael@0: michael@0: #define DEFAULT_VALUE "Test" michael@0: michael@0: static void michael@0: synopsis (char *program_name) michael@0: { michael@0: PRFileDesc *pr_stderr; michael@0: michael@0: pr_stderr = PR_STDERR; michael@0: PR_fprintf (pr_stderr, michael@0: "Usage:\t%s [-i ] [-o ] [-d ]\n" michael@0: " \t[-l logfile] [-p pwd] [-f pwfile]\n", program_name); michael@0: } michael@0: michael@0: michael@0: static void michael@0: short_usage (char *program_name) michael@0: { michael@0: PR_fprintf (PR_STDERR, michael@0: "Type %s -H for more detailed descriptions\n", michael@0: program_name); michael@0: synopsis (program_name); michael@0: } michael@0: michael@0: michael@0: static void michael@0: long_usage (char *program_name) michael@0: { michael@0: PRFileDesc *pr_stderr; michael@0: michael@0: pr_stderr = PR_STDERR; michael@0: synopsis (program_name); michael@0: PR_fprintf (pr_stderr, "\nDecode encrypted passwords (and other data).\n"); michael@0: PR_fprintf (pr_stderr, michael@0: "This program reads in standard configuration files looking\n" michael@0: "for base 64 encoded data. Data that looks like it's base 64 encode\n" michael@0: "is decoded an passed to the NSS SDR code. If the decode and decrypt\n" michael@0: "is successful, then decrypted data is outputted in place of the\n" michael@0: "original base 64 data. If the decode or decrypt fails, the original\n" michael@0: "data is written and the reason for failure is logged to the \n" michael@0: "optional logfile.\n"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Read stream including encrypted data from " michael@0: "\"read_file\"\n", michael@0: "-i read_file"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Write results to \"write_file\"\n", michael@0: "-o write_file"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Find security databases in \"dbdir\"\n", michael@0: "-d dbdir"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Log failed decrypt/decode attempts to \"log_file\"\n", michael@0: "-l log_file"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Token password\n", michael@0: "-p pwd"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Password file\n", michael@0: "-f pwfile"); michael@0: } michael@0: michael@0: /* michael@0: * base64 table only used to identify the end of a base64 string michael@0: */ michael@0: static unsigned char b64[256] = { michael@0: /* 00: */ 0, 0, 0, 0, 0, 0, 0, 0, michael@0: /* 08: */ 0, 0, 0, 0, 0, 0, 0, 0, michael@0: /* 10: */ 0, 0, 0, 0, 0, 0, 0, 0, michael@0: /* 18: */ 0, 0, 0, 0, 0, 0, 0, 0, michael@0: /* 20: */ 0, 0, 0, 0, 0, 0, 0, 0, michael@0: /* 28: */ 0, 0, 0, 1, 0, 0, 0, 1, michael@0: /* 30: */ 1, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 38: */ 1, 1, 0, 0, 0, 0, 0, 0, michael@0: /* 40: */ 0, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 48: */ 1, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 50: */ 1, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 58: */ 1, 1, 1, 0, 0, 0, 0, 0, michael@0: /* 60: */ 0, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 68: */ 1, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 70: */ 1, 1, 1, 1, 1, 1, 1, 1, michael@0: /* 78: */ 1, 1, 1, 0, 0, 0, 0, 0, michael@0: }; michael@0: michael@0: enum { michael@0: false = 0, michael@0: true = 1 michael@0: } bool; michael@0: michael@0: #define isatobchar(c) (b64[c]) michael@0: michael@0: #define MAX_STRING 8192 michael@0: michael@0: int michael@0: isBase64(char *inString) michael@0: { michael@0: unsigned int i; michael@0: unsigned char c; michael@0: michael@0: for (i = 0; (c = inString[i]) != 0 && isatobchar(c); ++i) michael@0: ; michael@0: if (c == '=') { michael@0: while ((c = inString[++i]) == '=') michael@0: ; /* skip trailing '=' characters */ michael@0: } michael@0: if (c && c != '\n' && c != '\r') michael@0: return false; michael@0: if (i == 0 || i % 4) michael@0: return false; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: doDecrypt(char * dataString, FILE *outFile, FILE *logFile, secuPWData *pwdata) michael@0: { michael@0: int strLen = strlen(dataString); michael@0: SECItem *decoded = NSSBase64_DecodeBuffer(NULL, NULL, dataString, strLen); michael@0: SECStatus rv; michael@0: int err; michael@0: SECItem result = { siBuffer, NULL, 0 }; michael@0: michael@0: if ((decoded == NULL) || (decoded->len == 0)) { michael@0: if (logFile) { michael@0: err = PORT_GetError(); michael@0: fprintf(logFile,"Base 64 decode failed on <%s>\n", dataString); michael@0: fprintf(logFile," Error %d: %s\n", err, SECU_Strerror(err)); michael@0: } michael@0: fputs(dataString, outFile); michael@0: if (decoded) michael@0: SECITEM_FreeItem(decoded, PR_TRUE); michael@0: return; michael@0: } michael@0: michael@0: rv = PK11SDR_Decrypt(decoded, &result, pwdata); michael@0: SECITEM_ZfreeItem(decoded, PR_TRUE); michael@0: if (rv == SECSuccess) { michael@0: /* result buffer has no extra space for a NULL */ michael@0: fprintf(outFile, "Decrypted: \"%.*s\"\n", result.len, result.data); michael@0: SECITEM_ZfreeItem(&result, PR_FALSE); michael@0: return; michael@0: } michael@0: /* Encryption failed. output raw input. */ michael@0: if (logFile) { michael@0: err = PORT_GetError(); michael@0: fprintf(logFile,"SDR decrypt failed on <%s>\n", dataString); michael@0: fprintf(logFile," Error %d: %s\n", err, SECU_Strerror(err)); michael@0: } michael@0: fputs(dataString,outFile); michael@0: } michael@0: michael@0: void michael@0: doDecode(char * dataString, FILE *outFile, FILE *logFile) michael@0: { michael@0: int strLen = strlen(dataString + 1); michael@0: SECItem *decoded; michael@0: michael@0: decoded = NSSBase64_DecodeBuffer(NULL, NULL, dataString + 1, strLen); michael@0: if ((decoded == NULL) || (decoded->len == 0)) { michael@0: if (logFile) { michael@0: int err = PORT_GetError(); michael@0: fprintf(logFile,"Base 64 decode failed on <%s>\n", dataString + 1); michael@0: fprintf(logFile," Error %d: %s\n", err, SECU_Strerror(err)); michael@0: } michael@0: fputs(dataString, outFile); michael@0: if (decoded) michael@0: SECITEM_FreeItem(decoded, PR_TRUE); michael@0: return; michael@0: } michael@0: fprintf(outFile, "Decoded: \"%.*s\"\n", decoded->len, decoded->data); michael@0: SECITEM_ZfreeItem(decoded, PR_TRUE); michael@0: } michael@0: michael@0: char dataString[MAX_STRING + 1]; michael@0: michael@0: int michael@0: main (int argc, char **argv) michael@0: { michael@0: int retval = 0; /* 0 - test succeeded. -1 - test failed */ michael@0: SECStatus rv; michael@0: PLOptState *optstate; michael@0: char *program_name; michael@0: char *input_file = NULL; /* read encrypted data from here (or create) */ michael@0: char *output_file = NULL; /* write new encrypted data here */ michael@0: char *log_file = NULL; /* write new encrypted data here */ michael@0: FILE *inFile = stdin; michael@0: FILE *outFile = stdout; michael@0: FILE *logFile = NULL; michael@0: PLOptStatus optstatus; michael@0: secuPWData pwdata = { PW_NONE, NULL }; michael@0: michael@0: michael@0: program_name = PL_strrchr(argv[0], '/'); michael@0: program_name = program_name ? (program_name + 1) : argv[0]; michael@0: michael@0: optstate = PL_CreateOptState (argc, argv, "Hd:f:i:o:l:p:?"); michael@0: if (optstate == NULL) { michael@0: SECU_PrintError (program_name, "PL_CreateOptState failed"); michael@0: return 1; michael@0: } michael@0: michael@0: while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { michael@0: switch (optstate->option) { michael@0: case '?': michael@0: short_usage (program_name); michael@0: return 1; michael@0: michael@0: case 'H': michael@0: long_usage (program_name); michael@0: return 1; michael@0: michael@0: case 'd': michael@0: SECU_ConfigDirectory(optstate->value); michael@0: break; michael@0: michael@0: case 'i': michael@0: input_file = PL_strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'o': michael@0: output_file = PL_strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'l': michael@0: log_file = PL_strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'f': michael@0: pwdata.source = PW_FROMFILE; michael@0: pwdata.data = PL_strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'p': michael@0: pwdata.source = PW_PLAINTEXT; michael@0: pwdata.data = PL_strdup(optstate->value); michael@0: break; michael@0: michael@0: } michael@0: } michael@0: PL_DestroyOptState(optstate); michael@0: if (optstatus == PL_OPT_BAD) { michael@0: short_usage (program_name); michael@0: return 1; michael@0: } michael@0: michael@0: if (input_file) { michael@0: inFile = fopen(input_file,"r"); michael@0: if (inFile == NULL) { michael@0: perror(input_file); michael@0: return 1; michael@0: } michael@0: PR_Free(input_file); michael@0: } michael@0: if (output_file) { michael@0: outFile = fopen(output_file,"w+"); michael@0: if (outFile == NULL) { michael@0: perror(output_file); michael@0: return 1; michael@0: } michael@0: PR_Free(output_file); michael@0: } michael@0: if (log_file) { michael@0: if (log_file[0] == '-') michael@0: logFile = stderr; michael@0: else michael@0: logFile = fopen(log_file,"w+"); michael@0: if (logFile == NULL) { michael@0: perror(log_file); michael@0: return 1; michael@0: } michael@0: PR_Free(log_file); michael@0: } michael@0: michael@0: /* michael@0: * Initialize the Security libraries. michael@0: */ michael@0: PK11_SetPasswordFunc(SECU_GetModulePassword); michael@0: rv = NSS_Init(SECU_ConfigDirectory(NULL)); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError (program_name, "NSS_Init failed"); michael@0: retval = 1; michael@0: goto prdone; michael@0: } michael@0: michael@0: /* Get the encrypted result, either from the input file michael@0: * or from encrypting the plaintext value michael@0: */ michael@0: while (fgets(dataString, sizeof dataString, inFile)) { michael@0: unsigned char c = dataString[0]; michael@0: michael@0: if (c == 'M' && isBase64(dataString)) { michael@0: doDecrypt(dataString, outFile, logFile, &pwdata); michael@0: } else if (c == '~' && isBase64(dataString + 1)) { michael@0: doDecode(dataString, outFile, logFile); michael@0: } else { michael@0: fputs(dataString, outFile); michael@0: } michael@0: } michael@0: if (pwdata.data) michael@0: PR_Free(pwdata.data); michael@0: michael@0: fclose(outFile); michael@0: fclose(inFile); michael@0: if (logFile && logFile != stderr) { michael@0: fclose(logFile); michael@0: } michael@0: michael@0: if (NSS_Shutdown() != SECSuccess) { michael@0: SECU_PrintError (program_name, "NSS_Shutdown failed"); michael@0: exit(1); michael@0: } michael@0: michael@0: prdone: michael@0: PR_Cleanup (); michael@0: return retval; michael@0: }