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