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: michael@0: #include "plgetopt.h" michael@0: #include "pk11sdr.h" michael@0: #include "nssb64.h" michael@0: michael@0: #define DEFAULT_VALUE "Test" michael@0: static const char default_value[] = { DEFAULT_VALUE }; michael@0: michael@0: PRFileDesc *pr_stderr; michael@0: PRBool verbose = PR_FALSE; michael@0: michael@0: static void michael@0: synopsis (char *program_name) michael@0: { michael@0: PR_fprintf (pr_stderr, michael@0: "Usage: %s [] -i \n" michael@0: " %s [] -o \n" michael@0: " [-d dir] [-v] [-t text] [-a] [-f pwfile | -p pwd]\n", michael@0: program_name, program_name); 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: synopsis (program_name); michael@0: PR_fprintf (pr_stderr, "\nSecret Decoder Test:\n"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Read encrypted data from \"file\"\n", michael@0: "-i file"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Write newly generated encrypted data to \"file\"\n", michael@0: "-o file"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s Use \"text\" as the plaintext for encryption and verification\n", michael@0: "-t text"); 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 read the password from \"pwfile\"\n", michael@0: "-f pwfile"); michael@0: PR_fprintf (pr_stderr, michael@0: " %-13s supply \"password\" on the command line\n", michael@0: "-p password"); michael@0: } michael@0: michael@0: int michael@0: readStdin(SECItem * result) michael@0: { michael@0: int bufsize = 0; michael@0: int cc; michael@0: int wanted = 8192; michael@0: michael@0: result->len = 0; michael@0: result->data = NULL; michael@0: do { michael@0: if (bufsize < wanted) { michael@0: unsigned char * tmpData = (unsigned char *)PR_Realloc(result->data, wanted); michael@0: if (!tmpData) { michael@0: if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n"); michael@0: return -1; michael@0: } michael@0: result->data = tmpData; michael@0: bufsize = wanted; michael@0: } michael@0: cc = PR_Read(PR_STDIN, result->data + result->len, bufsize - result->len); michael@0: if (cc > 0) { michael@0: result->len += (unsigned)cc; michael@0: if (result->len >= wanted) michael@0: wanted *= 2; michael@0: } michael@0: } while (cc > 0); michael@0: return cc; michael@0: } michael@0: michael@0: int michael@0: readInputFile(const char * filename, SECItem * result) michael@0: { michael@0: PRFileDesc *file /* = PR_OpenFile(input_file, 0) */; michael@0: PRFileInfo info; michael@0: PRStatus s; michael@0: PRInt32 count; michael@0: int retval = -1; michael@0: michael@0: file = PR_Open(filename, PR_RDONLY, 0); michael@0: if (!file) { michael@0: if (verbose) PR_fprintf(pr_stderr, "Open of file %s failed\n", filename); michael@0: goto loser; michael@0: } michael@0: michael@0: s = PR_GetOpenFileInfo(file, &info); michael@0: if (s != PR_SUCCESS) { michael@0: if (verbose) PR_fprintf(pr_stderr, "File info operation failed\n"); michael@0: goto file_loser; michael@0: } michael@0: michael@0: result->len = info.size; michael@0: result->data = (unsigned char *)PR_Malloc(result->len); michael@0: if (!result->data) { michael@0: if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n"); michael@0: goto file_loser; michael@0: } michael@0: michael@0: count = PR_Read(file, result->data, result->len); michael@0: if (count != result->len) { michael@0: if (verbose) PR_fprintf(pr_stderr, "Read failed\n"); michael@0: goto file_loser; michael@0: } michael@0: retval = 0; michael@0: michael@0: file_loser: michael@0: PR_Close(file); michael@0: loser: michael@0: return retval; michael@0: } 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: PLOptStatus optstatus; michael@0: char *program_name; michael@0: const char *input_file = NULL; /* read encrypted data from here (or create) */ michael@0: const char *output_file = NULL; /* write new encrypted data here */ michael@0: const char *value = default_value; /* Use this for plaintext */ michael@0: SECItem data; michael@0: SECItem result = {0, 0, 0}; michael@0: SECItem text; michael@0: PRBool ascii = PR_FALSE; michael@0: secuPWData pwdata = { PW_NONE, 0 }; michael@0: michael@0: pr_stderr = PR_STDERR; michael@0: result.data = 0; michael@0: text.data = 0; text.len = 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, "?Had:i:o:t:vf: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 retval; michael@0: michael@0: case 'H': michael@0: long_usage (program_name); michael@0: return retval; michael@0: michael@0: case 'a': michael@0: ascii = PR_TRUE; michael@0: break; 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 = optstate->value; michael@0: break; michael@0: michael@0: case 'o': michael@0: output_file = optstate->value; michael@0: break; michael@0: michael@0: case 't': michael@0: value = optstate->value; michael@0: break; michael@0: michael@0: case 'f': michael@0: if (pwdata.data) { michael@0: PORT_Free(pwdata.data); michael@0: short_usage(program_name); michael@0: return -1; michael@0: } michael@0: pwdata.source = PW_FROMFILE; michael@0: pwdata.data = PORT_Strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'p': michael@0: if (pwdata.data) { michael@0: PORT_Free(pwdata.data); michael@0: short_usage(program_name); michael@0: return -1; michael@0: } michael@0: pwdata.source = PW_PLAINTEXT; michael@0: pwdata.data = PORT_Strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'v': michael@0: verbose = PR_TRUE; michael@0: break; 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: if (!output_file && !input_file && value == default_value) { michael@0: short_usage (program_name); michael@0: PR_fprintf (pr_stderr, "Must specify at least one of -t, -i or -o \n"); michael@0: return -1; michael@0: } michael@0: michael@0: /* michael@0: * Initialize the Security libraries. michael@0: */ michael@0: PK11_SetPasswordFunc(SECU_GetModulePassword); michael@0: michael@0: if (output_file) { michael@0: rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL)); michael@0: } else { michael@0: rv = NSS_Init(SECU_ConfigDirectory(NULL)); michael@0: } 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: /* Convert value into an item */ michael@0: data.data = (unsigned char *)value; michael@0: data.len = strlen(value); 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: if (input_file) michael@0: { michael@0: if (verbose) printf("Reading data from %s\n", input_file); michael@0: michael@0: if (!strcmp(input_file, "-")) { michael@0: retval = readStdin(&result); michael@0: ascii = PR_TRUE; michael@0: } else { michael@0: retval = readInputFile(input_file, &result); michael@0: } michael@0: if (retval != 0) michael@0: goto loser; michael@0: if (ascii) { michael@0: /* input was base64 encoded. Decode it. */ michael@0: SECItem newResult = {0, 0, 0}; michael@0: SECItem *ok = NSSBase64_DecodeBuffer(NULL, &newResult, michael@0: (const char *)result.data, result.len); michael@0: if (!ok) { michael@0: SECU_PrintError(program_name, "Base 64 decode failed"); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: SECITEM_ZfreeItem(&result, PR_FALSE); michael@0: result = *ok; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: SECItem keyid = { 0, 0, 0 }; michael@0: SECItem outBuf = { 0, 0, 0 }; michael@0: PK11SlotInfo *slot = NULL; michael@0: michael@0: /* sigh, initialize the key database */ michael@0: slot = PK11_GetInternalKeySlot(); michael@0: if (slot && PK11_NeedUserInit(slot)) { michael@0: switch (pwdata.source) { michael@0: case PW_FROMFILE: michael@0: rv = SECU_ChangePW(slot, 0, pwdata.data); michael@0: break; michael@0: case PW_PLAINTEXT: michael@0: rv = SECU_ChangePW(slot, pwdata.data, 0); michael@0: break; michael@0: default: michael@0: rv = SECU_ChangePW(slot, "", 0); michael@0: break; michael@0: } michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(program_name, "Failed to initialize slot \"%s\"", michael@0: PK11_GetSlotName(slot)); michael@0: return SECFailure; michael@0: } michael@0: } michael@0: if (slot) { michael@0: PK11_FreeSlot(slot); michael@0: } michael@0: michael@0: rv = PK11SDR_Encrypt(&keyid, &data, &result, &pwdata); michael@0: if (rv != SECSuccess) { michael@0: if (verbose) michael@0: SECU_PrintError(program_name, "Encrypt operation failed\n"); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: michael@0: if (verbose) printf("Encrypted result is %d bytes long\n", result.len); michael@0: michael@0: if (!strcmp(output_file, "-")) { michael@0: ascii = PR_TRUE; michael@0: } michael@0: michael@0: if (ascii) { michael@0: /* base64 encode output. */ michael@0: char * newResult = NSSBase64_EncodeItem(NULL, NULL, 0, &result); michael@0: if (!newResult) { michael@0: SECU_PrintError(program_name, "Base 64 encode failed\n"); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: outBuf.data = (unsigned char *)newResult; michael@0: outBuf.len = strlen(newResult); michael@0: if (verbose) michael@0: printf("Base 64 encoded result is %d bytes long\n", outBuf.len); michael@0: } else { michael@0: outBuf = result; michael@0: } michael@0: michael@0: /* -v printf("Result is %.*s\n", text.len, text.data); */ michael@0: if (output_file) { michael@0: PRFileDesc *file; michael@0: PRInt32 count; michael@0: michael@0: if (verbose) printf("Writing result to %s\n", output_file); michael@0: if (!strcmp(output_file, "-")) { michael@0: file = PR_STDOUT; michael@0: } else { michael@0: /* Write to file */ michael@0: file = PR_Open(output_file, PR_CREATE_FILE|PR_WRONLY, 0666); michael@0: } michael@0: if (!file) { michael@0: if (verbose) michael@0: SECU_PrintError(program_name, michael@0: "Open of output file %s failed\n", michael@0: output_file); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: michael@0: count = PR_Write(file, outBuf.data, outBuf.len); michael@0: michael@0: if (file == PR_STDOUT) { michael@0: puts(""); michael@0: } else { michael@0: PR_Close(file); michael@0: } michael@0: michael@0: if (count != outBuf.len) { michael@0: if (verbose) SECU_PrintError(program_name, "Write failed\n"); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: if (ascii) { michael@0: free(outBuf.data); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* Decrypt the value */ michael@0: rv = PK11SDR_Decrypt(&result, &text, &pwdata); michael@0: if (rv != SECSuccess) { michael@0: if (verbose) SECU_PrintError(program_name, "Decrypt operation failed\n"); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: michael@0: if (verbose) printf("Decrypted result is \"%.*s\"\n", text.len, text.data); michael@0: michael@0: /* Compare to required value */ michael@0: if (text.len != data.len || memcmp(data.data, text.data, text.len) != 0) michael@0: { michael@0: if (verbose) PR_fprintf(pr_stderr, "Comparison failed\n"); michael@0: retval = -1; michael@0: goto loser; michael@0: } michael@0: michael@0: loser: michael@0: if (text.data) SECITEM_ZfreeItem(&text, PR_FALSE); michael@0: if (result.data) SECITEM_ZfreeItem(&result, PR_FALSE); michael@0: if (NSS_Shutdown() != SECSuccess) { michael@0: exit(1); michael@0: } michael@0: michael@0: prdone: michael@0: PR_Cleanup (); michael@0: if (pwdata.data) { michael@0: PORT_Free(pwdata.data); michael@0: } michael@0: return retval; michael@0: }