/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Test program for SDR (Secret Decoder Ring) functions. */ #include "nspr.h" #include "string.h" #include "nss.h" #include "secutil.h" #include "cert.h" #include "pk11func.h" #include "plgetopt.h" #include "pk11sdr.h" #include "nssb64.h" #define DEFAULT_VALUE "Test" static const char default_value[] = { DEFAULT_VALUE }; PRFileDesc *pr_stderr; PRBool verbose = PR_FALSE; static void synopsis(char *program_name) { PR_fprintf(pr_stderr, "Usage: %s [] -i \n" " %s [] -o \n" " [-d dir] [-v] [-t text] [-a] [-f pwfile | -p pwd]\n", program_name, program_name); } static void short_usage(char *program_name) { PR_fprintf(pr_stderr, "Type %s -H for more detailed descriptions\n", program_name); synopsis(program_name); } static void long_usage(char *program_name) { synopsis(program_name); PR_fprintf(pr_stderr, "\nSecret Decoder Test:\n"); PR_fprintf(pr_stderr, " %-13s Read encrypted data from \"file\"\n", "-i file"); PR_fprintf(pr_stderr, " %-13s Write newly generated encrypted data to \"file\"\n", "-o file"); PR_fprintf(pr_stderr, " %-13s Use \"text\" as the plaintext for encryption and verification\n", "-t text"); PR_fprintf(pr_stderr, " %-13s Find security databases in \"dbdir\"\n", "-d dbdir"); PR_fprintf(pr_stderr, " %-13s read the password from \"pwfile\"\n", "-f pwfile"); PR_fprintf(pr_stderr, " %-13s supply \"password\" on the command line\n", "-p password"); } int readStdin(SECItem *result) { unsigned int bufsize = 0; int cc; unsigned int wanted = 8192U; result->len = 0; result->data = NULL; do { if (bufsize < wanted) { unsigned char *tmpData = (unsigned char *)PR_Realloc(result->data, wanted); if (!tmpData) { if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n"); return -1; } result->data = tmpData; bufsize = wanted; } cc = PR_Read(PR_STDIN, result->data + result->len, bufsize - result->len); if (cc > 0) { result->len += (unsigned)cc; if (result->len >= wanted) wanted *= 2; } } while (cc > 0); return cc; } int readInputFile(const char *filename, SECItem *result) { PRFileDesc *file /* = PR_OpenFile(input_file, 0) */; PRFileInfo info; PRStatus s; PRInt32 count; int retval = -1; file = PR_Open(filename, PR_RDONLY, 0); if (!file) { if (verbose) PR_fprintf(pr_stderr, "Open of file %s failed\n", filename); goto loser; } s = PR_GetOpenFileInfo(file, &info); if (s != PR_SUCCESS) { if (verbose) PR_fprintf(pr_stderr, "File info operation failed\n"); goto file_loser; } result->len = info.size; result->data = (unsigned char *)PR_Malloc(result->len); if (!result->data) { if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n"); goto file_loser; } count = PR_Read(file, result->data, result->len); if (count != result->len) { if (verbose) PR_fprintf(pr_stderr, "Read failed\n"); goto file_loser; } retval = 0; file_loser: PR_Close(file); loser: return retval; } int main(int argc, char **argv) { int retval = 0; /* 0 - test succeeded. -1 - test failed */ SECStatus rv; PLOptState *optstate; PLOptStatus optstatus; char *program_name; const char *input_file = NULL; /* read encrypted data from here (or create) */ const char *output_file = NULL; /* write new encrypted data here */ const char *value = default_value; /* Use this for plaintext */ SECItem data; SECItem result = { 0, 0, 0 }; SECItem text; PRBool ascii = PR_FALSE; secuPWData pwdata = { PW_NONE, 0 }; pr_stderr = PR_STDERR; result.data = 0; text.data = 0; text.len = 0; program_name = PL_strrchr(argv[0], '/'); program_name = program_name ? (program_name + 1) : argv[0]; optstate = PL_CreateOptState(argc, argv, "?Had:i:o:t:vf:p:"); if (optstate == NULL) { SECU_PrintError(program_name, "PL_CreateOptState failed"); return -1; } while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case '?': short_usage(program_name); return retval; case 'H': long_usage(program_name); return retval; case 'a': ascii = PR_TRUE; break; case 'd': SECU_ConfigDirectory(optstate->value); break; case 'i': input_file = optstate->value; break; case 'o': output_file = optstate->value; break; case 't': value = optstate->value; break; case 'f': if (pwdata.data) { PORT_Free(pwdata.data); short_usage(program_name); return -1; } pwdata.source = PW_FROMFILE; pwdata.data = PORT_Strdup(optstate->value); break; case 'p': if (pwdata.data) { PORT_Free(pwdata.data); short_usage(program_name); return -1; } pwdata.source = PW_PLAINTEXT; pwdata.data = PORT_Strdup(optstate->value); break; case 'v': verbose = PR_TRUE; break; } } PL_DestroyOptState(optstate); if (optstatus == PL_OPT_BAD) { short_usage(program_name); return -1; } if (!output_file && !input_file && value == default_value) { short_usage(program_name); PR_fprintf(pr_stderr, "Must specify at least one of -t, -i or -o \n"); return -1; } /* * Initialize the Security libraries. */ PK11_SetPasswordFunc(SECU_GetModulePassword); if (output_file) { rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL)); } else { rv = NSS_Init(SECU_ConfigDirectory(NULL)); } if (rv != SECSuccess) { SECU_PrintError(program_name, "NSS_Init failed"); retval = -1; goto prdone; } /* Convert value into an item */ data.data = (unsigned char *)value; data.len = strlen(value); /* Get the encrypted result, either from the input file * or from encrypting the plaintext value */ if (input_file) { if (verbose) printf("Reading data from %s\n", input_file); if (!strcmp(input_file, "-")) { retval = readStdin(&result); ascii = PR_TRUE; } else { retval = readInputFile(input_file, &result); } if (retval != 0) goto loser; if (ascii) { /* input was base64 encoded. Decode it. */ SECItem newResult = { 0, 0, 0 }; SECItem *ok = NSSBase64_DecodeBuffer(NULL, &newResult, (const char *)result.data, result.len); if (!ok) { SECU_PrintError(program_name, "Base 64 decode failed"); retval = -1; goto loser; } SECITEM_ZfreeItem(&result, PR_FALSE); result = *ok; } } else { SECItem keyid = { 0, 0, 0 }; SECItem outBuf = { 0, 0, 0 }; PK11SlotInfo *slot = NULL; /* sigh, initialize the key database */ slot = PK11_GetInternalKeySlot(); if (slot && PK11_NeedUserInit(slot)) { switch (pwdata.source) { case PW_FROMFILE: rv = SECU_ChangePW(slot, 0, pwdata.data); break; case PW_PLAINTEXT: rv = SECU_ChangePW(slot, pwdata.data, 0); break; default: rv = SECU_ChangePW(slot, "", 0); break; } if (rv != SECSuccess) { SECU_PrintError(program_name, "Failed to initialize slot \"%s\"", PK11_GetSlotName(slot)); return SECFailure; } } if (slot) { PK11_FreeSlot(slot); } rv = PK11SDR_Encrypt(&keyid, &data, &result, &pwdata); if (rv != SECSuccess) { if (verbose) SECU_PrintError(program_name, "Encrypt operation failed\n"); retval = -1; goto loser; } if (verbose) printf("Encrypted result is %d bytes long\n", result.len); if (!strcmp(output_file, "-")) { ascii = PR_TRUE; } if (ascii) { /* base64 encode output. */ char *newResult = NSSBase64_EncodeItem(NULL, NULL, 0, &result); if (!newResult) { SECU_PrintError(program_name, "Base 64 encode failed\n"); retval = -1; goto loser; } outBuf.data = (unsigned char *)newResult; outBuf.len = strlen(newResult); if (verbose) printf("Base 64 encoded result is %d bytes long\n", outBuf.len); } else { outBuf = result; } /* -v printf("Result is %.*s\n", text.len, text.data); */ if (output_file) { PRFileDesc *file; PRInt32 count; if (verbose) printf("Writing result to %s\n", output_file); if (!strcmp(output_file, "-")) { file = PR_STDOUT; } else { /* Write to file */ file = PR_Open(output_file, PR_CREATE_FILE | PR_WRONLY, 0666); } if (!file) { if (verbose) SECU_PrintError(program_name, "Open of output file %s failed\n", output_file); retval = -1; goto loser; } count = PR_Write(file, outBuf.data, outBuf.len); if (file == PR_STDOUT) { puts(""); } else { PR_Close(file); } if (count != outBuf.len) { if (verbose) SECU_PrintError(program_name, "Write failed\n"); retval = -1; goto loser; } if (ascii) { free(outBuf.data); } } } /* Decrypt the value */ rv = PK11SDR_Decrypt(&result, &text, &pwdata); if (rv != SECSuccess) { if (verbose) SECU_PrintError(program_name, "Decrypt operation failed\n"); retval = -1; goto loser; } if (verbose) printf("Decrypted result is \"%.*s\"\n", text.len, text.data); /* Compare to required value */ if (text.len != data.len || memcmp(data.data, text.data, text.len) != 0) { if (verbose) PR_fprintf(pr_stderr, "Comparison failed\n"); retval = -1; goto loser; } loser: if (text.data) SECITEM_ZfreeItem(&text, PR_FALSE); if (result.data) SECITEM_ZfreeItem(&result, PR_FALSE); if (NSS_Shutdown() != SECSuccess) { exit(1); } prdone: PR_Cleanup(); if (pwdata.data) { PORT_Free(pwdata.data); } return retval; }