security/nss/cmd/sdrtest/sdrtest.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Test program for SDR (Secret Decoder Ring) functions.
michael@0 7 */
michael@0 8
michael@0 9 #include "nspr.h"
michael@0 10 #include "string.h"
michael@0 11 #include "nss.h"
michael@0 12 #include "secutil.h"
michael@0 13 #include "cert.h"
michael@0 14 #include "pk11func.h"
michael@0 15
michael@0 16 #include "plgetopt.h"
michael@0 17 #include "pk11sdr.h"
michael@0 18 #include "nssb64.h"
michael@0 19
michael@0 20 #define DEFAULT_VALUE "Test"
michael@0 21 static const char default_value[] = { DEFAULT_VALUE };
michael@0 22
michael@0 23 PRFileDesc *pr_stderr;
michael@0 24 PRBool verbose = PR_FALSE;
michael@0 25
michael@0 26 static void
michael@0 27 synopsis (char *program_name)
michael@0 28 {
michael@0 29 PR_fprintf (pr_stderr,
michael@0 30 "Usage: %s [<common>] -i <input-file>\n"
michael@0 31 " %s [<common>] -o <output-file>\n"
michael@0 32 " <common> [-d dir] [-v] [-t text] [-a] [-f pwfile | -p pwd]\n",
michael@0 33 program_name, program_name);
michael@0 34 }
michael@0 35
michael@0 36 static void
michael@0 37 short_usage (char *program_name)
michael@0 38 {
michael@0 39 PR_fprintf (pr_stderr,
michael@0 40 "Type %s -H for more detailed descriptions\n",
michael@0 41 program_name);
michael@0 42 synopsis (program_name);
michael@0 43 }
michael@0 44
michael@0 45
michael@0 46 static void
michael@0 47 long_usage (char *program_name)
michael@0 48 {
michael@0 49 synopsis (program_name);
michael@0 50 PR_fprintf (pr_stderr, "\nSecret Decoder Test:\n");
michael@0 51 PR_fprintf (pr_stderr,
michael@0 52 " %-13s Read encrypted data from \"file\"\n",
michael@0 53 "-i file");
michael@0 54 PR_fprintf (pr_stderr,
michael@0 55 " %-13s Write newly generated encrypted data to \"file\"\n",
michael@0 56 "-o file");
michael@0 57 PR_fprintf (pr_stderr,
michael@0 58 " %-13s Use \"text\" as the plaintext for encryption and verification\n",
michael@0 59 "-t text");
michael@0 60 PR_fprintf (pr_stderr,
michael@0 61 " %-13s Find security databases in \"dbdir\"\n",
michael@0 62 "-d dbdir");
michael@0 63 PR_fprintf (pr_stderr,
michael@0 64 " %-13s read the password from \"pwfile\"\n",
michael@0 65 "-f pwfile");
michael@0 66 PR_fprintf (pr_stderr,
michael@0 67 " %-13s supply \"password\" on the command line\n",
michael@0 68 "-p password");
michael@0 69 }
michael@0 70
michael@0 71 int
michael@0 72 readStdin(SECItem * result)
michael@0 73 {
michael@0 74 int bufsize = 0;
michael@0 75 int cc;
michael@0 76 int wanted = 8192;
michael@0 77
michael@0 78 result->len = 0;
michael@0 79 result->data = NULL;
michael@0 80 do {
michael@0 81 if (bufsize < wanted) {
michael@0 82 unsigned char * tmpData = (unsigned char *)PR_Realloc(result->data, wanted);
michael@0 83 if (!tmpData) {
michael@0 84 if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n");
michael@0 85 return -1;
michael@0 86 }
michael@0 87 result->data = tmpData;
michael@0 88 bufsize = wanted;
michael@0 89 }
michael@0 90 cc = PR_Read(PR_STDIN, result->data + result->len, bufsize - result->len);
michael@0 91 if (cc > 0) {
michael@0 92 result->len += (unsigned)cc;
michael@0 93 if (result->len >= wanted)
michael@0 94 wanted *= 2;
michael@0 95 }
michael@0 96 } while (cc > 0);
michael@0 97 return cc;
michael@0 98 }
michael@0 99
michael@0 100 int
michael@0 101 readInputFile(const char * filename, SECItem * result)
michael@0 102 {
michael@0 103 PRFileDesc *file /* = PR_OpenFile(input_file, 0) */;
michael@0 104 PRFileInfo info;
michael@0 105 PRStatus s;
michael@0 106 PRInt32 count;
michael@0 107 int retval = -1;
michael@0 108
michael@0 109 file = PR_Open(filename, PR_RDONLY, 0);
michael@0 110 if (!file) {
michael@0 111 if (verbose) PR_fprintf(pr_stderr, "Open of file %s failed\n", filename);
michael@0 112 goto loser;
michael@0 113 }
michael@0 114
michael@0 115 s = PR_GetOpenFileInfo(file, &info);
michael@0 116 if (s != PR_SUCCESS) {
michael@0 117 if (verbose) PR_fprintf(pr_stderr, "File info operation failed\n");
michael@0 118 goto file_loser;
michael@0 119 }
michael@0 120
michael@0 121 result->len = info.size;
michael@0 122 result->data = (unsigned char *)PR_Malloc(result->len);
michael@0 123 if (!result->data) {
michael@0 124 if (verbose) PR_fprintf(pr_stderr, "Allocation of buffer failed\n");
michael@0 125 goto file_loser;
michael@0 126 }
michael@0 127
michael@0 128 count = PR_Read(file, result->data, result->len);
michael@0 129 if (count != result->len) {
michael@0 130 if (verbose) PR_fprintf(pr_stderr, "Read failed\n");
michael@0 131 goto file_loser;
michael@0 132 }
michael@0 133 retval = 0;
michael@0 134
michael@0 135 file_loser:
michael@0 136 PR_Close(file);
michael@0 137 loser:
michael@0 138 return retval;
michael@0 139 }
michael@0 140
michael@0 141 int
michael@0 142 main (int argc, char **argv)
michael@0 143 {
michael@0 144 int retval = 0; /* 0 - test succeeded. -1 - test failed */
michael@0 145 SECStatus rv;
michael@0 146 PLOptState *optstate;
michael@0 147 PLOptStatus optstatus;
michael@0 148 char *program_name;
michael@0 149 const char *input_file = NULL; /* read encrypted data from here (or create) */
michael@0 150 const char *output_file = NULL; /* write new encrypted data here */
michael@0 151 const char *value = default_value; /* Use this for plaintext */
michael@0 152 SECItem data;
michael@0 153 SECItem result = {0, 0, 0};
michael@0 154 SECItem text;
michael@0 155 PRBool ascii = PR_FALSE;
michael@0 156 secuPWData pwdata = { PW_NONE, 0 };
michael@0 157
michael@0 158 pr_stderr = PR_STDERR;
michael@0 159 result.data = 0;
michael@0 160 text.data = 0; text.len = 0;
michael@0 161
michael@0 162 program_name = PL_strrchr(argv[0], '/');
michael@0 163 program_name = program_name ? (program_name + 1) : argv[0];
michael@0 164
michael@0 165 optstate = PL_CreateOptState (argc, argv, "?Had:i:o:t:vf:p:");
michael@0 166 if (optstate == NULL) {
michael@0 167 SECU_PrintError (program_name, "PL_CreateOptState failed");
michael@0 168 return -1;
michael@0 169 }
michael@0 170
michael@0 171 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
michael@0 172 switch (optstate->option) {
michael@0 173 case '?':
michael@0 174 short_usage (program_name);
michael@0 175 return retval;
michael@0 176
michael@0 177 case 'H':
michael@0 178 long_usage (program_name);
michael@0 179 return retval;
michael@0 180
michael@0 181 case 'a':
michael@0 182 ascii = PR_TRUE;
michael@0 183 break;
michael@0 184
michael@0 185 case 'd':
michael@0 186 SECU_ConfigDirectory(optstate->value);
michael@0 187 break;
michael@0 188
michael@0 189 case 'i':
michael@0 190 input_file = optstate->value;
michael@0 191 break;
michael@0 192
michael@0 193 case 'o':
michael@0 194 output_file = optstate->value;
michael@0 195 break;
michael@0 196
michael@0 197 case 't':
michael@0 198 value = optstate->value;
michael@0 199 break;
michael@0 200
michael@0 201 case 'f':
michael@0 202 if (pwdata.data) {
michael@0 203 PORT_Free(pwdata.data);
michael@0 204 short_usage(program_name);
michael@0 205 return -1;
michael@0 206 }
michael@0 207 pwdata.source = PW_FROMFILE;
michael@0 208 pwdata.data = PORT_Strdup(optstate->value);
michael@0 209 break;
michael@0 210
michael@0 211 case 'p':
michael@0 212 if (pwdata.data) {
michael@0 213 PORT_Free(pwdata.data);
michael@0 214 short_usage(program_name);
michael@0 215 return -1;
michael@0 216 }
michael@0 217 pwdata.source = PW_PLAINTEXT;
michael@0 218 pwdata.data = PORT_Strdup(optstate->value);
michael@0 219 break;
michael@0 220
michael@0 221 case 'v':
michael@0 222 verbose = PR_TRUE;
michael@0 223 break;
michael@0 224 }
michael@0 225 }
michael@0 226 PL_DestroyOptState(optstate);
michael@0 227 if (optstatus == PL_OPT_BAD) {
michael@0 228 short_usage (program_name);
michael@0 229 return -1;
michael@0 230 }
michael@0 231 if (!output_file && !input_file && value == default_value) {
michael@0 232 short_usage (program_name);
michael@0 233 PR_fprintf (pr_stderr, "Must specify at least one of -t, -i or -o \n");
michael@0 234 return -1;
michael@0 235 }
michael@0 236
michael@0 237 /*
michael@0 238 * Initialize the Security libraries.
michael@0 239 */
michael@0 240 PK11_SetPasswordFunc(SECU_GetModulePassword);
michael@0 241
michael@0 242 if (output_file) {
michael@0 243 rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
michael@0 244 } else {
michael@0 245 rv = NSS_Init(SECU_ConfigDirectory(NULL));
michael@0 246 }
michael@0 247 if (rv != SECSuccess) {
michael@0 248 SECU_PrintError(program_name, "NSS_Init failed");
michael@0 249 retval = -1;
michael@0 250 goto prdone;
michael@0 251 }
michael@0 252
michael@0 253 /* Convert value into an item */
michael@0 254 data.data = (unsigned char *)value;
michael@0 255 data.len = strlen(value);
michael@0 256
michael@0 257 /* Get the encrypted result, either from the input file
michael@0 258 * or from encrypting the plaintext value
michael@0 259 */
michael@0 260 if (input_file)
michael@0 261 {
michael@0 262 if (verbose) printf("Reading data from %s\n", input_file);
michael@0 263
michael@0 264 if (!strcmp(input_file, "-")) {
michael@0 265 retval = readStdin(&result);
michael@0 266 ascii = PR_TRUE;
michael@0 267 } else {
michael@0 268 retval = readInputFile(input_file, &result);
michael@0 269 }
michael@0 270 if (retval != 0)
michael@0 271 goto loser;
michael@0 272 if (ascii) {
michael@0 273 /* input was base64 encoded. Decode it. */
michael@0 274 SECItem newResult = {0, 0, 0};
michael@0 275 SECItem *ok = NSSBase64_DecodeBuffer(NULL, &newResult,
michael@0 276 (const char *)result.data, result.len);
michael@0 277 if (!ok) {
michael@0 278 SECU_PrintError(program_name, "Base 64 decode failed");
michael@0 279 retval = -1;
michael@0 280 goto loser;
michael@0 281 }
michael@0 282 SECITEM_ZfreeItem(&result, PR_FALSE);
michael@0 283 result = *ok;
michael@0 284 }
michael@0 285 }
michael@0 286 else
michael@0 287 {
michael@0 288 SECItem keyid = { 0, 0, 0 };
michael@0 289 SECItem outBuf = { 0, 0, 0 };
michael@0 290 PK11SlotInfo *slot = NULL;
michael@0 291
michael@0 292 /* sigh, initialize the key database */
michael@0 293 slot = PK11_GetInternalKeySlot();
michael@0 294 if (slot && PK11_NeedUserInit(slot)) {
michael@0 295 switch (pwdata.source) {
michael@0 296 case PW_FROMFILE:
michael@0 297 rv = SECU_ChangePW(slot, 0, pwdata.data);
michael@0 298 break;
michael@0 299 case PW_PLAINTEXT:
michael@0 300 rv = SECU_ChangePW(slot, pwdata.data, 0);
michael@0 301 break;
michael@0 302 default:
michael@0 303 rv = SECU_ChangePW(slot, "", 0);
michael@0 304 break;
michael@0 305 }
michael@0 306 if (rv != SECSuccess) {
michael@0 307 SECU_PrintError(program_name, "Failed to initialize slot \"%s\"",
michael@0 308 PK11_GetSlotName(slot));
michael@0 309 return SECFailure;
michael@0 310 }
michael@0 311 }
michael@0 312 if (slot) {
michael@0 313 PK11_FreeSlot(slot);
michael@0 314 }
michael@0 315
michael@0 316 rv = PK11SDR_Encrypt(&keyid, &data, &result, &pwdata);
michael@0 317 if (rv != SECSuccess) {
michael@0 318 if (verbose)
michael@0 319 SECU_PrintError(program_name, "Encrypt operation failed\n");
michael@0 320 retval = -1;
michael@0 321 goto loser;
michael@0 322 }
michael@0 323
michael@0 324 if (verbose) printf("Encrypted result is %d bytes long\n", result.len);
michael@0 325
michael@0 326 if (!strcmp(output_file, "-")) {
michael@0 327 ascii = PR_TRUE;
michael@0 328 }
michael@0 329
michael@0 330 if (ascii) {
michael@0 331 /* base64 encode output. */
michael@0 332 char * newResult = NSSBase64_EncodeItem(NULL, NULL, 0, &result);
michael@0 333 if (!newResult) {
michael@0 334 SECU_PrintError(program_name, "Base 64 encode failed\n");
michael@0 335 retval = -1;
michael@0 336 goto loser;
michael@0 337 }
michael@0 338 outBuf.data = (unsigned char *)newResult;
michael@0 339 outBuf.len = strlen(newResult);
michael@0 340 if (verbose)
michael@0 341 printf("Base 64 encoded result is %d bytes long\n", outBuf.len);
michael@0 342 } else {
michael@0 343 outBuf = result;
michael@0 344 }
michael@0 345
michael@0 346 /* -v printf("Result is %.*s\n", text.len, text.data); */
michael@0 347 if (output_file) {
michael@0 348 PRFileDesc *file;
michael@0 349 PRInt32 count;
michael@0 350
michael@0 351 if (verbose) printf("Writing result to %s\n", output_file);
michael@0 352 if (!strcmp(output_file, "-")) {
michael@0 353 file = PR_STDOUT;
michael@0 354 } else {
michael@0 355 /* Write to file */
michael@0 356 file = PR_Open(output_file, PR_CREATE_FILE|PR_WRONLY, 0666);
michael@0 357 }
michael@0 358 if (!file) {
michael@0 359 if (verbose)
michael@0 360 SECU_PrintError(program_name,
michael@0 361 "Open of output file %s failed\n",
michael@0 362 output_file);
michael@0 363 retval = -1;
michael@0 364 goto loser;
michael@0 365 }
michael@0 366
michael@0 367 count = PR_Write(file, outBuf.data, outBuf.len);
michael@0 368
michael@0 369 if (file == PR_STDOUT) {
michael@0 370 puts("");
michael@0 371 } else {
michael@0 372 PR_Close(file);
michael@0 373 }
michael@0 374
michael@0 375 if (count != outBuf.len) {
michael@0 376 if (verbose) SECU_PrintError(program_name, "Write failed\n");
michael@0 377 retval = -1;
michael@0 378 goto loser;
michael@0 379 }
michael@0 380 if (ascii) {
michael@0 381 free(outBuf.data);
michael@0 382 }
michael@0 383 }
michael@0 384 }
michael@0 385
michael@0 386 /* Decrypt the value */
michael@0 387 rv = PK11SDR_Decrypt(&result, &text, &pwdata);
michael@0 388 if (rv != SECSuccess) {
michael@0 389 if (verbose) SECU_PrintError(program_name, "Decrypt operation failed\n");
michael@0 390 retval = -1;
michael@0 391 goto loser;
michael@0 392 }
michael@0 393
michael@0 394 if (verbose) printf("Decrypted result is \"%.*s\"\n", text.len, text.data);
michael@0 395
michael@0 396 /* Compare to required value */
michael@0 397 if (text.len != data.len || memcmp(data.data, text.data, text.len) != 0)
michael@0 398 {
michael@0 399 if (verbose) PR_fprintf(pr_stderr, "Comparison failed\n");
michael@0 400 retval = -1;
michael@0 401 goto loser;
michael@0 402 }
michael@0 403
michael@0 404 loser:
michael@0 405 if (text.data) SECITEM_ZfreeItem(&text, PR_FALSE);
michael@0 406 if (result.data) SECITEM_ZfreeItem(&result, PR_FALSE);
michael@0 407 if (NSS_Shutdown() != SECSuccess) {
michael@0 408 exit(1);
michael@0 409 }
michael@0 410
michael@0 411 prdone:
michael@0 412 PR_Cleanup ();
michael@0 413 if (pwdata.data) {
michael@0 414 PORT_Free(pwdata.data);
michael@0 415 }
michael@0 416 return retval;
michael@0 417 }

mercurial