security/nss/cmd/fipstest/fipstest.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 #include <stdio.h>
michael@0 6 #include <stdlib.h>
michael@0 7 #include <ctype.h>
michael@0 8
michael@0 9 #include "secitem.h"
michael@0 10 #include "blapi.h"
michael@0 11 #include "nssutil.h"
michael@0 12 #include "secerr.h"
michael@0 13 #include "secder.h"
michael@0 14 #include "secdig.h"
michael@0 15 #include "secoid.h"
michael@0 16 #include "ec.h"
michael@0 17 #include "hasht.h"
michael@0 18 #include "lowkeyi.h"
michael@0 19 #include "softoken.h"
michael@0 20
michael@0 21 #if 0
michael@0 22 #include "../../lib/freebl/mpi/mpi.h"
michael@0 23 #endif
michael@0 24
michael@0 25 #ifndef NSS_DISABLE_ECC
michael@0 26 extern SECStatus
michael@0 27 EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
michael@0 28 extern SECStatus
michael@0 29 EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
michael@0 30 const ECParams *srcParams);
michael@0 31 #endif
michael@0 32
michael@0 33 #define ENCRYPT 1
michael@0 34 #define DECRYPT 0
michael@0 35 #define BYTE unsigned char
michael@0 36 #define DEFAULT_RSA_PUBLIC_EXPONENT 0x10001
michael@0 37 #define RSA_MAX_TEST_MODULUS_BITS 4096
michael@0 38 #define RSA_MAX_TEST_MODULUS_BYTES RSA_MAX_TEST_MODULUS_BITS/8
michael@0 39 #define RSA_MAX_TEST_EXPONENT_BYTES 8
michael@0 40 #define PQG_TEST_SEED_BYTES 20
michael@0 41
michael@0 42 SECStatus
michael@0 43 hex_to_byteval(const char *c2, unsigned char *byteval)
michael@0 44 {
michael@0 45 int i;
michael@0 46 unsigned char offset;
michael@0 47 *byteval = 0;
michael@0 48 for (i=0; i<2; i++) {
michael@0 49 if (c2[i] >= '0' && c2[i] <= '9') {
michael@0 50 offset = c2[i] - '0';
michael@0 51 *byteval |= offset << 4*(1-i);
michael@0 52 } else if (c2[i] >= 'a' && c2[i] <= 'f') {
michael@0 53 offset = c2[i] - 'a';
michael@0 54 *byteval |= (offset + 10) << 4*(1-i);
michael@0 55 } else if (c2[i] >= 'A' && c2[i] <= 'F') {
michael@0 56 offset = c2[i] - 'A';
michael@0 57 *byteval |= (offset + 10) << 4*(1-i);
michael@0 58 } else {
michael@0 59 return SECFailure;
michael@0 60 }
michael@0 61 }
michael@0 62 return SECSuccess;
michael@0 63 }
michael@0 64
michael@0 65 SECStatus
michael@0 66 byteval_to_hex(unsigned char byteval, char *c2, char a)
michael@0 67 {
michael@0 68 int i;
michael@0 69 unsigned char offset;
michael@0 70 for (i=0; i<2; i++) {
michael@0 71 offset = (byteval >> 4*(1-i)) & 0x0f;
michael@0 72 if (offset < 10) {
michael@0 73 c2[i] = '0' + offset;
michael@0 74 } else {
michael@0 75 c2[i] = a + offset - 10;
michael@0 76 }
michael@0 77 }
michael@0 78 return SECSuccess;
michael@0 79 }
michael@0 80
michael@0 81 void
michael@0 82 to_hex_str(char *str, const unsigned char *buf, unsigned int len)
michael@0 83 {
michael@0 84 unsigned int i;
michael@0 85 for (i=0; i<len; i++) {
michael@0 86 byteval_to_hex(buf[i], &str[2*i], 'a');
michael@0 87 }
michael@0 88 str[2*len] = '\0';
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 to_hex_str_cap(char *str, const unsigned char *buf, unsigned int len)
michael@0 93 {
michael@0 94 unsigned int i;
michael@0 95 for (i=0; i<len; i++) {
michael@0 96 byteval_to_hex(buf[i], &str[2*i], 'A');
michael@0 97 }
michael@0 98 str[2*len] = '\0';
michael@0 99 }
michael@0 100
michael@0 101 /*
michael@0 102 * Convert a string of hex digits (str) to an array (buf) of len bytes.
michael@0 103 * Return PR_TRUE if the hex string can fit in the byte array. Return
michael@0 104 * PR_FALSE if the hex string is empty or is too long.
michael@0 105 */
michael@0 106 PRBool
michael@0 107 from_hex_str(unsigned char *buf, unsigned int len, const char *str)
michael@0 108 {
michael@0 109 unsigned int nxdigit; /* number of hex digits in str */
michael@0 110 unsigned int i; /* index into buf */
michael@0 111 unsigned int j; /* index into str */
michael@0 112
michael@0 113 /* count the hex digits */
michael@0 114 nxdigit = 0;
michael@0 115 for (nxdigit = 0; isxdigit(str[nxdigit]); nxdigit++) {
michael@0 116 /* empty body */
michael@0 117 }
michael@0 118 if (nxdigit == 0) {
michael@0 119 return PR_FALSE;
michael@0 120 }
michael@0 121 if (nxdigit > 2*len) {
michael@0 122 /*
michael@0 123 * The input hex string is too long, but we allow it if the
michael@0 124 * extra digits are leading 0's.
michael@0 125 */
michael@0 126 for (j = 0; j < nxdigit-2*len; j++) {
michael@0 127 if (str[j] != '0') {
michael@0 128 return PR_FALSE;
michael@0 129 }
michael@0 130 }
michael@0 131 /* skip leading 0's */
michael@0 132 str += nxdigit-2*len;
michael@0 133 nxdigit = 2*len;
michael@0 134 }
michael@0 135 for (i=0, j=0; i< len; i++) {
michael@0 136 if (2*i < 2*len-nxdigit) {
michael@0 137 /* Handle a short input as if we padded it with leading 0's. */
michael@0 138 if (2*i+1 < 2*len-nxdigit) {
michael@0 139 buf[i] = 0;
michael@0 140 } else {
michael@0 141 char tmp[2];
michael@0 142 tmp[0] = '0';
michael@0 143 tmp[1] = str[j];
michael@0 144 hex_to_byteval(tmp, &buf[i]);
michael@0 145 j++;
michael@0 146 }
michael@0 147 } else {
michael@0 148 hex_to_byteval(&str[j], &buf[i]);
michael@0 149 j += 2;
michael@0 150 }
michael@0 151 }
michael@0 152 return PR_TRUE;
michael@0 153 }
michael@0 154
michael@0 155 SECStatus
michael@0 156 tdea_encrypt_buf(
michael@0 157 int mode,
michael@0 158 const unsigned char *key,
michael@0 159 const unsigned char *iv,
michael@0 160 unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
michael@0 161 const unsigned char *input, unsigned int inputlen)
michael@0 162 {
michael@0 163 SECStatus rv = SECFailure;
michael@0 164 DESContext *cx;
michael@0 165 unsigned char doublecheck[8*20]; /* 1 to 20 blocks */
michael@0 166 unsigned int doublechecklen = 0;
michael@0 167
michael@0 168 cx = DES_CreateContext(key, iv, mode, PR_TRUE);
michael@0 169 if (cx == NULL) {
michael@0 170 goto loser;
michael@0 171 }
michael@0 172 rv = DES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
michael@0 173 if (rv != SECSuccess) {
michael@0 174 goto loser;
michael@0 175 }
michael@0 176 if (*outputlen != inputlen) {
michael@0 177 goto loser;
michael@0 178 }
michael@0 179 DES_DestroyContext(cx, PR_TRUE);
michael@0 180 cx = NULL;
michael@0 181
michael@0 182 /*
michael@0 183 * Doublecheck our result by decrypting the ciphertext and
michael@0 184 * compare the output with the input plaintext.
michael@0 185 */
michael@0 186 cx = DES_CreateContext(key, iv, mode, PR_FALSE);
michael@0 187 if (cx == NULL) {
michael@0 188 goto loser;
michael@0 189 }
michael@0 190 rv = DES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
michael@0 191 output, *outputlen);
michael@0 192 if (rv != SECSuccess) {
michael@0 193 goto loser;
michael@0 194 }
michael@0 195 if (doublechecklen != *outputlen) {
michael@0 196 goto loser;
michael@0 197 }
michael@0 198 DES_DestroyContext(cx, PR_TRUE);
michael@0 199 cx = NULL;
michael@0 200 if (memcmp(doublecheck, input, inputlen) != 0) {
michael@0 201 goto loser;
michael@0 202 }
michael@0 203 rv = SECSuccess;
michael@0 204
michael@0 205 loser:
michael@0 206 if (cx != NULL) {
michael@0 207 DES_DestroyContext(cx, PR_TRUE);
michael@0 208 }
michael@0 209 return rv;
michael@0 210 }
michael@0 211
michael@0 212 SECStatus
michael@0 213 tdea_decrypt_buf(
michael@0 214 int mode,
michael@0 215 const unsigned char *key,
michael@0 216 const unsigned char *iv,
michael@0 217 unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
michael@0 218 const unsigned char *input, unsigned int inputlen)
michael@0 219 {
michael@0 220 SECStatus rv = SECFailure;
michael@0 221 DESContext *cx;
michael@0 222 unsigned char doublecheck[8*20]; /* 1 to 20 blocks */
michael@0 223 unsigned int doublechecklen = 0;
michael@0 224
michael@0 225 cx = DES_CreateContext(key, iv, mode, PR_FALSE);
michael@0 226 if (cx == NULL) {
michael@0 227 goto loser;
michael@0 228 }
michael@0 229 rv = DES_Decrypt(cx, output, outputlen, maxoutputlen,
michael@0 230 input, inputlen);
michael@0 231 if (rv != SECSuccess) {
michael@0 232 goto loser;
michael@0 233 }
michael@0 234 if (*outputlen != inputlen) {
michael@0 235 goto loser;
michael@0 236 }
michael@0 237 DES_DestroyContext(cx, PR_TRUE);
michael@0 238 cx = NULL;
michael@0 239
michael@0 240 /*
michael@0 241 * Doublecheck our result by encrypting the plaintext and
michael@0 242 * compare the output with the input ciphertext.
michael@0 243 */
michael@0 244 cx = DES_CreateContext(key, iv, mode, PR_TRUE);
michael@0 245 if (cx == NULL) {
michael@0 246 goto loser;
michael@0 247 }
michael@0 248 rv = DES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
michael@0 249 output, *outputlen);
michael@0 250 if (rv != SECSuccess) {
michael@0 251 goto loser;
michael@0 252 }
michael@0 253 if (doublechecklen != *outputlen) {
michael@0 254 goto loser;
michael@0 255 }
michael@0 256 DES_DestroyContext(cx, PR_TRUE);
michael@0 257 cx = NULL;
michael@0 258 if (memcmp(doublecheck, input, inputlen) != 0) {
michael@0 259 goto loser;
michael@0 260 }
michael@0 261 rv = SECSuccess;
michael@0 262
michael@0 263 loser:
michael@0 264 if (cx != NULL) {
michael@0 265 DES_DestroyContext(cx, PR_TRUE);
michael@0 266 }
michael@0 267 return rv;
michael@0 268 }
michael@0 269
michael@0 270 /*
michael@0 271 * Perform the TDEA Known Answer Test (KAT) or Multi-block Message
michael@0 272 * Test (MMT) in ECB or CBC mode. The KAT (there are five types)
michael@0 273 * and MMT have the same structure: given the key and IV (CBC mode
michael@0 274 * only), encrypt the given plaintext or decrypt the given ciphertext.
michael@0 275 * So we can handle them the same way.
michael@0 276 *
michael@0 277 * reqfn is the pathname of the REQUEST file.
michael@0 278 *
michael@0 279 * The output RESPONSE file is written to stdout.
michael@0 280 */
michael@0 281 void
michael@0 282 tdea_kat_mmt(char *reqfn)
michael@0 283 {
michael@0 284 char buf[180]; /* holds one line from the input REQUEST file.
michael@0 285 * needs to be large enough to hold the longest
michael@0 286 * line "CIPHERTEXT = <180 hex digits>\n".
michael@0 287 */
michael@0 288 FILE *req; /* input stream from the REQUEST file */
michael@0 289 FILE *resp; /* output stream to the RESPONSE file */
michael@0 290 int i, j;
michael@0 291 int mode; /* NSS_DES_EDE3 (ECB) or NSS_DES_EDE3_CBC */
michael@0 292 int crypt = DECRYPT; /* 1 means encrypt, 0 means decrypt */
michael@0 293 unsigned char key[24]; /* TDEA 3 key bundle */
michael@0 294 unsigned int numKeys = 0;
michael@0 295 unsigned char iv[8]; /* for all modes except ECB */
michael@0 296 unsigned char plaintext[8*20]; /* 1 to 20 blocks */
michael@0 297 unsigned int plaintextlen;
michael@0 298 unsigned char ciphertext[8*20]; /* 1 to 20 blocks */
michael@0 299 unsigned int ciphertextlen;
michael@0 300 SECStatus rv;
michael@0 301
michael@0 302 req = fopen(reqfn, "r");
michael@0 303 resp = stdout;
michael@0 304 while (fgets(buf, sizeof buf, req) != NULL) {
michael@0 305 /* a comment or blank line */
michael@0 306 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 307 fputs(buf, resp);
michael@0 308 continue;
michael@0 309 }
michael@0 310 /* [ENCRYPT] or [DECRYPT] */
michael@0 311 if (buf[0] == '[') {
michael@0 312 if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
michael@0 313 crypt = ENCRYPT;
michael@0 314 } else {
michael@0 315 crypt = DECRYPT;
michael@0 316 }
michael@0 317 fputs(buf, resp);
michael@0 318 continue;
michael@0 319 }
michael@0 320 /* NumKeys */
michael@0 321 if (strncmp(&buf[0], "NumKeys", 7) == 0) {
michael@0 322 i = 7;
michael@0 323 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 324 i++;
michael@0 325 }
michael@0 326 numKeys = buf[i];
michael@0 327 fputs(buf, resp);
michael@0 328 continue;
michael@0 329 }
michael@0 330 /* "COUNT = x" begins a new data set */
michael@0 331 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 332 /* mode defaults to ECB, if dataset has IV mode will be set CBC */
michael@0 333 mode = NSS_DES_EDE3;
michael@0 334 /* zeroize the variables for the test with this data set */
michael@0 335 memset(key, 0, sizeof key);
michael@0 336 memset(iv, 0, sizeof iv);
michael@0 337 memset(plaintext, 0, sizeof plaintext);
michael@0 338 plaintextlen = 0;
michael@0 339 memset(ciphertext, 0, sizeof ciphertext);
michael@0 340 ciphertextlen = 0;
michael@0 341 fputs(buf, resp);
michael@0 342 continue;
michael@0 343 }
michael@0 344 if (numKeys == 0) {
michael@0 345 if (strncmp(buf, "KEYs", 4) == 0) {
michael@0 346 i = 4;
michael@0 347 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 348 i++;
michael@0 349 }
michael@0 350 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 351 hex_to_byteval(&buf[i], &key[j]);
michael@0 352 key[j+8] = key[j];
michael@0 353 key[j+16] = key[j];
michael@0 354 }
michael@0 355 fputs(buf, resp);
michael@0 356 continue;
michael@0 357 }
michael@0 358 } else {
michael@0 359 /* KEY1 = ... */
michael@0 360 if (strncmp(buf, "KEY1", 4) == 0) {
michael@0 361 i = 4;
michael@0 362 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 363 i++;
michael@0 364 }
michael@0 365 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 366 hex_to_byteval(&buf[i], &key[j]);
michael@0 367 }
michael@0 368 fputs(buf, resp);
michael@0 369 continue;
michael@0 370 }
michael@0 371 /* KEY2 = ... */
michael@0 372 if (strncmp(buf, "KEY2", 4) == 0) {
michael@0 373 i = 4;
michael@0 374 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 375 i++;
michael@0 376 }
michael@0 377 for (j=8; isxdigit(buf[i]); i+=2,j++) {
michael@0 378 hex_to_byteval(&buf[i], &key[j]);
michael@0 379 }
michael@0 380 fputs(buf, resp);
michael@0 381 continue;
michael@0 382 }
michael@0 383 /* KEY3 = ... */
michael@0 384 if (strncmp(buf, "KEY3", 4) == 0) {
michael@0 385 i = 4;
michael@0 386 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 387 i++;
michael@0 388 }
michael@0 389 for (j=16; isxdigit(buf[i]); i+=2,j++) {
michael@0 390 hex_to_byteval(&buf[i], &key[j]);
michael@0 391 }
michael@0 392 fputs(buf, resp);
michael@0 393 continue;
michael@0 394 }
michael@0 395 }
michael@0 396
michael@0 397 /* IV = ... */
michael@0 398 if (strncmp(buf, "IV", 2) == 0) {
michael@0 399 mode = NSS_DES_EDE3_CBC;
michael@0 400 i = 2;
michael@0 401 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 402 i++;
michael@0 403 }
michael@0 404 for (j=0; j<sizeof iv; i+=2,j++) {
michael@0 405 hex_to_byteval(&buf[i], &iv[j]);
michael@0 406 }
michael@0 407 fputs(buf, resp);
michael@0 408 continue;
michael@0 409 }
michael@0 410
michael@0 411 /* PLAINTEXT = ... */
michael@0 412 if (strncmp(buf, "PLAINTEXT", 9) == 0) {
michael@0 413 /* sanity check */
michael@0 414 if (crypt != ENCRYPT) {
michael@0 415 goto loser;
michael@0 416 }
michael@0 417 i = 9;
michael@0 418 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 419 i++;
michael@0 420 }
michael@0 421 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 422 hex_to_byteval(&buf[i], &plaintext[j]);
michael@0 423 }
michael@0 424 plaintextlen = j;
michael@0 425 rv = tdea_encrypt_buf(mode, key,
michael@0 426 (mode == NSS_DES_EDE3) ? NULL : iv,
michael@0 427 ciphertext, &ciphertextlen, sizeof ciphertext,
michael@0 428 plaintext, plaintextlen);
michael@0 429 if (rv != SECSuccess) {
michael@0 430 goto loser;
michael@0 431 }
michael@0 432
michael@0 433 fputs(buf, resp);
michael@0 434 fputs("CIPHERTEXT = ", resp);
michael@0 435 to_hex_str(buf, ciphertext, ciphertextlen);
michael@0 436 fputs(buf, resp);
michael@0 437 fputc('\n', resp);
michael@0 438 continue;
michael@0 439 }
michael@0 440 /* CIPHERTEXT = ... */
michael@0 441 if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
michael@0 442 /* sanity check */
michael@0 443 if (crypt != DECRYPT) {
michael@0 444 goto loser;
michael@0 445 }
michael@0 446
michael@0 447 i = 10;
michael@0 448 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 449 i++;
michael@0 450 }
michael@0 451 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 452 hex_to_byteval(&buf[i], &ciphertext[j]);
michael@0 453 }
michael@0 454 ciphertextlen = j;
michael@0 455
michael@0 456 rv = tdea_decrypt_buf(mode, key,
michael@0 457 (mode == NSS_DES_EDE3) ? NULL : iv,
michael@0 458 plaintext, &plaintextlen, sizeof plaintext,
michael@0 459 ciphertext, ciphertextlen);
michael@0 460 if (rv != SECSuccess) {
michael@0 461 goto loser;
michael@0 462 }
michael@0 463
michael@0 464 fputs(buf, resp);
michael@0 465 fputs("PLAINTEXT = ", resp);
michael@0 466 to_hex_str(buf, plaintext, plaintextlen);
michael@0 467 fputs(buf, resp);
michael@0 468 fputc('\n', resp);
michael@0 469 continue;
michael@0 470 }
michael@0 471 }
michael@0 472
michael@0 473 loser:
michael@0 474 fclose(req);
michael@0 475 }
michael@0 476
michael@0 477 /*
michael@0 478 * Set the parity bit for the given byte
michael@0 479 */
michael@0 480 BYTE odd_parity( BYTE in)
michael@0 481 {
michael@0 482 BYTE out = in;
michael@0 483 in ^= in >> 4;
michael@0 484 in ^= in >> 2;
michael@0 485 in ^= in >> 1;
michael@0 486 return (BYTE)(out ^ !(in & 1));
michael@0 487 }
michael@0 488
michael@0 489 /*
michael@0 490 * Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j]
michael@0 491 * for TDEA Monte Carlo Test (MCT) in ECB and CBC modes.
michael@0 492 */
michael@0 493 void
michael@0 494 tdea_mct_next_keys(unsigned char *key,
michael@0 495 const unsigned char *text_2, const unsigned char *text_1,
michael@0 496 const unsigned char *text, unsigned int numKeys)
michael@0 497 {
michael@0 498 int k;
michael@0 499
michael@0 500 /* key1[i+1] = key1[i] xor PT/CT[j] */
michael@0 501 for (k=0; k<8; k++) {
michael@0 502 key[k] ^= text[k];
michael@0 503 }
michael@0 504 /* key2 */
michael@0 505 if (numKeys == 2 || numKeys == 3) {
michael@0 506 /* key2 independent */
michael@0 507 for (k=8; k<16; k++) {
michael@0 508 /* key2[i+1] = KEY2[i] xor PT/CT[j-1] */
michael@0 509 key[k] ^= text_1[k-8];
michael@0 510 }
michael@0 511 } else {
michael@0 512 /* key2 == key 1 */
michael@0 513 for (k=8; k<16; k++) {
michael@0 514 /* key2[i+1] = KEY2[i] xor PT/CT[j] */
michael@0 515 key[k] = key[k-8];
michael@0 516 }
michael@0 517 }
michael@0 518 /* key3 */
michael@0 519 if (numKeys == 1 || numKeys == 2) {
michael@0 520 /* key3 == key 1 */
michael@0 521 for (k=16; k<24; k++) {
michael@0 522 /* key3[i+1] = KEY3[i] xor PT/CT[j] */
michael@0 523 key[k] = key[k-16];
michael@0 524 }
michael@0 525 } else {
michael@0 526 /* key3 independent */
michael@0 527 for (k=16; k<24; k++) {
michael@0 528 /* key3[i+1] = KEY3[i] xor PT/CT[j-2] */
michael@0 529 key[k] ^= text_2[k-16];
michael@0 530 }
michael@0 531 }
michael@0 532 /* set the parity bits */
michael@0 533 for (k=0; k<24; k++) {
michael@0 534 key[k] = odd_parity(key[k]);
michael@0 535 }
michael@0 536 }
michael@0 537
michael@0 538 /*
michael@0 539 * Perform the Monte Carlo Test
michael@0 540 *
michael@0 541 * mode = NSS_DES_EDE3 or NSS_DES_EDE3_CBC
michael@0 542 * crypt = ENCRYPT || DECRYPT
michael@0 543 * inputtext = plaintext or Cyphertext depending on the value of crypt
michael@0 544 * inputlength is expected to be size 8 bytes
michael@0 545 * iv = needs to be set for NSS_DES_EDE3_CBC mode
michael@0 546 * resp = is the output response file.
michael@0 547 */
michael@0 548 void
michael@0 549 tdea_mct_test(int mode, unsigned char* key, unsigned int numKeys,
michael@0 550 unsigned int crypt, unsigned char* inputtext,
michael@0 551 unsigned int inputlength, unsigned char* iv, FILE *resp) {
michael@0 552
michael@0 553 int i, j;
michael@0 554 unsigned char outputtext_1[8]; /* PT/CT[j-1] */
michael@0 555 unsigned char outputtext_2[8]; /* PT/CT[j-2] */
michael@0 556 char buf[80]; /* holds one line from the input REQUEST file. */
michael@0 557 unsigned int outputlen;
michael@0 558 unsigned char outputtext[8];
michael@0 559
michael@0 560
michael@0 561 SECStatus rv;
michael@0 562
michael@0 563 if (mode == NSS_DES_EDE3 && iv != NULL) {
michael@0 564 printf("IV must be NULL for NSS_DES_EDE3 mode");
michael@0 565 goto loser;
michael@0 566 } else if (mode == NSS_DES_EDE3_CBC && iv == NULL) {
michael@0 567 printf("IV must not be NULL for NSS_DES_EDE3_CBC mode");
michael@0 568 goto loser;
michael@0 569 }
michael@0 570
michael@0 571 /* loop 400 times */
michael@0 572 for (i=0; i<400; i++) {
michael@0 573 /* if i == 0 CV[0] = IV not necessary */
michael@0 574 /* record the count and key values and plainText */
michael@0 575 sprintf(buf, "COUNT = %d\n", i);
michael@0 576 fputs(buf, resp);
michael@0 577 /* Output KEY1[i] */
michael@0 578 fputs("KEY1 = ", resp);
michael@0 579 to_hex_str(buf, key, 8);
michael@0 580 fputs(buf, resp);
michael@0 581 fputc('\n', resp);
michael@0 582 /* Output KEY2[i] */
michael@0 583 fputs("KEY2 = ", resp);
michael@0 584 to_hex_str(buf, &key[8], 8);
michael@0 585 fputs(buf, resp);
michael@0 586 fputc('\n', resp);
michael@0 587 /* Output KEY3[i] */
michael@0 588 fputs("KEY3 = ", resp);
michael@0 589 to_hex_str(buf, &key[16], 8);
michael@0 590 fputs(buf, resp);
michael@0 591 fputc('\n', resp);
michael@0 592 if (mode == NSS_DES_EDE3_CBC) {
michael@0 593 /* Output CV[i] */
michael@0 594 fputs("IV = ", resp);
michael@0 595 to_hex_str(buf, iv, 8);
michael@0 596 fputs(buf, resp);
michael@0 597 fputc('\n', resp);
michael@0 598 }
michael@0 599 if (crypt == ENCRYPT) {
michael@0 600 /* Output PT[0] */
michael@0 601 fputs("PLAINTEXT = ", resp);
michael@0 602 } else {
michael@0 603 /* Output CT[0] */
michael@0 604 fputs("CIPHERTEXT = ", resp);
michael@0 605 }
michael@0 606
michael@0 607 to_hex_str(buf, inputtext, inputlength);
michael@0 608 fputs(buf, resp);
michael@0 609 fputc('\n', resp);
michael@0 610
michael@0 611 /* loop 10,000 times */
michael@0 612 for (j=0; j<10000; j++) {
michael@0 613
michael@0 614 outputlen = 0;
michael@0 615 if (crypt == ENCRYPT) {
michael@0 616 /* inputtext == ciphertext outputtext == plaintext*/
michael@0 617 rv = tdea_encrypt_buf(mode, key,
michael@0 618 (mode == NSS_DES_EDE3) ? NULL : iv,
michael@0 619 outputtext, &outputlen, 8,
michael@0 620 inputtext, 8);
michael@0 621 } else {
michael@0 622 /* inputtext == plaintext outputtext == ciphertext */
michael@0 623 rv = tdea_decrypt_buf(mode, key,
michael@0 624 (mode == NSS_DES_EDE3) ? NULL : iv,
michael@0 625 outputtext, &outputlen, 8,
michael@0 626 inputtext, 8);
michael@0 627 }
michael@0 628
michael@0 629 if (rv != SECSuccess) {
michael@0 630 goto loser;
michael@0 631 }
michael@0 632 if (outputlen != inputlength) {
michael@0 633 goto loser;
michael@0 634 }
michael@0 635
michael@0 636 if (mode == NSS_DES_EDE3_CBC) {
michael@0 637 if (crypt == ENCRYPT) {
michael@0 638 if (j == 0) {
michael@0 639 /*P[j+1] = CV[0] */
michael@0 640 memcpy(inputtext, iv, 8);
michael@0 641 } else {
michael@0 642 /* p[j+1] = C[j-1] */
michael@0 643 memcpy(inputtext, outputtext_1, 8);
michael@0 644 }
michael@0 645 /* CV[j+1] = C[j] */
michael@0 646 memcpy(iv, outputtext, 8);
michael@0 647 if (j != 9999) {
michael@0 648 /* save C[j-1] */
michael@0 649 memcpy(outputtext_1, outputtext, 8);
michael@0 650 }
michael@0 651 } else { /* DECRYPT */
michael@0 652 /* CV[j+1] = C[j] */
michael@0 653 memcpy(iv, inputtext, 8);
michael@0 654 /* C[j+1] = P[j] */
michael@0 655 memcpy(inputtext, outputtext, 8);
michael@0 656 }
michael@0 657 } else {
michael@0 658 /* ECB mode PT/CT[j+1] = CT/PT[j] */
michael@0 659 memcpy(inputtext, outputtext, 8);
michael@0 660 }
michael@0 661
michael@0 662 /* Save PT/CT[j-2] and PT/CT[j-1] */
michael@0 663 if (j==9997) memcpy(outputtext_2, outputtext, 8);
michael@0 664 if (j==9998) memcpy(outputtext_1, outputtext, 8);
michael@0 665 /* done at the end of the for(j) loop */
michael@0 666 }
michael@0 667
michael@0 668
michael@0 669 if (crypt == ENCRYPT) {
michael@0 670 /* Output CT[j] */
michael@0 671 fputs("CIPHERTEXT = ", resp);
michael@0 672 } else {
michael@0 673 /* Output PT[j] */
michael@0 674 fputs("PLAINTEXT = ", resp);
michael@0 675 }
michael@0 676 to_hex_str(buf, outputtext, 8);
michael@0 677 fputs(buf, resp);
michael@0 678 fputc('\n', resp);
michael@0 679
michael@0 680 /* Key[i+1] = Key[i] xor ... outputtext_2 == PT/CT[j-2]
michael@0 681 * outputtext_1 == PT/CT[j-1] outputtext == PT/CT[j]
michael@0 682 */
michael@0 683 tdea_mct_next_keys(key, outputtext_2,
michael@0 684 outputtext_1, outputtext, numKeys);
michael@0 685
michael@0 686 if (mode == NSS_DES_EDE3_CBC) {
michael@0 687 /* taken care of in the j=9999 iteration */
michael@0 688 if (crypt == ENCRYPT) {
michael@0 689 /* P[i] = C[j-1] */
michael@0 690 /* CV[i] = C[j] */
michael@0 691 } else {
michael@0 692 /* taken care of in the j=9999 iteration */
michael@0 693 /* CV[i] = C[j] */
michael@0 694 /* C[i] = P[j] */
michael@0 695 }
michael@0 696 } else {
michael@0 697 /* ECB PT/CT[i] = PT/CT[j] */
michael@0 698 memcpy(inputtext, outputtext, 8);
michael@0 699 }
michael@0 700 /* done at the end of the for(i) loop */
michael@0 701 fputc('\n', resp);
michael@0 702 }
michael@0 703
michael@0 704 loser:
michael@0 705 return;
michael@0 706 }
michael@0 707
michael@0 708 /*
michael@0 709 * Perform the TDEA Monte Carlo Test (MCT) in ECB/CBC modes.
michael@0 710 * by gathering the input from the request file, and then
michael@0 711 * calling tdea_mct_test.
michael@0 712 *
michael@0 713 * reqfn is the pathname of the input REQUEST file.
michael@0 714 *
michael@0 715 * The output RESPONSE file is written to stdout.
michael@0 716 */
michael@0 717 void
michael@0 718 tdea_mct(int mode, char *reqfn)
michael@0 719 {
michael@0 720 int i, j;
michael@0 721 char buf[80]; /* holds one line from the input REQUEST file. */
michael@0 722 FILE *req; /* input stream from the REQUEST file */
michael@0 723 FILE *resp; /* output stream to the RESPONSE file */
michael@0 724 unsigned int crypt = 0; /* 1 means encrypt, 0 means decrypt */
michael@0 725 unsigned char key[24]; /* TDEA 3 key bundle */
michael@0 726 unsigned int numKeys = 0;
michael@0 727 unsigned char plaintext[8]; /* PT[j] */
michael@0 728 unsigned char ciphertext[8]; /* CT[j] */
michael@0 729 unsigned char iv[8];
michael@0 730
michael@0 731 /* zeroize the variables for the test with this data set */
michael@0 732 memset(key, 0, sizeof key);
michael@0 733 memset(plaintext, 0, sizeof plaintext);
michael@0 734 memset(ciphertext, 0, sizeof ciphertext);
michael@0 735 memset(iv, 0, sizeof iv);
michael@0 736
michael@0 737 req = fopen(reqfn, "r");
michael@0 738 resp = stdout;
michael@0 739 while (fgets(buf, sizeof buf, req) != NULL) {
michael@0 740 /* a comment or blank line */
michael@0 741 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 742 fputs(buf, resp);
michael@0 743 continue;
michael@0 744 }
michael@0 745 /* [ENCRYPT] or [DECRYPT] */
michael@0 746 if (buf[0] == '[') {
michael@0 747 if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
michael@0 748 crypt = ENCRYPT;
michael@0 749 } else {
michael@0 750 crypt = DECRYPT;
michael@0 751 }
michael@0 752 fputs(buf, resp);
michael@0 753 continue;
michael@0 754 }
michael@0 755 /* NumKeys */
michael@0 756 if (strncmp(&buf[0], "NumKeys", 7) == 0) {
michael@0 757 i = 7;
michael@0 758 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 759 i++;
michael@0 760 }
michael@0 761 numKeys = atoi(&buf[i]);
michael@0 762 continue;
michael@0 763 }
michael@0 764 /* KEY1 = ... */
michael@0 765 if (strncmp(buf, "KEY1", 4) == 0) {
michael@0 766 i = 4;
michael@0 767 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 768 i++;
michael@0 769 }
michael@0 770 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 771 hex_to_byteval(&buf[i], &key[j]);
michael@0 772 }
michael@0 773 continue;
michael@0 774 }
michael@0 775 /* KEY2 = ... */
michael@0 776 if (strncmp(buf, "KEY2", 4) == 0) {
michael@0 777 i = 4;
michael@0 778 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 779 i++;
michael@0 780 }
michael@0 781 for (j=8; isxdigit(buf[i]); i+=2,j++) {
michael@0 782 hex_to_byteval(&buf[i], &key[j]);
michael@0 783 }
michael@0 784 continue;
michael@0 785 }
michael@0 786 /* KEY3 = ... */
michael@0 787 if (strncmp(buf, "KEY3", 4) == 0) {
michael@0 788 i = 4;
michael@0 789 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 790 i++;
michael@0 791 }
michael@0 792 for (j=16; isxdigit(buf[i]); i+=2,j++) {
michael@0 793 hex_to_byteval(&buf[i], &key[j]);
michael@0 794 }
michael@0 795 continue;
michael@0 796 }
michael@0 797
michael@0 798 /* IV = ... */
michael@0 799 if (strncmp(buf, "IV", 2) == 0) {
michael@0 800 i = 2;
michael@0 801 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 802 i++;
michael@0 803 }
michael@0 804 for (j=0; j<sizeof iv; i+=2,j++) {
michael@0 805 hex_to_byteval(&buf[i], &iv[j]);
michael@0 806 }
michael@0 807 continue;
michael@0 808 }
michael@0 809
michael@0 810 /* PLAINTEXT = ... */
michael@0 811 if (strncmp(buf, "PLAINTEXT", 9) == 0) {
michael@0 812
michael@0 813 /* sanity check */
michael@0 814 if (crypt != ENCRYPT) {
michael@0 815 goto loser;
michael@0 816 }
michael@0 817 /* PT[0] = PT */
michael@0 818 i = 9;
michael@0 819 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 820 i++;
michael@0 821 }
michael@0 822 for (j=0; j<sizeof plaintext; i+=2,j++) {
michael@0 823 hex_to_byteval(&buf[i], &plaintext[j]);
michael@0 824 }
michael@0 825
michael@0 826 /* do the Monte Carlo test */
michael@0 827 if (mode==NSS_DES_EDE3) {
michael@0 828 tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, plaintext, sizeof plaintext, NULL, resp);
michael@0 829 } else {
michael@0 830 tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, plaintext, sizeof plaintext, iv, resp);
michael@0 831 }
michael@0 832 continue;
michael@0 833 }
michael@0 834 /* CIPHERTEXT = ... */
michael@0 835 if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
michael@0 836 /* sanity check */
michael@0 837 if (crypt != DECRYPT) {
michael@0 838 goto loser;
michael@0 839 }
michael@0 840 /* CT[0] = CT */
michael@0 841 i = 10;
michael@0 842 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 843 i++;
michael@0 844 }
michael@0 845 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 846 hex_to_byteval(&buf[i], &ciphertext[j]);
michael@0 847 }
michael@0 848
michael@0 849 /* do the Monte Carlo test */
michael@0 850 if (mode==NSS_DES_EDE3) {
michael@0 851 tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, ciphertext, sizeof ciphertext, NULL, resp);
michael@0 852 } else {
michael@0 853 tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, ciphertext, sizeof ciphertext, iv, resp);
michael@0 854 }
michael@0 855 continue;
michael@0 856 }
michael@0 857 }
michael@0 858
michael@0 859 loser:
michael@0 860 fclose(req);
michael@0 861 }
michael@0 862
michael@0 863
michael@0 864 SECStatus
michael@0 865 aes_encrypt_buf(
michael@0 866 int mode,
michael@0 867 const unsigned char *key, unsigned int keysize,
michael@0 868 const unsigned char *iv,
michael@0 869 unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
michael@0 870 const unsigned char *input, unsigned int inputlen)
michael@0 871 {
michael@0 872 SECStatus rv = SECFailure;
michael@0 873 AESContext *cx;
michael@0 874 unsigned char doublecheck[10*16]; /* 1 to 10 blocks */
michael@0 875 unsigned int doublechecklen = 0;
michael@0 876
michael@0 877 cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
michael@0 878 if (cx == NULL) {
michael@0 879 goto loser;
michael@0 880 }
michael@0 881 rv = AES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
michael@0 882 if (rv != SECSuccess) {
michael@0 883 goto loser;
michael@0 884 }
michael@0 885 if (*outputlen != inputlen) {
michael@0 886 goto loser;
michael@0 887 }
michael@0 888 AES_DestroyContext(cx, PR_TRUE);
michael@0 889 cx = NULL;
michael@0 890
michael@0 891 /*
michael@0 892 * Doublecheck our result by decrypting the ciphertext and
michael@0 893 * compare the output with the input plaintext.
michael@0 894 */
michael@0 895 cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
michael@0 896 if (cx == NULL) {
michael@0 897 goto loser;
michael@0 898 }
michael@0 899 rv = AES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
michael@0 900 output, *outputlen);
michael@0 901 if (rv != SECSuccess) {
michael@0 902 goto loser;
michael@0 903 }
michael@0 904 if (doublechecklen != *outputlen) {
michael@0 905 goto loser;
michael@0 906 }
michael@0 907 AES_DestroyContext(cx, PR_TRUE);
michael@0 908 cx = NULL;
michael@0 909 if (memcmp(doublecheck, input, inputlen) != 0) {
michael@0 910 goto loser;
michael@0 911 }
michael@0 912 rv = SECSuccess;
michael@0 913
michael@0 914 loser:
michael@0 915 if (cx != NULL) {
michael@0 916 AES_DestroyContext(cx, PR_TRUE);
michael@0 917 }
michael@0 918 return rv;
michael@0 919 }
michael@0 920
michael@0 921 SECStatus
michael@0 922 aes_decrypt_buf(
michael@0 923 int mode,
michael@0 924 const unsigned char *key, unsigned int keysize,
michael@0 925 const unsigned char *iv,
michael@0 926 unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
michael@0 927 const unsigned char *input, unsigned int inputlen)
michael@0 928 {
michael@0 929 SECStatus rv = SECFailure;
michael@0 930 AESContext *cx;
michael@0 931 unsigned char doublecheck[10*16]; /* 1 to 10 blocks */
michael@0 932 unsigned int doublechecklen = 0;
michael@0 933
michael@0 934 cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
michael@0 935 if (cx == NULL) {
michael@0 936 goto loser;
michael@0 937 }
michael@0 938 rv = AES_Decrypt(cx, output, outputlen, maxoutputlen,
michael@0 939 input, inputlen);
michael@0 940 if (rv != SECSuccess) {
michael@0 941 goto loser;
michael@0 942 }
michael@0 943 if (*outputlen != inputlen) {
michael@0 944 goto loser;
michael@0 945 }
michael@0 946 AES_DestroyContext(cx, PR_TRUE);
michael@0 947 cx = NULL;
michael@0 948
michael@0 949 /*
michael@0 950 * Doublecheck our result by encrypting the plaintext and
michael@0 951 * compare the output with the input ciphertext.
michael@0 952 */
michael@0 953 cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
michael@0 954 if (cx == NULL) {
michael@0 955 goto loser;
michael@0 956 }
michael@0 957 rv = AES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
michael@0 958 output, *outputlen);
michael@0 959 if (rv != SECSuccess) {
michael@0 960 goto loser;
michael@0 961 }
michael@0 962 if (doublechecklen != *outputlen) {
michael@0 963 goto loser;
michael@0 964 }
michael@0 965 AES_DestroyContext(cx, PR_TRUE);
michael@0 966 cx = NULL;
michael@0 967 if (memcmp(doublecheck, input, inputlen) != 0) {
michael@0 968 goto loser;
michael@0 969 }
michael@0 970 rv = SECSuccess;
michael@0 971
michael@0 972 loser:
michael@0 973 if (cx != NULL) {
michael@0 974 AES_DestroyContext(cx, PR_TRUE);
michael@0 975 }
michael@0 976 return rv;
michael@0 977 }
michael@0 978
michael@0 979 /*
michael@0 980 * Perform the AES Known Answer Test (KAT) or Multi-block Message
michael@0 981 * Test (MMT) in ECB or CBC mode. The KAT (there are four types)
michael@0 982 * and MMT have the same structure: given the key and IV (CBC mode
michael@0 983 * only), encrypt the given plaintext or decrypt the given ciphertext.
michael@0 984 * So we can handle them the same way.
michael@0 985 *
michael@0 986 * reqfn is the pathname of the REQUEST file.
michael@0 987 *
michael@0 988 * The output RESPONSE file is written to stdout.
michael@0 989 */
michael@0 990 void
michael@0 991 aes_kat_mmt(char *reqfn)
michael@0 992 {
michael@0 993 char buf[512]; /* holds one line from the input REQUEST file.
michael@0 994 * needs to be large enough to hold the longest
michael@0 995 * line "CIPHERTEXT = <320 hex digits>\n".
michael@0 996 */
michael@0 997 FILE *aesreq; /* input stream from the REQUEST file */
michael@0 998 FILE *aesresp; /* output stream to the RESPONSE file */
michael@0 999 int i, j;
michael@0 1000 int mode; /* NSS_AES (ECB) or NSS_AES_CBC */
michael@0 1001 int encrypt = 0; /* 1 means encrypt, 0 means decrypt */
michael@0 1002 unsigned char key[32]; /* 128, 192, or 256 bits */
michael@0 1003 unsigned int keysize;
michael@0 1004 unsigned char iv[16]; /* for all modes except ECB */
michael@0 1005 unsigned char plaintext[10*16]; /* 1 to 10 blocks */
michael@0 1006 unsigned int plaintextlen;
michael@0 1007 unsigned char ciphertext[10*16]; /* 1 to 10 blocks */
michael@0 1008 unsigned int ciphertextlen;
michael@0 1009 SECStatus rv;
michael@0 1010
michael@0 1011 aesreq = fopen(reqfn, "r");
michael@0 1012 aesresp = stdout;
michael@0 1013 while (fgets(buf, sizeof buf, aesreq) != NULL) {
michael@0 1014 /* a comment or blank line */
michael@0 1015 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 1016 fputs(buf, aesresp);
michael@0 1017 continue;
michael@0 1018 }
michael@0 1019 /* [ENCRYPT] or [DECRYPT] */
michael@0 1020 if (buf[0] == '[') {
michael@0 1021 if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
michael@0 1022 encrypt = 1;
michael@0 1023 } else {
michael@0 1024 encrypt = 0;
michael@0 1025 }
michael@0 1026 fputs(buf, aesresp);
michael@0 1027 continue;
michael@0 1028 }
michael@0 1029 /* "COUNT = x" begins a new data set */
michael@0 1030 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 1031 mode = NSS_AES;
michael@0 1032 /* zeroize the variables for the test with this data set */
michael@0 1033 memset(key, 0, sizeof key);
michael@0 1034 keysize = 0;
michael@0 1035 memset(iv, 0, sizeof iv);
michael@0 1036 memset(plaintext, 0, sizeof plaintext);
michael@0 1037 plaintextlen = 0;
michael@0 1038 memset(ciphertext, 0, sizeof ciphertext);
michael@0 1039 ciphertextlen = 0;
michael@0 1040 fputs(buf, aesresp);
michael@0 1041 continue;
michael@0 1042 }
michael@0 1043 /* KEY = ... */
michael@0 1044 if (strncmp(buf, "KEY", 3) == 0) {
michael@0 1045 i = 3;
michael@0 1046 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1047 i++;
michael@0 1048 }
michael@0 1049 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1050 hex_to_byteval(&buf[i], &key[j]);
michael@0 1051 }
michael@0 1052 keysize = j;
michael@0 1053 fputs(buf, aesresp);
michael@0 1054 continue;
michael@0 1055 }
michael@0 1056 /* IV = ... */
michael@0 1057 if (strncmp(buf, "IV", 2) == 0) {
michael@0 1058 mode = NSS_AES_CBC;
michael@0 1059 i = 2;
michael@0 1060 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1061 i++;
michael@0 1062 }
michael@0 1063 for (j=0; j<sizeof iv; i+=2,j++) {
michael@0 1064 hex_to_byteval(&buf[i], &iv[j]);
michael@0 1065 }
michael@0 1066 fputs(buf, aesresp);
michael@0 1067 continue;
michael@0 1068 }
michael@0 1069 /* PLAINTEXT = ... */
michael@0 1070 if (strncmp(buf, "PLAINTEXT", 9) == 0) {
michael@0 1071 /* sanity check */
michael@0 1072 if (!encrypt) {
michael@0 1073 goto loser;
michael@0 1074 }
michael@0 1075
michael@0 1076 i = 9;
michael@0 1077 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1078 i++;
michael@0 1079 }
michael@0 1080 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1081 hex_to_byteval(&buf[i], &plaintext[j]);
michael@0 1082 }
michael@0 1083 plaintextlen = j;
michael@0 1084
michael@0 1085 rv = aes_encrypt_buf(mode, key, keysize,
michael@0 1086 (mode == NSS_AES) ? NULL : iv,
michael@0 1087 ciphertext, &ciphertextlen, sizeof ciphertext,
michael@0 1088 plaintext, plaintextlen);
michael@0 1089 if (rv != SECSuccess) {
michael@0 1090 goto loser;
michael@0 1091 }
michael@0 1092
michael@0 1093 fputs(buf, aesresp);
michael@0 1094 fputs("CIPHERTEXT = ", aesresp);
michael@0 1095 to_hex_str(buf, ciphertext, ciphertextlen);
michael@0 1096 fputs(buf, aesresp);
michael@0 1097 fputc('\n', aesresp);
michael@0 1098 continue;
michael@0 1099 }
michael@0 1100 /* CIPHERTEXT = ... */
michael@0 1101 if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
michael@0 1102 /* sanity check */
michael@0 1103 if (encrypt) {
michael@0 1104 goto loser;
michael@0 1105 }
michael@0 1106
michael@0 1107 i = 10;
michael@0 1108 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1109 i++;
michael@0 1110 }
michael@0 1111 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1112 hex_to_byteval(&buf[i], &ciphertext[j]);
michael@0 1113 }
michael@0 1114 ciphertextlen = j;
michael@0 1115
michael@0 1116 rv = aes_decrypt_buf(mode, key, keysize,
michael@0 1117 (mode == NSS_AES) ? NULL : iv,
michael@0 1118 plaintext, &plaintextlen, sizeof plaintext,
michael@0 1119 ciphertext, ciphertextlen);
michael@0 1120 if (rv != SECSuccess) {
michael@0 1121 goto loser;
michael@0 1122 }
michael@0 1123
michael@0 1124 fputs(buf, aesresp);
michael@0 1125 fputs("PLAINTEXT = ", aesresp);
michael@0 1126 to_hex_str(buf, plaintext, plaintextlen);
michael@0 1127 fputs(buf, aesresp);
michael@0 1128 fputc('\n', aesresp);
michael@0 1129 continue;
michael@0 1130 }
michael@0 1131 }
michael@0 1132 loser:
michael@0 1133 fclose(aesreq);
michael@0 1134 }
michael@0 1135
michael@0 1136 /*
michael@0 1137 * Generate Key[i+1] from Key[i], CT[j-1], and CT[j] for AES Monte Carlo
michael@0 1138 * Test (MCT) in ECB and CBC modes.
michael@0 1139 */
michael@0 1140 void
michael@0 1141 aes_mct_next_key(unsigned char *key, unsigned int keysize,
michael@0 1142 const unsigned char *ciphertext_1, const unsigned char *ciphertext)
michael@0 1143 {
michael@0 1144 int k;
michael@0 1145
michael@0 1146 switch (keysize) {
michael@0 1147 case 16: /* 128-bit key */
michael@0 1148 /* Key[i+1] = Key[i] xor CT[j] */
michael@0 1149 for (k=0; k<16; k++) {
michael@0 1150 key[k] ^= ciphertext[k];
michael@0 1151 }
michael@0 1152 break;
michael@0 1153 case 24: /* 192-bit key */
michael@0 1154 /*
michael@0 1155 * Key[i+1] = Key[i] xor (last 64-bits of
michael@0 1156 * CT[j-1] || CT[j])
michael@0 1157 */
michael@0 1158 for (k=0; k<8; k++) {
michael@0 1159 key[k] ^= ciphertext_1[k+8];
michael@0 1160 }
michael@0 1161 for (k=8; k<24; k++) {
michael@0 1162 key[k] ^= ciphertext[k-8];
michael@0 1163 }
michael@0 1164 break;
michael@0 1165 case 32: /* 256-bit key */
michael@0 1166 /* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */
michael@0 1167 for (k=0; k<16; k++) {
michael@0 1168 key[k] ^= ciphertext_1[k];
michael@0 1169 }
michael@0 1170 for (k=16; k<32; k++) {
michael@0 1171 key[k] ^= ciphertext[k-16];
michael@0 1172 }
michael@0 1173 break;
michael@0 1174 }
michael@0 1175 }
michael@0 1176
michael@0 1177 /*
michael@0 1178 * Perform the AES Monte Carlo Test (MCT) in ECB mode. MCT exercises
michael@0 1179 * our AES code in streaming mode because the plaintext or ciphertext
michael@0 1180 * is generated block by block as we go, so we can't collect all the
michael@0 1181 * plaintext or ciphertext in one buffer and encrypt or decrypt it in
michael@0 1182 * one shot.
michael@0 1183 *
michael@0 1184 * reqfn is the pathname of the input REQUEST file.
michael@0 1185 *
michael@0 1186 * The output RESPONSE file is written to stdout.
michael@0 1187 */
michael@0 1188 void
michael@0 1189 aes_ecb_mct(char *reqfn)
michael@0 1190 {
michael@0 1191 char buf[80]; /* holds one line from the input REQUEST file.
michael@0 1192 * needs to be large enough to hold the longest
michael@0 1193 * line "KEY = <64 hex digits>\n".
michael@0 1194 */
michael@0 1195 FILE *aesreq; /* input stream from the REQUEST file */
michael@0 1196 FILE *aesresp; /* output stream to the RESPONSE file */
michael@0 1197 int i, j;
michael@0 1198 int encrypt = 0; /* 1 means encrypt, 0 means decrypt */
michael@0 1199 unsigned char key[32]; /* 128, 192, or 256 bits */
michael@0 1200 unsigned int keysize;
michael@0 1201 unsigned char plaintext[16]; /* PT[j] */
michael@0 1202 unsigned char plaintext_1[16]; /* PT[j-1] */
michael@0 1203 unsigned char ciphertext[16]; /* CT[j] */
michael@0 1204 unsigned char ciphertext_1[16]; /* CT[j-1] */
michael@0 1205 unsigned char doublecheck[16];
michael@0 1206 unsigned int outputlen;
michael@0 1207 AESContext *cx = NULL; /* the operation being tested */
michael@0 1208 AESContext *cx2 = NULL; /* the inverse operation done in parallel
michael@0 1209 * to doublecheck our result.
michael@0 1210 */
michael@0 1211 SECStatus rv;
michael@0 1212
michael@0 1213 aesreq = fopen(reqfn, "r");
michael@0 1214 aesresp = stdout;
michael@0 1215 while (fgets(buf, sizeof buf, aesreq) != NULL) {
michael@0 1216 /* a comment or blank line */
michael@0 1217 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 1218 fputs(buf, aesresp);
michael@0 1219 continue;
michael@0 1220 }
michael@0 1221 /* [ENCRYPT] or [DECRYPT] */
michael@0 1222 if (buf[0] == '[') {
michael@0 1223 if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
michael@0 1224 encrypt = 1;
michael@0 1225 } else {
michael@0 1226 encrypt = 0;
michael@0 1227 }
michael@0 1228 fputs(buf, aesresp);
michael@0 1229 continue;
michael@0 1230 }
michael@0 1231 /* "COUNT = x" begins a new data set */
michael@0 1232 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 1233 /* zeroize the variables for the test with this data set */
michael@0 1234 memset(key, 0, sizeof key);
michael@0 1235 keysize = 0;
michael@0 1236 memset(plaintext, 0, sizeof plaintext);
michael@0 1237 memset(ciphertext, 0, sizeof ciphertext);
michael@0 1238 continue;
michael@0 1239 }
michael@0 1240 /* KEY = ... */
michael@0 1241 if (strncmp(buf, "KEY", 3) == 0) {
michael@0 1242 /* Key[0] = Key */
michael@0 1243 i = 3;
michael@0 1244 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1245 i++;
michael@0 1246 }
michael@0 1247 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1248 hex_to_byteval(&buf[i], &key[j]);
michael@0 1249 }
michael@0 1250 keysize = j;
michael@0 1251 continue;
michael@0 1252 }
michael@0 1253 /* PLAINTEXT = ... */
michael@0 1254 if (strncmp(buf, "PLAINTEXT", 9) == 0) {
michael@0 1255 /* sanity check */
michael@0 1256 if (!encrypt) {
michael@0 1257 goto loser;
michael@0 1258 }
michael@0 1259 /* PT[0] = PT */
michael@0 1260 i = 9;
michael@0 1261 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1262 i++;
michael@0 1263 }
michael@0 1264 for (j=0; j<sizeof plaintext; i+=2,j++) {
michael@0 1265 hex_to_byteval(&buf[i], &plaintext[j]);
michael@0 1266 }
michael@0 1267
michael@0 1268 for (i=0; i<100; i++) {
michael@0 1269 sprintf(buf, "COUNT = %d\n", i);
michael@0 1270 fputs(buf, aesresp);
michael@0 1271 /* Output Key[i] */
michael@0 1272 fputs("KEY = ", aesresp);
michael@0 1273 to_hex_str(buf, key, keysize);
michael@0 1274 fputs(buf, aesresp);
michael@0 1275 fputc('\n', aesresp);
michael@0 1276 /* Output PT[0] */
michael@0 1277 fputs("PLAINTEXT = ", aesresp);
michael@0 1278 to_hex_str(buf, plaintext, sizeof plaintext);
michael@0 1279 fputs(buf, aesresp);
michael@0 1280 fputc('\n', aesresp);
michael@0 1281
michael@0 1282 cx = AES_CreateContext(key, NULL, NSS_AES,
michael@0 1283 PR_TRUE, keysize, 16);
michael@0 1284 if (cx == NULL) {
michael@0 1285 goto loser;
michael@0 1286 }
michael@0 1287 /*
michael@0 1288 * doublecheck our result by decrypting the result
michael@0 1289 * and comparing the output with the plaintext.
michael@0 1290 */
michael@0 1291 cx2 = AES_CreateContext(key, NULL, NSS_AES,
michael@0 1292 PR_FALSE, keysize, 16);
michael@0 1293 if (cx2 == NULL) {
michael@0 1294 goto loser;
michael@0 1295 }
michael@0 1296 for (j=0; j<1000; j++) {
michael@0 1297 /* Save CT[j-1] */
michael@0 1298 memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
michael@0 1299
michael@0 1300 /* CT[j] = AES(Key[i], PT[j]) */
michael@0 1301 outputlen = 0;
michael@0 1302 rv = AES_Encrypt(cx,
michael@0 1303 ciphertext, &outputlen, sizeof ciphertext,
michael@0 1304 plaintext, sizeof plaintext);
michael@0 1305 if (rv != SECSuccess) {
michael@0 1306 goto loser;
michael@0 1307 }
michael@0 1308 if (outputlen != sizeof plaintext) {
michael@0 1309 goto loser;
michael@0 1310 }
michael@0 1311
michael@0 1312 /* doublecheck our result */
michael@0 1313 outputlen = 0;
michael@0 1314 rv = AES_Decrypt(cx2,
michael@0 1315 doublecheck, &outputlen, sizeof doublecheck,
michael@0 1316 ciphertext, sizeof ciphertext);
michael@0 1317 if (rv != SECSuccess) {
michael@0 1318 goto loser;
michael@0 1319 }
michael@0 1320 if (outputlen != sizeof ciphertext) {
michael@0 1321 goto loser;
michael@0 1322 }
michael@0 1323 if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
michael@0 1324 goto loser;
michael@0 1325 }
michael@0 1326
michael@0 1327 /* PT[j+1] = CT[j] */
michael@0 1328 memcpy(plaintext, ciphertext, sizeof plaintext);
michael@0 1329 }
michael@0 1330 AES_DestroyContext(cx, PR_TRUE);
michael@0 1331 cx = NULL;
michael@0 1332 AES_DestroyContext(cx2, PR_TRUE);
michael@0 1333 cx2 = NULL;
michael@0 1334
michael@0 1335 /* Output CT[j] */
michael@0 1336 fputs("CIPHERTEXT = ", aesresp);
michael@0 1337 to_hex_str(buf, ciphertext, sizeof ciphertext);
michael@0 1338 fputs(buf, aesresp);
michael@0 1339 fputc('\n', aesresp);
michael@0 1340
michael@0 1341 /* Key[i+1] = Key[i] xor ... */
michael@0 1342 aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
michael@0 1343 /* PT[0] = CT[j] */
michael@0 1344 /* done at the end of the for(j) loop */
michael@0 1345
michael@0 1346 fputc('\n', aesresp);
michael@0 1347 }
michael@0 1348
michael@0 1349 continue;
michael@0 1350 }
michael@0 1351 /* CIPHERTEXT = ... */
michael@0 1352 if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
michael@0 1353 /* sanity check */
michael@0 1354 if (encrypt) {
michael@0 1355 goto loser;
michael@0 1356 }
michael@0 1357 /* CT[0] = CT */
michael@0 1358 i = 10;
michael@0 1359 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1360 i++;
michael@0 1361 }
michael@0 1362 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1363 hex_to_byteval(&buf[i], &ciphertext[j]);
michael@0 1364 }
michael@0 1365
michael@0 1366 for (i=0; i<100; i++) {
michael@0 1367 sprintf(buf, "COUNT = %d\n", i);
michael@0 1368 fputs(buf, aesresp);
michael@0 1369 /* Output Key[i] */
michael@0 1370 fputs("KEY = ", aesresp);
michael@0 1371 to_hex_str(buf, key, keysize);
michael@0 1372 fputs(buf, aesresp);
michael@0 1373 fputc('\n', aesresp);
michael@0 1374 /* Output CT[0] */
michael@0 1375 fputs("CIPHERTEXT = ", aesresp);
michael@0 1376 to_hex_str(buf, ciphertext, sizeof ciphertext);
michael@0 1377 fputs(buf, aesresp);
michael@0 1378 fputc('\n', aesresp);
michael@0 1379
michael@0 1380 cx = AES_CreateContext(key, NULL, NSS_AES,
michael@0 1381 PR_FALSE, keysize, 16);
michael@0 1382 if (cx == NULL) {
michael@0 1383 goto loser;
michael@0 1384 }
michael@0 1385 /*
michael@0 1386 * doublecheck our result by encrypting the result
michael@0 1387 * and comparing the output with the ciphertext.
michael@0 1388 */
michael@0 1389 cx2 = AES_CreateContext(key, NULL, NSS_AES,
michael@0 1390 PR_TRUE, keysize, 16);
michael@0 1391 if (cx2 == NULL) {
michael@0 1392 goto loser;
michael@0 1393 }
michael@0 1394 for (j=0; j<1000; j++) {
michael@0 1395 /* Save PT[j-1] */
michael@0 1396 memcpy(plaintext_1, plaintext, sizeof plaintext);
michael@0 1397
michael@0 1398 /* PT[j] = AES(Key[i], CT[j]) */
michael@0 1399 outputlen = 0;
michael@0 1400 rv = AES_Decrypt(cx,
michael@0 1401 plaintext, &outputlen, sizeof plaintext,
michael@0 1402 ciphertext, sizeof ciphertext);
michael@0 1403 if (rv != SECSuccess) {
michael@0 1404 goto loser;
michael@0 1405 }
michael@0 1406 if (outputlen != sizeof ciphertext) {
michael@0 1407 goto loser;
michael@0 1408 }
michael@0 1409
michael@0 1410 /* doublecheck our result */
michael@0 1411 outputlen = 0;
michael@0 1412 rv = AES_Encrypt(cx2,
michael@0 1413 doublecheck, &outputlen, sizeof doublecheck,
michael@0 1414 plaintext, sizeof plaintext);
michael@0 1415 if (rv != SECSuccess) {
michael@0 1416 goto loser;
michael@0 1417 }
michael@0 1418 if (outputlen != sizeof plaintext) {
michael@0 1419 goto loser;
michael@0 1420 }
michael@0 1421 if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
michael@0 1422 goto loser;
michael@0 1423 }
michael@0 1424
michael@0 1425 /* CT[j+1] = PT[j] */
michael@0 1426 memcpy(ciphertext, plaintext, sizeof ciphertext);
michael@0 1427 }
michael@0 1428 AES_DestroyContext(cx, PR_TRUE);
michael@0 1429 cx = NULL;
michael@0 1430 AES_DestroyContext(cx2, PR_TRUE);
michael@0 1431 cx2 = NULL;
michael@0 1432
michael@0 1433 /* Output PT[j] */
michael@0 1434 fputs("PLAINTEXT = ", aesresp);
michael@0 1435 to_hex_str(buf, plaintext, sizeof plaintext);
michael@0 1436 fputs(buf, aesresp);
michael@0 1437 fputc('\n', aesresp);
michael@0 1438
michael@0 1439 /* Key[i+1] = Key[i] xor ... */
michael@0 1440 aes_mct_next_key(key, keysize, plaintext_1, plaintext);
michael@0 1441 /* CT[0] = PT[j] */
michael@0 1442 /* done at the end of the for(j) loop */
michael@0 1443
michael@0 1444 fputc('\n', aesresp);
michael@0 1445 }
michael@0 1446
michael@0 1447 continue;
michael@0 1448 }
michael@0 1449 }
michael@0 1450 loser:
michael@0 1451 if (cx != NULL) {
michael@0 1452 AES_DestroyContext(cx, PR_TRUE);
michael@0 1453 }
michael@0 1454 if (cx2 != NULL) {
michael@0 1455 AES_DestroyContext(cx2, PR_TRUE);
michael@0 1456 }
michael@0 1457 fclose(aesreq);
michael@0 1458 }
michael@0 1459
michael@0 1460 /*
michael@0 1461 * Perform the AES Monte Carlo Test (MCT) in CBC mode. MCT exercises
michael@0 1462 * our AES code in streaming mode because the plaintext or ciphertext
michael@0 1463 * is generated block by block as we go, so we can't collect all the
michael@0 1464 * plaintext or ciphertext in one buffer and encrypt or decrypt it in
michael@0 1465 * one shot.
michael@0 1466 *
michael@0 1467 * reqfn is the pathname of the input REQUEST file.
michael@0 1468 *
michael@0 1469 * The output RESPONSE file is written to stdout.
michael@0 1470 */
michael@0 1471 void
michael@0 1472 aes_cbc_mct(char *reqfn)
michael@0 1473 {
michael@0 1474 char buf[80]; /* holds one line from the input REQUEST file.
michael@0 1475 * needs to be large enough to hold the longest
michael@0 1476 * line "KEY = <64 hex digits>\n".
michael@0 1477 */
michael@0 1478 FILE *aesreq; /* input stream from the REQUEST file */
michael@0 1479 FILE *aesresp; /* output stream to the RESPONSE file */
michael@0 1480 int i, j;
michael@0 1481 int encrypt = 0; /* 1 means encrypt, 0 means decrypt */
michael@0 1482 unsigned char key[32]; /* 128, 192, or 256 bits */
michael@0 1483 unsigned int keysize;
michael@0 1484 unsigned char iv[16];
michael@0 1485 unsigned char plaintext[16]; /* PT[j] */
michael@0 1486 unsigned char plaintext_1[16]; /* PT[j-1] */
michael@0 1487 unsigned char ciphertext[16]; /* CT[j] */
michael@0 1488 unsigned char ciphertext_1[16]; /* CT[j-1] */
michael@0 1489 unsigned char doublecheck[16];
michael@0 1490 unsigned int outputlen;
michael@0 1491 AESContext *cx = NULL; /* the operation being tested */
michael@0 1492 AESContext *cx2 = NULL; /* the inverse operation done in parallel
michael@0 1493 * to doublecheck our result.
michael@0 1494 */
michael@0 1495 SECStatus rv;
michael@0 1496
michael@0 1497 aesreq = fopen(reqfn, "r");
michael@0 1498 aesresp = stdout;
michael@0 1499 while (fgets(buf, sizeof buf, aesreq) != NULL) {
michael@0 1500 /* a comment or blank line */
michael@0 1501 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 1502 fputs(buf, aesresp);
michael@0 1503 continue;
michael@0 1504 }
michael@0 1505 /* [ENCRYPT] or [DECRYPT] */
michael@0 1506 if (buf[0] == '[') {
michael@0 1507 if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
michael@0 1508 encrypt = 1;
michael@0 1509 } else {
michael@0 1510 encrypt = 0;
michael@0 1511 }
michael@0 1512 fputs(buf, aesresp);
michael@0 1513 continue;
michael@0 1514 }
michael@0 1515 /* "COUNT = x" begins a new data set */
michael@0 1516 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 1517 /* zeroize the variables for the test with this data set */
michael@0 1518 memset(key, 0, sizeof key);
michael@0 1519 keysize = 0;
michael@0 1520 memset(iv, 0, sizeof iv);
michael@0 1521 memset(plaintext, 0, sizeof plaintext);
michael@0 1522 memset(ciphertext, 0, sizeof ciphertext);
michael@0 1523 continue;
michael@0 1524 }
michael@0 1525 /* KEY = ... */
michael@0 1526 if (strncmp(buf, "KEY", 3) == 0) {
michael@0 1527 /* Key[0] = Key */
michael@0 1528 i = 3;
michael@0 1529 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1530 i++;
michael@0 1531 }
michael@0 1532 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1533 hex_to_byteval(&buf[i], &key[j]);
michael@0 1534 }
michael@0 1535 keysize = j;
michael@0 1536 continue;
michael@0 1537 }
michael@0 1538 /* IV = ... */
michael@0 1539 if (strncmp(buf, "IV", 2) == 0) {
michael@0 1540 /* IV[0] = IV */
michael@0 1541 i = 2;
michael@0 1542 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1543 i++;
michael@0 1544 }
michael@0 1545 for (j=0; j<sizeof iv; i+=2,j++) {
michael@0 1546 hex_to_byteval(&buf[i], &iv[j]);
michael@0 1547 }
michael@0 1548 continue;
michael@0 1549 }
michael@0 1550 /* PLAINTEXT = ... */
michael@0 1551 if (strncmp(buf, "PLAINTEXT", 9) == 0) {
michael@0 1552 /* sanity check */
michael@0 1553 if (!encrypt) {
michael@0 1554 goto loser;
michael@0 1555 }
michael@0 1556 /* PT[0] = PT */
michael@0 1557 i = 9;
michael@0 1558 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1559 i++;
michael@0 1560 }
michael@0 1561 for (j=0; j<sizeof plaintext; i+=2,j++) {
michael@0 1562 hex_to_byteval(&buf[i], &plaintext[j]);
michael@0 1563 }
michael@0 1564
michael@0 1565 for (i=0; i<100; i++) {
michael@0 1566 sprintf(buf, "COUNT = %d\n", i);
michael@0 1567 fputs(buf, aesresp);
michael@0 1568 /* Output Key[i] */
michael@0 1569 fputs("KEY = ", aesresp);
michael@0 1570 to_hex_str(buf, key, keysize);
michael@0 1571 fputs(buf, aesresp);
michael@0 1572 fputc('\n', aesresp);
michael@0 1573 /* Output IV[i] */
michael@0 1574 fputs("IV = ", aesresp);
michael@0 1575 to_hex_str(buf, iv, sizeof iv);
michael@0 1576 fputs(buf, aesresp);
michael@0 1577 fputc('\n', aesresp);
michael@0 1578 /* Output PT[0] */
michael@0 1579 fputs("PLAINTEXT = ", aesresp);
michael@0 1580 to_hex_str(buf, plaintext, sizeof plaintext);
michael@0 1581 fputs(buf, aesresp);
michael@0 1582 fputc('\n', aesresp);
michael@0 1583
michael@0 1584 cx = AES_CreateContext(key, iv, NSS_AES_CBC,
michael@0 1585 PR_TRUE, keysize, 16);
michael@0 1586 if (cx == NULL) {
michael@0 1587 goto loser;
michael@0 1588 }
michael@0 1589 /*
michael@0 1590 * doublecheck our result by decrypting the result
michael@0 1591 * and comparing the output with the plaintext.
michael@0 1592 */
michael@0 1593 cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
michael@0 1594 PR_FALSE, keysize, 16);
michael@0 1595 if (cx2 == NULL) {
michael@0 1596 goto loser;
michael@0 1597 }
michael@0 1598 /* CT[-1] = IV[i] */
michael@0 1599 memcpy(ciphertext, iv, sizeof ciphertext);
michael@0 1600 for (j=0; j<1000; j++) {
michael@0 1601 /* Save CT[j-1] */
michael@0 1602 memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
michael@0 1603 /*
michael@0 1604 * If ( j=0 )
michael@0 1605 * CT[j] = AES(Key[i], IV[i], PT[j])
michael@0 1606 * PT[j+1] = IV[i] (= CT[j-1])
michael@0 1607 * Else
michael@0 1608 * CT[j] = AES(Key[i], PT[j])
michael@0 1609 * PT[j+1] = CT[j-1]
michael@0 1610 */
michael@0 1611 outputlen = 0;
michael@0 1612 rv = AES_Encrypt(cx,
michael@0 1613 ciphertext, &outputlen, sizeof ciphertext,
michael@0 1614 plaintext, sizeof plaintext);
michael@0 1615 if (rv != SECSuccess) {
michael@0 1616 goto loser;
michael@0 1617 }
michael@0 1618 if (outputlen != sizeof plaintext) {
michael@0 1619 goto loser;
michael@0 1620 }
michael@0 1621
michael@0 1622 /* doublecheck our result */
michael@0 1623 outputlen = 0;
michael@0 1624 rv = AES_Decrypt(cx2,
michael@0 1625 doublecheck, &outputlen, sizeof doublecheck,
michael@0 1626 ciphertext, sizeof ciphertext);
michael@0 1627 if (rv != SECSuccess) {
michael@0 1628 goto loser;
michael@0 1629 }
michael@0 1630 if (outputlen != sizeof ciphertext) {
michael@0 1631 goto loser;
michael@0 1632 }
michael@0 1633 if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
michael@0 1634 goto loser;
michael@0 1635 }
michael@0 1636
michael@0 1637 memcpy(plaintext, ciphertext_1, sizeof plaintext);
michael@0 1638 }
michael@0 1639 AES_DestroyContext(cx, PR_TRUE);
michael@0 1640 cx = NULL;
michael@0 1641 AES_DestroyContext(cx2, PR_TRUE);
michael@0 1642 cx2 = NULL;
michael@0 1643
michael@0 1644 /* Output CT[j] */
michael@0 1645 fputs("CIPHERTEXT = ", aesresp);
michael@0 1646 to_hex_str(buf, ciphertext, sizeof ciphertext);
michael@0 1647 fputs(buf, aesresp);
michael@0 1648 fputc('\n', aesresp);
michael@0 1649
michael@0 1650 /* Key[i+1] = Key[i] xor ... */
michael@0 1651 aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
michael@0 1652 /* IV[i+1] = CT[j] */
michael@0 1653 memcpy(iv, ciphertext, sizeof iv);
michael@0 1654 /* PT[0] = CT[j-1] */
michael@0 1655 /* done at the end of the for(j) loop */
michael@0 1656
michael@0 1657 fputc('\n', aesresp);
michael@0 1658 }
michael@0 1659
michael@0 1660 continue;
michael@0 1661 }
michael@0 1662 /* CIPHERTEXT = ... */
michael@0 1663 if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
michael@0 1664 /* sanity check */
michael@0 1665 if (encrypt) {
michael@0 1666 goto loser;
michael@0 1667 }
michael@0 1668 /* CT[0] = CT */
michael@0 1669 i = 10;
michael@0 1670 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 1671 i++;
michael@0 1672 }
michael@0 1673 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 1674 hex_to_byteval(&buf[i], &ciphertext[j]);
michael@0 1675 }
michael@0 1676
michael@0 1677 for (i=0; i<100; i++) {
michael@0 1678 sprintf(buf, "COUNT = %d\n", i);
michael@0 1679 fputs(buf, aesresp);
michael@0 1680 /* Output Key[i] */
michael@0 1681 fputs("KEY = ", aesresp);
michael@0 1682 to_hex_str(buf, key, keysize);
michael@0 1683 fputs(buf, aesresp);
michael@0 1684 fputc('\n', aesresp);
michael@0 1685 /* Output IV[i] */
michael@0 1686 fputs("IV = ", aesresp);
michael@0 1687 to_hex_str(buf, iv, sizeof iv);
michael@0 1688 fputs(buf, aesresp);
michael@0 1689 fputc('\n', aesresp);
michael@0 1690 /* Output CT[0] */
michael@0 1691 fputs("CIPHERTEXT = ", aesresp);
michael@0 1692 to_hex_str(buf, ciphertext, sizeof ciphertext);
michael@0 1693 fputs(buf, aesresp);
michael@0 1694 fputc('\n', aesresp);
michael@0 1695
michael@0 1696 cx = AES_CreateContext(key, iv, NSS_AES_CBC,
michael@0 1697 PR_FALSE, keysize, 16);
michael@0 1698 if (cx == NULL) {
michael@0 1699 goto loser;
michael@0 1700 }
michael@0 1701 /*
michael@0 1702 * doublecheck our result by encrypting the result
michael@0 1703 * and comparing the output with the ciphertext.
michael@0 1704 */
michael@0 1705 cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
michael@0 1706 PR_TRUE, keysize, 16);
michael@0 1707 if (cx2 == NULL) {
michael@0 1708 goto loser;
michael@0 1709 }
michael@0 1710 /* PT[-1] = IV[i] */
michael@0 1711 memcpy(plaintext, iv, sizeof plaintext);
michael@0 1712 for (j=0; j<1000; j++) {
michael@0 1713 /* Save PT[j-1] */
michael@0 1714 memcpy(plaintext_1, plaintext, sizeof plaintext);
michael@0 1715 /*
michael@0 1716 * If ( j=0 )
michael@0 1717 * PT[j] = AES(Key[i], IV[i], CT[j])
michael@0 1718 * CT[j+1] = IV[i] (= PT[j-1])
michael@0 1719 * Else
michael@0 1720 * PT[j] = AES(Key[i], CT[j])
michael@0 1721 * CT[j+1] = PT[j-1]
michael@0 1722 */
michael@0 1723 outputlen = 0;
michael@0 1724 rv = AES_Decrypt(cx,
michael@0 1725 plaintext, &outputlen, sizeof plaintext,
michael@0 1726 ciphertext, sizeof ciphertext);
michael@0 1727 if (rv != SECSuccess) {
michael@0 1728 goto loser;
michael@0 1729 }
michael@0 1730 if (outputlen != sizeof ciphertext) {
michael@0 1731 goto loser;
michael@0 1732 }
michael@0 1733
michael@0 1734 /* doublecheck our result */
michael@0 1735 outputlen = 0;
michael@0 1736 rv = AES_Encrypt(cx2,
michael@0 1737 doublecheck, &outputlen, sizeof doublecheck,
michael@0 1738 plaintext, sizeof plaintext);
michael@0 1739 if (rv != SECSuccess) {
michael@0 1740 goto loser;
michael@0 1741 }
michael@0 1742 if (outputlen != sizeof plaintext) {
michael@0 1743 goto loser;
michael@0 1744 }
michael@0 1745 if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
michael@0 1746 goto loser;
michael@0 1747 }
michael@0 1748
michael@0 1749 memcpy(ciphertext, plaintext_1, sizeof ciphertext);
michael@0 1750 }
michael@0 1751 AES_DestroyContext(cx, PR_TRUE);
michael@0 1752 cx = NULL;
michael@0 1753 AES_DestroyContext(cx2, PR_TRUE);
michael@0 1754 cx2 = NULL;
michael@0 1755
michael@0 1756 /* Output PT[j] */
michael@0 1757 fputs("PLAINTEXT = ", aesresp);
michael@0 1758 to_hex_str(buf, plaintext, sizeof plaintext);
michael@0 1759 fputs(buf, aesresp);
michael@0 1760 fputc('\n', aesresp);
michael@0 1761
michael@0 1762 /* Key[i+1] = Key[i] xor ... */
michael@0 1763 aes_mct_next_key(key, keysize, plaintext_1, plaintext);
michael@0 1764 /* IV[i+1] = PT[j] */
michael@0 1765 memcpy(iv, plaintext, sizeof iv);
michael@0 1766 /* CT[0] = PT[j-1] */
michael@0 1767 /* done at the end of the for(j) loop */
michael@0 1768
michael@0 1769 fputc('\n', aesresp);
michael@0 1770 }
michael@0 1771
michael@0 1772 continue;
michael@0 1773 }
michael@0 1774 }
michael@0 1775 loser:
michael@0 1776 if (cx != NULL) {
michael@0 1777 AES_DestroyContext(cx, PR_TRUE);
michael@0 1778 }
michael@0 1779 if (cx2 != NULL) {
michael@0 1780 AES_DestroyContext(cx2, PR_TRUE);
michael@0 1781 }
michael@0 1782 fclose(aesreq);
michael@0 1783 }
michael@0 1784
michael@0 1785 void write_compact_string(FILE *out, unsigned char *hash, unsigned int len)
michael@0 1786 {
michael@0 1787 unsigned int i;
michael@0 1788 int j, count = 0, last = -1, z = 0;
michael@0 1789 long start = ftell(out);
michael@0 1790 for (i=0; i<len; i++) {
michael@0 1791 for (j=7; j>=0; j--) {
michael@0 1792 if (last < 0) {
michael@0 1793 last = (hash[i] & (1 << j)) ? 1 : 0;
michael@0 1794 fprintf(out, "%d ", last);
michael@0 1795 count = 1;
michael@0 1796 } else if (hash[i] & (1 << j)) {
michael@0 1797 if (last) {
michael@0 1798 count++;
michael@0 1799 } else {
michael@0 1800 last = 0;
michael@0 1801 fprintf(out, "%d ", count);
michael@0 1802 count = 1;
michael@0 1803 z++;
michael@0 1804 }
michael@0 1805 } else {
michael@0 1806 if (!last) {
michael@0 1807 count++;
michael@0 1808 } else {
michael@0 1809 last = 1;
michael@0 1810 fprintf(out, "%d ", count);
michael@0 1811 count = 1;
michael@0 1812 z++;
michael@0 1813 }
michael@0 1814 }
michael@0 1815 }
michael@0 1816 }
michael@0 1817 fprintf(out, "^\n");
michael@0 1818 fseek(out, start, SEEK_SET);
michael@0 1819 fprintf(out, "%d ", z);
michael@0 1820 fseek(out, 0, SEEK_END);
michael@0 1821 }
michael@0 1822
michael@0 1823 int get_next_line(FILE *req, char *key, char *val, FILE *rsp)
michael@0 1824 {
michael@0 1825 int ignore = 0;
michael@0 1826 char *writeto = key;
michael@0 1827 int w = 0;
michael@0 1828 int c;
michael@0 1829 while ((c = fgetc(req)) != EOF) {
michael@0 1830 if (ignore) {
michael@0 1831 fprintf(rsp, "%c", c);
michael@0 1832 if (c == '\n') return ignore;
michael@0 1833 } else if (c == '\n') {
michael@0 1834 break;
michael@0 1835 } else if (c == '#') {
michael@0 1836 ignore = 1;
michael@0 1837 fprintf(rsp, "%c", c);
michael@0 1838 } else if (c == '=') {
michael@0 1839 writeto[w] = '\0';
michael@0 1840 w = 0;
michael@0 1841 writeto = val;
michael@0 1842 } else if (c == ' ' || c == '[' || c == ']') {
michael@0 1843 continue;
michael@0 1844 } else {
michael@0 1845 writeto[w++] = c;
michael@0 1846 }
michael@0 1847 }
michael@0 1848 writeto[w] = '\0';
michael@0 1849 return (c == EOF) ? -1 : ignore;
michael@0 1850 }
michael@0 1851
michael@0 1852 #ifndef NSS_DISABLE_ECC
michael@0 1853 typedef struct curveNameTagPairStr {
michael@0 1854 char *curveName;
michael@0 1855 SECOidTag curveOidTag;
michael@0 1856 } CurveNameTagPair;
michael@0 1857
michael@0 1858 #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1
michael@0 1859 /* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */
michael@0 1860
michael@0 1861 static CurveNameTagPair nameTagPair[] =
michael@0 1862 {
michael@0 1863 { "sect163k1", SEC_OID_SECG_EC_SECT163K1},
michael@0 1864 { "nistk163", SEC_OID_SECG_EC_SECT163K1},
michael@0 1865 { "sect163r1", SEC_OID_SECG_EC_SECT163R1},
michael@0 1866 { "sect163r2", SEC_OID_SECG_EC_SECT163R2},
michael@0 1867 { "nistb163", SEC_OID_SECG_EC_SECT163R2},
michael@0 1868 { "sect193r1", SEC_OID_SECG_EC_SECT193R1},
michael@0 1869 { "sect193r2", SEC_OID_SECG_EC_SECT193R2},
michael@0 1870 { "sect233k1", SEC_OID_SECG_EC_SECT233K1},
michael@0 1871 { "nistk233", SEC_OID_SECG_EC_SECT233K1},
michael@0 1872 { "sect233r1", SEC_OID_SECG_EC_SECT233R1},
michael@0 1873 { "nistb233", SEC_OID_SECG_EC_SECT233R1},
michael@0 1874 { "sect239k1", SEC_OID_SECG_EC_SECT239K1},
michael@0 1875 { "sect283k1", SEC_OID_SECG_EC_SECT283K1},
michael@0 1876 { "nistk283", SEC_OID_SECG_EC_SECT283K1},
michael@0 1877 { "sect283r1", SEC_OID_SECG_EC_SECT283R1},
michael@0 1878 { "nistb283", SEC_OID_SECG_EC_SECT283R1},
michael@0 1879 { "sect409k1", SEC_OID_SECG_EC_SECT409K1},
michael@0 1880 { "nistk409", SEC_OID_SECG_EC_SECT409K1},
michael@0 1881 { "sect409r1", SEC_OID_SECG_EC_SECT409R1},
michael@0 1882 { "nistb409", SEC_OID_SECG_EC_SECT409R1},
michael@0 1883 { "sect571k1", SEC_OID_SECG_EC_SECT571K1},
michael@0 1884 { "nistk571", SEC_OID_SECG_EC_SECT571K1},
michael@0 1885 { "sect571r1", SEC_OID_SECG_EC_SECT571R1},
michael@0 1886 { "nistb571", SEC_OID_SECG_EC_SECT571R1},
michael@0 1887 { "secp160k1", SEC_OID_SECG_EC_SECP160K1},
michael@0 1888 { "secp160r1", SEC_OID_SECG_EC_SECP160R1},
michael@0 1889 { "secp160r2", SEC_OID_SECG_EC_SECP160R2},
michael@0 1890 { "secp192k1", SEC_OID_SECG_EC_SECP192K1},
michael@0 1891 { "secp192r1", SEC_OID_SECG_EC_SECP192R1},
michael@0 1892 { "nistp192", SEC_OID_SECG_EC_SECP192R1},
michael@0 1893 { "secp224k1", SEC_OID_SECG_EC_SECP224K1},
michael@0 1894 { "secp224r1", SEC_OID_SECG_EC_SECP224R1},
michael@0 1895 { "nistp224", SEC_OID_SECG_EC_SECP224R1},
michael@0 1896 { "secp256k1", SEC_OID_SECG_EC_SECP256K1},
michael@0 1897 { "secp256r1", SEC_OID_SECG_EC_SECP256R1},
michael@0 1898 { "nistp256", SEC_OID_SECG_EC_SECP256R1},
michael@0 1899 { "secp384r1", SEC_OID_SECG_EC_SECP384R1},
michael@0 1900 { "nistp384", SEC_OID_SECG_EC_SECP384R1},
michael@0 1901 { "secp521r1", SEC_OID_SECG_EC_SECP521R1},
michael@0 1902 { "nistp521", SEC_OID_SECG_EC_SECP521R1},
michael@0 1903
michael@0 1904 { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
michael@0 1905 { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
michael@0 1906 { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
michael@0 1907 { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
michael@0 1908 { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
michael@0 1909 { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
michael@0 1910
michael@0 1911 { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
michael@0 1912 { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
michael@0 1913 { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
michael@0 1914 { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
michael@0 1915 { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
michael@0 1916 { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
michael@0 1917 { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
michael@0 1918 { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
michael@0 1919 { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
michael@0 1920 { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
michael@0 1921 { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
michael@0 1922 { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
michael@0 1923 { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
michael@0 1924 { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
michael@0 1925 { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
michael@0 1926 { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
michael@0 1927 { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
michael@0 1928 { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
michael@0 1929 { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
michael@0 1930 { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
michael@0 1931
michael@0 1932 { "secp112r1", SEC_OID_SECG_EC_SECP112R1},
michael@0 1933 { "secp112r2", SEC_OID_SECG_EC_SECP112R2},
michael@0 1934 { "secp128r1", SEC_OID_SECG_EC_SECP128R1},
michael@0 1935 { "secp128r2", SEC_OID_SECG_EC_SECP128R2},
michael@0 1936
michael@0 1937 { "sect113r1", SEC_OID_SECG_EC_SECT113R1},
michael@0 1938 { "sect113r2", SEC_OID_SECG_EC_SECT113R2},
michael@0 1939 { "sect131r1", SEC_OID_SECG_EC_SECT131R1},
michael@0 1940 { "sect131r2", SEC_OID_SECG_EC_SECT131R2},
michael@0 1941 };
michael@0 1942
michael@0 1943 static SECItem *
michael@0 1944 getECParams(const char *curve)
michael@0 1945 {
michael@0 1946 SECItem *ecparams;
michael@0 1947 SECOidData *oidData = NULL;
michael@0 1948 SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
michael@0 1949 int i, numCurves;
michael@0 1950
michael@0 1951 if (curve != NULL) {
michael@0 1952 numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
michael@0 1953 for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
michael@0 1954 i++) {
michael@0 1955 if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
michael@0 1956 curveOidTag = nameTagPair[i].curveOidTag;
michael@0 1957 }
michael@0 1958 }
michael@0 1959
michael@0 1960 /* Return NULL if curve name is not recognized */
michael@0 1961 if ((curveOidTag == SEC_OID_UNKNOWN) ||
michael@0 1962 (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
michael@0 1963 fprintf(stderr, "Unrecognized elliptic curve %s\n", curve);
michael@0 1964 return NULL;
michael@0 1965 }
michael@0 1966
michael@0 1967 ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
michael@0 1968
michael@0 1969 /*
michael@0 1970 * ecparams->data needs to contain the ASN encoding of an object ID (OID)
michael@0 1971 * representing the named curve. The actual OID is in
michael@0 1972 * oidData->oid.data so we simply prepend 0x06 and OID length
michael@0 1973 */
michael@0 1974 ecparams->data[0] = SEC_ASN1_OBJECT_ID;
michael@0 1975 ecparams->data[1] = oidData->oid.len;
michael@0 1976 memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
michael@0 1977
michael@0 1978 return ecparams;
michael@0 1979 }
michael@0 1980
michael@0 1981 /*
michael@0 1982 * Perform the ECDSA Key Pair Generation Test.
michael@0 1983 *
michael@0 1984 * reqfn is the pathname of the REQUEST file.
michael@0 1985 *
michael@0 1986 * The output RESPONSE file is written to stdout.
michael@0 1987 */
michael@0 1988 void
michael@0 1989 ecdsa_keypair_test(char *reqfn)
michael@0 1990 {
michael@0 1991 char buf[256]; /* holds one line from the input REQUEST file
michael@0 1992 * or to the output RESPONSE file.
michael@0 1993 * needs to be large enough to hold the longest
michael@0 1994 * line "Qx = <144 hex digits>\n".
michael@0 1995 */
michael@0 1996 FILE *ecdsareq; /* input stream from the REQUEST file */
michael@0 1997 FILE *ecdsaresp; /* output stream to the RESPONSE file */
michael@0 1998 char curve[16]; /* "nistxddd" */
michael@0 1999 ECParams *ecparams;
michael@0 2000 int N;
michael@0 2001 int i;
michael@0 2002 unsigned int len;
michael@0 2003
michael@0 2004 ecdsareq = fopen(reqfn, "r");
michael@0 2005 ecdsaresp = stdout;
michael@0 2006 strcpy(curve, "nist");
michael@0 2007 while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
michael@0 2008 /* a comment or blank line */
michael@0 2009 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 2010 fputs(buf, ecdsaresp);
michael@0 2011 continue;
michael@0 2012 }
michael@0 2013 /* [X-ddd] */
michael@0 2014 if (buf[0] == '[') {
michael@0 2015 const char *src;
michael@0 2016 char *dst;
michael@0 2017 SECItem *encodedparams;
michael@0 2018
michael@0 2019 src = &buf[1];
michael@0 2020 dst = &curve[4];
michael@0 2021 *dst++ = tolower(*src);
michael@0 2022 src += 2; /* skip the hyphen */
michael@0 2023 *dst++ = *src++;
michael@0 2024 *dst++ = *src++;
michael@0 2025 *dst++ = *src++;
michael@0 2026 *dst = '\0';
michael@0 2027 encodedparams = getECParams(curve);
michael@0 2028 if (encodedparams == NULL) {
michael@0 2029 goto loser;
michael@0 2030 }
michael@0 2031 if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
michael@0 2032 goto loser;
michael@0 2033 }
michael@0 2034 SECITEM_FreeItem(encodedparams, PR_TRUE);
michael@0 2035 fputs(buf, ecdsaresp);
michael@0 2036 continue;
michael@0 2037 }
michael@0 2038 /* N = x */
michael@0 2039 if (buf[0] == 'N') {
michael@0 2040 if (sscanf(buf, "N = %d", &N) != 1) {
michael@0 2041 goto loser;
michael@0 2042 }
michael@0 2043 for (i = 0; i < N; i++) {
michael@0 2044 ECPrivateKey *ecpriv;
michael@0 2045
michael@0 2046 if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
michael@0 2047 goto loser;
michael@0 2048 }
michael@0 2049 fputs("d = ", ecdsaresp);
michael@0 2050 to_hex_str(buf, ecpriv->privateValue.data,
michael@0 2051 ecpriv->privateValue.len);
michael@0 2052 fputs(buf, ecdsaresp);
michael@0 2053 fputc('\n', ecdsaresp);
michael@0 2054 if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
michael@0 2055 != SECSuccess) {
michael@0 2056 goto loser;
michael@0 2057 }
michael@0 2058 len = ecpriv->publicValue.len;
michael@0 2059 if (len%2 == 0) {
michael@0 2060 goto loser;
michael@0 2061 }
michael@0 2062 len = (len-1)/2;
michael@0 2063 if (ecpriv->publicValue.data[0]
michael@0 2064 != EC_POINT_FORM_UNCOMPRESSED) {
michael@0 2065 goto loser;
michael@0 2066 }
michael@0 2067 fputs("Qx = ", ecdsaresp);
michael@0 2068 to_hex_str(buf, &ecpriv->publicValue.data[1], len);
michael@0 2069 fputs(buf, ecdsaresp);
michael@0 2070 fputc('\n', ecdsaresp);
michael@0 2071 fputs("Qy = ", ecdsaresp);
michael@0 2072 to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
michael@0 2073 fputs(buf, ecdsaresp);
michael@0 2074 fputc('\n', ecdsaresp);
michael@0 2075 fputc('\n', ecdsaresp);
michael@0 2076 PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
michael@0 2077 }
michael@0 2078 PORT_FreeArena(ecparams->arena, PR_FALSE);
michael@0 2079 continue;
michael@0 2080 }
michael@0 2081 }
michael@0 2082 loser:
michael@0 2083 fclose(ecdsareq);
michael@0 2084 }
michael@0 2085
michael@0 2086 /*
michael@0 2087 * Perform the ECDSA Public Key Validation Test.
michael@0 2088 *
michael@0 2089 * reqfn is the pathname of the REQUEST file.
michael@0 2090 *
michael@0 2091 * The output RESPONSE file is written to stdout.
michael@0 2092 */
michael@0 2093 void
michael@0 2094 ecdsa_pkv_test(char *reqfn)
michael@0 2095 {
michael@0 2096 char buf[256]; /* holds one line from the input REQUEST file.
michael@0 2097 * needs to be large enough to hold the longest
michael@0 2098 * line "Qx = <144 hex digits>\n".
michael@0 2099 */
michael@0 2100 FILE *ecdsareq; /* input stream from the REQUEST file */
michael@0 2101 FILE *ecdsaresp; /* output stream to the RESPONSE file */
michael@0 2102 char curve[16]; /* "nistxddd" */
michael@0 2103 ECParams *ecparams = NULL;
michael@0 2104 SECItem pubkey;
michael@0 2105 unsigned int i;
michael@0 2106 unsigned int len;
michael@0 2107 PRBool keyvalid = PR_TRUE;
michael@0 2108
michael@0 2109 ecdsareq = fopen(reqfn, "r");
michael@0 2110 ecdsaresp = stdout;
michael@0 2111 strcpy(curve, "nist");
michael@0 2112 pubkey.data = NULL;
michael@0 2113 while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
michael@0 2114 /* a comment or blank line */
michael@0 2115 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 2116 fputs(buf, ecdsaresp);
michael@0 2117 continue;
michael@0 2118 }
michael@0 2119 /* [X-ddd] */
michael@0 2120 if (buf[0] == '[') {
michael@0 2121 const char *src;
michael@0 2122 char *dst;
michael@0 2123 SECItem *encodedparams;
michael@0 2124
michael@0 2125 src = &buf[1];
michael@0 2126 dst = &curve[4];
michael@0 2127 *dst++ = tolower(*src);
michael@0 2128 src += 2; /* skip the hyphen */
michael@0 2129 *dst++ = *src++;
michael@0 2130 *dst++ = *src++;
michael@0 2131 *dst++ = *src++;
michael@0 2132 *dst = '\0';
michael@0 2133 if (ecparams != NULL) {
michael@0 2134 PORT_FreeArena(ecparams->arena, PR_FALSE);
michael@0 2135 ecparams = NULL;
michael@0 2136 }
michael@0 2137 encodedparams = getECParams(curve);
michael@0 2138 if (encodedparams == NULL) {
michael@0 2139 goto loser;
michael@0 2140 }
michael@0 2141 if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
michael@0 2142 goto loser;
michael@0 2143 }
michael@0 2144 SECITEM_FreeItem(encodedparams, PR_TRUE);
michael@0 2145 len = (ecparams->fieldID.size + 7) >> 3;
michael@0 2146 if (pubkey.data != NULL) {
michael@0 2147 PORT_Free(pubkey.data);
michael@0 2148 pubkey.data = NULL;
michael@0 2149 }
michael@0 2150 SECITEM_AllocItem(NULL, &pubkey, 2*len+1);
michael@0 2151 if (pubkey.data == NULL) {
michael@0 2152 goto loser;
michael@0 2153 }
michael@0 2154 pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
michael@0 2155 fputs(buf, ecdsaresp);
michael@0 2156 continue;
michael@0 2157 }
michael@0 2158 /* Qx = ... */
michael@0 2159 if (strncmp(buf, "Qx", 2) == 0) {
michael@0 2160 fputs(buf, ecdsaresp);
michael@0 2161 i = 2;
michael@0 2162 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2163 i++;
michael@0 2164 }
michael@0 2165 keyvalid = from_hex_str(&pubkey.data[1], len, &buf[i]);
michael@0 2166 continue;
michael@0 2167 }
michael@0 2168 /* Qy = ... */
michael@0 2169 if (strncmp(buf, "Qy", 2) == 0) {
michael@0 2170 fputs(buf, ecdsaresp);
michael@0 2171 if (!keyvalid) {
michael@0 2172 fputs("Result = F\n", ecdsaresp);
michael@0 2173 continue;
michael@0 2174 }
michael@0 2175 i = 2;
michael@0 2176 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2177 i++;
michael@0 2178 }
michael@0 2179 keyvalid = from_hex_str(&pubkey.data[1+len], len, &buf[i]);
michael@0 2180 if (!keyvalid) {
michael@0 2181 fputs("Result = F\n", ecdsaresp);
michael@0 2182 continue;
michael@0 2183 }
michael@0 2184 if (EC_ValidatePublicKey(ecparams, &pubkey) == SECSuccess) {
michael@0 2185 fputs("Result = P\n", ecdsaresp);
michael@0 2186 } else if (PORT_GetError() == SEC_ERROR_BAD_KEY) {
michael@0 2187 fputs("Result = F\n", ecdsaresp);
michael@0 2188 } else {
michael@0 2189 goto loser;
michael@0 2190 }
michael@0 2191 continue;
michael@0 2192 }
michael@0 2193 }
michael@0 2194 loser:
michael@0 2195 if (ecparams != NULL) {
michael@0 2196 PORT_FreeArena(ecparams->arena, PR_FALSE);
michael@0 2197 }
michael@0 2198 if (pubkey.data != NULL) {
michael@0 2199 PORT_Free(pubkey.data);
michael@0 2200 }
michael@0 2201 fclose(ecdsareq);
michael@0 2202 }
michael@0 2203
michael@0 2204 /*
michael@0 2205 * Perform the ECDSA Signature Generation Test.
michael@0 2206 *
michael@0 2207 * reqfn is the pathname of the REQUEST file.
michael@0 2208 *
michael@0 2209 * The output RESPONSE file is written to stdout.
michael@0 2210 */
michael@0 2211 void
michael@0 2212 ecdsa_siggen_test(char *reqfn)
michael@0 2213 {
michael@0 2214 char buf[1024]; /* holds one line from the input REQUEST file
michael@0 2215 * or to the output RESPONSE file.
michael@0 2216 * needs to be large enough to hold the longest
michael@0 2217 * line "Msg = <256 hex digits>\n".
michael@0 2218 */
michael@0 2219 FILE *ecdsareq; /* input stream from the REQUEST file */
michael@0 2220 FILE *ecdsaresp; /* output stream to the RESPONSE file */
michael@0 2221 char curve[16]; /* "nistxddd" */
michael@0 2222 ECParams *ecparams = NULL;
michael@0 2223 int i, j;
michael@0 2224 unsigned int len;
michael@0 2225 unsigned char msg[512]; /* message to be signed (<= 128 bytes) */
michael@0 2226 unsigned int msglen;
michael@0 2227 unsigned char sha1[20]; /* SHA-1 hash (160 bits) */
michael@0 2228 unsigned char sig[2*MAX_ECKEY_LEN];
michael@0 2229 SECItem signature, digest;
michael@0 2230
michael@0 2231 ecdsareq = fopen(reqfn, "r");
michael@0 2232 ecdsaresp = stdout;
michael@0 2233 strcpy(curve, "nist");
michael@0 2234 while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
michael@0 2235 /* a comment or blank line */
michael@0 2236 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 2237 fputs(buf, ecdsaresp);
michael@0 2238 continue;
michael@0 2239 }
michael@0 2240 /* [X-ddd] */
michael@0 2241 if (buf[0] == '[') {
michael@0 2242 const char *src;
michael@0 2243 char *dst;
michael@0 2244 SECItem *encodedparams;
michael@0 2245
michael@0 2246 src = &buf[1];
michael@0 2247 dst = &curve[4];
michael@0 2248 *dst++ = tolower(*src);
michael@0 2249 src += 2; /* skip the hyphen */
michael@0 2250 *dst++ = *src++;
michael@0 2251 *dst++ = *src++;
michael@0 2252 *dst++ = *src++;
michael@0 2253 *dst = '\0';
michael@0 2254 if (ecparams != NULL) {
michael@0 2255 PORT_FreeArena(ecparams->arena, PR_FALSE);
michael@0 2256 ecparams = NULL;
michael@0 2257 }
michael@0 2258 encodedparams = getECParams(curve);
michael@0 2259 if (encodedparams == NULL) {
michael@0 2260 goto loser;
michael@0 2261 }
michael@0 2262 if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
michael@0 2263 goto loser;
michael@0 2264 }
michael@0 2265 SECITEM_FreeItem(encodedparams, PR_TRUE);
michael@0 2266 fputs(buf, ecdsaresp);
michael@0 2267 continue;
michael@0 2268 }
michael@0 2269 /* Msg = ... */
michael@0 2270 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 2271 ECPrivateKey *ecpriv;
michael@0 2272
michael@0 2273 i = 3;
michael@0 2274 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2275 i++;
michael@0 2276 }
michael@0 2277 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 2278 hex_to_byteval(&buf[i], &msg[j]);
michael@0 2279 }
michael@0 2280 msglen = j;
michael@0 2281 if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
michael@0 2282 goto loser;
michael@0 2283 }
michael@0 2284 fputs(buf, ecdsaresp);
michael@0 2285
michael@0 2286 if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
michael@0 2287 goto loser;
michael@0 2288 }
michael@0 2289 if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
michael@0 2290 != SECSuccess) {
michael@0 2291 goto loser;
michael@0 2292 }
michael@0 2293 len = ecpriv->publicValue.len;
michael@0 2294 if (len%2 == 0) {
michael@0 2295 goto loser;
michael@0 2296 }
michael@0 2297 len = (len-1)/2;
michael@0 2298 if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
michael@0 2299 goto loser;
michael@0 2300 }
michael@0 2301 fputs("Qx = ", ecdsaresp);
michael@0 2302 to_hex_str(buf, &ecpriv->publicValue.data[1], len);
michael@0 2303 fputs(buf, ecdsaresp);
michael@0 2304 fputc('\n', ecdsaresp);
michael@0 2305 fputs("Qy = ", ecdsaresp);
michael@0 2306 to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
michael@0 2307 fputs(buf, ecdsaresp);
michael@0 2308 fputc('\n', ecdsaresp);
michael@0 2309
michael@0 2310 digest.type = siBuffer;
michael@0 2311 digest.data = sha1;
michael@0 2312 digest.len = sizeof sha1;
michael@0 2313 signature.type = siBuffer;
michael@0 2314 signature.data = sig;
michael@0 2315 signature.len = sizeof sig;
michael@0 2316 if (ECDSA_SignDigest(ecpriv, &signature, &digest) != SECSuccess) {
michael@0 2317 goto loser;
michael@0 2318 }
michael@0 2319 len = signature.len;
michael@0 2320 if (len%2 != 0) {
michael@0 2321 goto loser;
michael@0 2322 }
michael@0 2323 len = len/2;
michael@0 2324 fputs("R = ", ecdsaresp);
michael@0 2325 to_hex_str(buf, &signature.data[0], len);
michael@0 2326 fputs(buf, ecdsaresp);
michael@0 2327 fputc('\n', ecdsaresp);
michael@0 2328 fputs("S = ", ecdsaresp);
michael@0 2329 to_hex_str(buf, &signature.data[len], len);
michael@0 2330 fputs(buf, ecdsaresp);
michael@0 2331 fputc('\n', ecdsaresp);
michael@0 2332
michael@0 2333 PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
michael@0 2334 continue;
michael@0 2335 }
michael@0 2336 }
michael@0 2337 loser:
michael@0 2338 if (ecparams != NULL) {
michael@0 2339 PORT_FreeArena(ecparams->arena, PR_FALSE);
michael@0 2340 }
michael@0 2341 fclose(ecdsareq);
michael@0 2342 }
michael@0 2343
michael@0 2344 /*
michael@0 2345 * Perform the ECDSA Signature Verification Test.
michael@0 2346 *
michael@0 2347 * reqfn is the pathname of the REQUEST file.
michael@0 2348 *
michael@0 2349 * The output RESPONSE file is written to stdout.
michael@0 2350 */
michael@0 2351 void
michael@0 2352 ecdsa_sigver_test(char *reqfn)
michael@0 2353 {
michael@0 2354 char buf[1024]; /* holds one line from the input REQUEST file.
michael@0 2355 * needs to be large enough to hold the longest
michael@0 2356 * line "Msg = <256 hex digits>\n".
michael@0 2357 */
michael@0 2358 FILE *ecdsareq; /* input stream from the REQUEST file */
michael@0 2359 FILE *ecdsaresp; /* output stream to the RESPONSE file */
michael@0 2360 char curve[16]; /* "nistxddd" */
michael@0 2361 ECPublicKey ecpub;
michael@0 2362 unsigned int i, j;
michael@0 2363 unsigned int flen; /* length in bytes of the field size */
michael@0 2364 unsigned int olen; /* length in bytes of the base point order */
michael@0 2365 unsigned char msg[512]; /* message that was signed (<= 128 bytes) */
michael@0 2366 unsigned int msglen;
michael@0 2367 unsigned char sha1[20]; /* SHA-1 hash (160 bits) */
michael@0 2368 unsigned char sig[2*MAX_ECKEY_LEN];
michael@0 2369 SECItem signature, digest;
michael@0 2370 PRBool keyvalid = PR_TRUE;
michael@0 2371 PRBool sigvalid = PR_TRUE;
michael@0 2372
michael@0 2373 ecdsareq = fopen(reqfn, "r");
michael@0 2374 ecdsaresp = stdout;
michael@0 2375 ecpub.ecParams.arena = NULL;
michael@0 2376 strcpy(curve, "nist");
michael@0 2377 while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
michael@0 2378 /* a comment or blank line */
michael@0 2379 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 2380 fputs(buf, ecdsaresp);
michael@0 2381 continue;
michael@0 2382 }
michael@0 2383 /* [X-ddd] */
michael@0 2384 if (buf[0] == '[') {
michael@0 2385 const char *src;
michael@0 2386 char *dst;
michael@0 2387 SECItem *encodedparams;
michael@0 2388 ECParams *ecparams;
michael@0 2389
michael@0 2390 src = &buf[1];
michael@0 2391 dst = &curve[4];
michael@0 2392 *dst++ = tolower(*src);
michael@0 2393 src += 2; /* skip the hyphen */
michael@0 2394 *dst++ = *src++;
michael@0 2395 *dst++ = *src++;
michael@0 2396 *dst++ = *src++;
michael@0 2397 *dst = '\0';
michael@0 2398 encodedparams = getECParams(curve);
michael@0 2399 if (encodedparams == NULL) {
michael@0 2400 goto loser;
michael@0 2401 }
michael@0 2402 if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
michael@0 2403 goto loser;
michael@0 2404 }
michael@0 2405 SECITEM_FreeItem(encodedparams, PR_TRUE);
michael@0 2406 if (ecpub.ecParams.arena != NULL) {
michael@0 2407 PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
michael@0 2408 }
michael@0 2409 ecpub.ecParams.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2410 if (ecpub.ecParams.arena == NULL) {
michael@0 2411 goto loser;
michael@0 2412 }
michael@0 2413 if (EC_CopyParams(ecpub.ecParams.arena, &ecpub.ecParams, ecparams)
michael@0 2414 != SECSuccess) {
michael@0 2415 goto loser;
michael@0 2416 }
michael@0 2417 PORT_FreeArena(ecparams->arena, PR_FALSE);
michael@0 2418 flen = (ecpub.ecParams.fieldID.size + 7) >> 3;
michael@0 2419 olen = ecpub.ecParams.order.len;
michael@0 2420 if (2*olen > sizeof sig) {
michael@0 2421 goto loser;
michael@0 2422 }
michael@0 2423 ecpub.publicValue.type = siBuffer;
michael@0 2424 ecpub.publicValue.data = NULL;
michael@0 2425 ecpub.publicValue.len = 0;
michael@0 2426 SECITEM_AllocItem(ecpub.ecParams.arena,
michael@0 2427 &ecpub.publicValue, 2*flen+1);
michael@0 2428 if (ecpub.publicValue.data == NULL) {
michael@0 2429 goto loser;
michael@0 2430 }
michael@0 2431 ecpub.publicValue.data[0] = EC_POINT_FORM_UNCOMPRESSED;
michael@0 2432 fputs(buf, ecdsaresp);
michael@0 2433 continue;
michael@0 2434 }
michael@0 2435 /* Msg = ... */
michael@0 2436 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 2437 i = 3;
michael@0 2438 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2439 i++;
michael@0 2440 }
michael@0 2441 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 2442 hex_to_byteval(&buf[i], &msg[j]);
michael@0 2443 }
michael@0 2444 msglen = j;
michael@0 2445 if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
michael@0 2446 goto loser;
michael@0 2447 }
michael@0 2448 fputs(buf, ecdsaresp);
michael@0 2449
michael@0 2450 digest.type = siBuffer;
michael@0 2451 digest.data = sha1;
michael@0 2452 digest.len = sizeof sha1;
michael@0 2453
michael@0 2454 continue;
michael@0 2455 }
michael@0 2456 /* Qx = ... */
michael@0 2457 if (strncmp(buf, "Qx", 2) == 0) {
michael@0 2458 fputs(buf, ecdsaresp);
michael@0 2459 i = 2;
michael@0 2460 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2461 i++;
michael@0 2462 }
michael@0 2463 keyvalid = from_hex_str(&ecpub.publicValue.data[1], flen,
michael@0 2464 &buf[i]);
michael@0 2465 continue;
michael@0 2466 }
michael@0 2467 /* Qy = ... */
michael@0 2468 if (strncmp(buf, "Qy", 2) == 0) {
michael@0 2469 fputs(buf, ecdsaresp);
michael@0 2470 if (!keyvalid) {
michael@0 2471 continue;
michael@0 2472 }
michael@0 2473 i = 2;
michael@0 2474 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2475 i++;
michael@0 2476 }
michael@0 2477 keyvalid = from_hex_str(&ecpub.publicValue.data[1+flen], flen,
michael@0 2478 &buf[i]);
michael@0 2479 if (!keyvalid) {
michael@0 2480 continue;
michael@0 2481 }
michael@0 2482 if (EC_ValidatePublicKey(&ecpub.ecParams, &ecpub.publicValue)
michael@0 2483 != SECSuccess) {
michael@0 2484 if (PORT_GetError() == SEC_ERROR_BAD_KEY) {
michael@0 2485 keyvalid = PR_FALSE;
michael@0 2486 } else {
michael@0 2487 goto loser;
michael@0 2488 }
michael@0 2489 }
michael@0 2490 continue;
michael@0 2491 }
michael@0 2492 /* R = ... */
michael@0 2493 if (buf[0] == 'R') {
michael@0 2494 fputs(buf, ecdsaresp);
michael@0 2495 i = 1;
michael@0 2496 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2497 i++;
michael@0 2498 }
michael@0 2499 sigvalid = from_hex_str(sig, olen, &buf[i]);
michael@0 2500 continue;
michael@0 2501 }
michael@0 2502 /* S = ... */
michael@0 2503 if (buf[0] == 'S') {
michael@0 2504 fputs(buf, ecdsaresp);
michael@0 2505 i = 1;
michael@0 2506 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2507 i++;
michael@0 2508 }
michael@0 2509 if (sigvalid) {
michael@0 2510 sigvalid = from_hex_str(&sig[olen], olen, &buf[i]);
michael@0 2511 }
michael@0 2512 signature.type = siBuffer;
michael@0 2513 signature.data = sig;
michael@0 2514 signature.len = 2*olen;
michael@0 2515
michael@0 2516 if (!keyvalid || !sigvalid) {
michael@0 2517 fputs("Result = F\n", ecdsaresp);
michael@0 2518 } else if (ECDSA_VerifyDigest(&ecpub, &signature, &digest)
michael@0 2519 == SECSuccess) {
michael@0 2520 fputs("Result = P\n", ecdsaresp);
michael@0 2521 } else {
michael@0 2522 fputs("Result = F\n", ecdsaresp);
michael@0 2523 }
michael@0 2524 continue;
michael@0 2525 }
michael@0 2526 }
michael@0 2527 loser:
michael@0 2528 if (ecpub.ecParams.arena != NULL) {
michael@0 2529 PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
michael@0 2530 }
michael@0 2531 fclose(ecdsareq);
michael@0 2532 }
michael@0 2533 #endif /* NSS_DISABLE_ECC */
michael@0 2534
michael@0 2535
michael@0 2536 /*
michael@0 2537 * Read a value from the test and allocate the result.
michael@0 2538 */
michael@0 2539 static unsigned char *
michael@0 2540 alloc_value(char *buf, int *len)
michael@0 2541 {
michael@0 2542 unsigned char * value;
michael@0 2543 int i, count;
michael@0 2544
michael@0 2545 if (strncmp(buf, "<None>", 6) == 0) {
michael@0 2546 *len = 0;
michael@0 2547 return NULL;
michael@0 2548 }
michael@0 2549
michael@0 2550 /* find the length of the number */
michael@0 2551 for (count = 0; isxdigit(buf[count]); count++);
michael@0 2552 *len = count/2;
michael@0 2553
michael@0 2554 if (*len == 0) {
michael@0 2555 return NULL;
michael@0 2556 }
michael@0 2557
michael@0 2558 value = PORT_Alloc(*len);
michael@0 2559 if (!value) {
michael@0 2560 *len = 0;
michael@0 2561 return NULL;
michael@0 2562 }
michael@0 2563
michael@0 2564 for (i=0; i<*len; buf+=2 , i++) {
michael@0 2565 hex_to_byteval(buf, &value[i]);
michael@0 2566 }
michael@0 2567
michael@0 2568
michael@0 2569 return value;
michael@0 2570 }
michael@0 2571
michael@0 2572 PRBool
michael@0 2573 isblankline(char *b)
michael@0 2574 {
michael@0 2575 while (isspace(*b)) b++;
michael@0 2576 if ((*b == '\n') || (*b == 0)) {
michael@0 2577 return PR_TRUE;
michael@0 2578 }
michael@0 2579 return PR_FALSE;
michael@0 2580 }
michael@0 2581
michael@0 2582 static int debug = 0;
michael@0 2583
michael@0 2584 /*
michael@0 2585 * Perform the Hash_DRBG (CAVS) for the RNG algorithm
michael@0 2586 *
michael@0 2587 * reqfn is the pathname of the REQUEST file.
michael@0 2588 *
michael@0 2589 * The output RESPONSE file is written to stdout.
michael@0 2590 */
michael@0 2591 void
michael@0 2592 drbg(char *reqfn)
michael@0 2593 {
michael@0 2594 char buf[2000]; /* test case has some very long lines, returned bits
michael@0 2595 * as high as 800 bytes (6400 bits). That 1600 byte
michael@0 2596 * plus a tag */
michael@0 2597 char buf2[2000];
michael@0 2598 FILE *rngreq; /* input stream from the REQUEST file */
michael@0 2599 FILE *rngresp; /* output stream to the RESPONSE file */
michael@0 2600
michael@0 2601 unsigned int i, j;
michael@0 2602 PRBool predictionResistance = PR_FALSE;
michael@0 2603 unsigned char *nonce = NULL;
michael@0 2604 int nonceLen = 0;
michael@0 2605 unsigned char *personalizationString = NULL;
michael@0 2606 int personalizationStringLen = 0;
michael@0 2607 unsigned char *additionalInput = NULL;
michael@0 2608 int additionalInputLen = 0;
michael@0 2609 unsigned char *entropyInput = NULL;
michael@0 2610 int entropyInputLen = 0;
michael@0 2611 unsigned char predictedreturn_bytes[SHA256_LENGTH];
michael@0 2612 unsigned char return_bytes[SHA256_LENGTH];
michael@0 2613 int return_bytes_len = SHA256_LENGTH;
michael@0 2614 enum { NONE, INSTANTIATE, GENERATE, RESEED, RESULT } command =
michael@0 2615 NONE;
michael@0 2616 PRBool genResult = PR_FALSE;
michael@0 2617 SECStatus rv;
michael@0 2618
michael@0 2619 rngreq = fopen(reqfn, "r");
michael@0 2620 rngresp = stdout;
michael@0 2621 while (fgets(buf, sizeof buf, rngreq) != NULL) {
michael@0 2622 switch (command) {
michael@0 2623 case INSTANTIATE:
michael@0 2624 if (debug) {
michael@0 2625 fputs("# PRNGTEST_Instantiate(",rngresp);
michael@0 2626 to_hex_str(buf2,entropyInput, entropyInputLen);
michael@0 2627 fputs(buf2,rngresp);
michael@0 2628 fprintf(rngresp,",%d,",entropyInputLen);
michael@0 2629 to_hex_str(buf2,nonce, nonceLen);
michael@0 2630 fputs(buf2,rngresp);
michael@0 2631 fprintf(rngresp,",%d,",nonceLen);
michael@0 2632 to_hex_str(buf2,personalizationString,
michael@0 2633 personalizationStringLen);
michael@0 2634 fputs(buf2,rngresp);
michael@0 2635 fprintf(rngresp,",%d)\n", personalizationStringLen);
michael@0 2636 }
michael@0 2637 rv = PRNGTEST_Instantiate(entropyInput, entropyInputLen,
michael@0 2638 nonce, nonceLen,
michael@0 2639 personalizationString,
michael@0 2640 personalizationStringLen);
michael@0 2641 if (rv != SECSuccess) {
michael@0 2642 goto loser;
michael@0 2643 }
michael@0 2644 break;
michael@0 2645
michael@0 2646 case GENERATE:
michael@0 2647 case RESULT:
michael@0 2648 memset(return_bytes, 0, return_bytes_len);
michael@0 2649 if (debug) {
michael@0 2650 fputs("# PRNGTEST_Generate(returnbytes",rngresp);
michael@0 2651 fprintf(rngresp,",%d,", return_bytes_len);
michael@0 2652 to_hex_str(buf2,additionalInput, additionalInputLen);
michael@0 2653 fputs(buf2,rngresp);
michael@0 2654 fprintf(rngresp,",%d)\n",additionalInputLen);
michael@0 2655 }
michael@0 2656 rv = PRNGTEST_Generate((PRUint8 *) return_bytes,
michael@0 2657 return_bytes_len,
michael@0 2658 (PRUint8 *) additionalInput,
michael@0 2659 additionalInputLen);
michael@0 2660 if (rv != SECSuccess) {
michael@0 2661 goto loser;
michael@0 2662 }
michael@0 2663
michael@0 2664 if (command == RESULT) {
michael@0 2665 fputs("ReturnedBits = ", rngresp);
michael@0 2666 to_hex_str(buf2, return_bytes, return_bytes_len);
michael@0 2667 fputs(buf2, rngresp);
michael@0 2668 fputc('\n', rngresp);
michael@0 2669 if (debug) {
michael@0 2670 fputs("# PRNGTEST_Uninstantiate()\n",rngresp);
michael@0 2671 }
michael@0 2672 rv = PRNGTEST_Uninstantiate();
michael@0 2673 if (rv != SECSuccess) {
michael@0 2674 goto loser;
michael@0 2675 }
michael@0 2676 } else if (debug) {
michael@0 2677 fputs("#ReturnedBits = ", rngresp);
michael@0 2678 to_hex_str(buf2, return_bytes, return_bytes_len);
michael@0 2679 fputs(buf2, rngresp);
michael@0 2680 fputc('\n', rngresp);
michael@0 2681 }
michael@0 2682
michael@0 2683 memset(additionalInput, 0, additionalInputLen);
michael@0 2684 break;
michael@0 2685
michael@0 2686 case RESEED:
michael@0 2687 if (entropyInput || additionalInput) {
michael@0 2688 if (debug) {
michael@0 2689 fputs("# PRNGTEST_Reseed(",rngresp);
michael@0 2690 fprintf(rngresp,",%d,", return_bytes_len);
michael@0 2691 to_hex_str(buf2,entropyInput, entropyInputLen);
michael@0 2692 fputs(buf2,rngresp);
michael@0 2693 fprintf(rngresp,",%d,", entropyInputLen);
michael@0 2694 to_hex_str(buf2,additionalInput, additionalInputLen);
michael@0 2695 fputs(buf2,rngresp);
michael@0 2696 fprintf(rngresp,",%d)\n",additionalInputLen);
michael@0 2697 }
michael@0 2698 rv = PRNGTEST_Reseed(entropyInput, entropyInputLen,
michael@0 2699 additionalInput, additionalInputLen);
michael@0 2700 if (rv != SECSuccess) {
michael@0 2701 goto loser;
michael@0 2702 }
michael@0 2703 }
michael@0 2704 memset(entropyInput, 0, entropyInputLen);
michael@0 2705 memset(additionalInput, 0, additionalInputLen);
michael@0 2706 break;
michael@0 2707 case NONE:
michael@0 2708 break;
michael@0 2709
michael@0 2710 }
michael@0 2711 command = NONE;
michael@0 2712
michael@0 2713 /* a comment or blank line */
michael@0 2714 if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r' ) {
michael@0 2715 fputs(buf, rngresp);
michael@0 2716 continue;
michael@0 2717 }
michael@0 2718
michael@0 2719 /* [Hash - SHA256] */
michael@0 2720 if (strncmp(buf, "[SHA-256]", 9) == 0) {
michael@0 2721 fputs(buf, rngresp);
michael@0 2722 continue;
michael@0 2723 }
michael@0 2724
michael@0 2725 if (strncmp(buf, "[PredictionResistance", 21) == 0) {
michael@0 2726 i = 21;
michael@0 2727 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2728 i++;
michael@0 2729 }
michael@0 2730 if (strncmp(buf, "False", 5) == 0) {
michael@0 2731 predictionResistance = PR_FALSE;
michael@0 2732 } else {
michael@0 2733 predictionResistance = PR_TRUE;
michael@0 2734 }
michael@0 2735
michael@0 2736 fputs(buf, rngresp);
michael@0 2737 continue;
michael@0 2738 }
michael@0 2739
michael@0 2740 if (strncmp(buf, "[EntropyInputLen", 16) == 0) {
michael@0 2741 if (entropyInput) {
michael@0 2742 PORT_ZFree(entropyInput, entropyInputLen);
michael@0 2743 entropyInput = NULL;
michael@0 2744 entropyInputLen = 0;
michael@0 2745 }
michael@0 2746 if (sscanf(buf, "[EntropyInputLen = %d]", &entropyInputLen) != 1) {
michael@0 2747 goto loser;
michael@0 2748 }
michael@0 2749 entropyInputLen = entropyInputLen/8;
michael@0 2750 if (entropyInputLen > 0) {
michael@0 2751 entropyInput = PORT_Alloc(entropyInputLen);
michael@0 2752 }
michael@0 2753 fputs(buf, rngresp);
michael@0 2754 continue;
michael@0 2755 }
michael@0 2756
michael@0 2757 if (strncmp(buf, "[NonceLen", 9) == 0) {
michael@0 2758 if (nonce) {
michael@0 2759 PORT_ZFree(nonce, nonceLen);
michael@0 2760 nonce = NULL;
michael@0 2761 nonceLen = 0;
michael@0 2762 }
michael@0 2763
michael@0 2764 if (sscanf(buf, "[NonceLen = %d]", &nonceLen) != 1) {
michael@0 2765 goto loser;
michael@0 2766 }
michael@0 2767 nonceLen = nonceLen/8;
michael@0 2768 if (nonceLen > 0) {
michael@0 2769 nonce = PORT_Alloc(nonceLen);
michael@0 2770 }
michael@0 2771 fputs(buf, rngresp);
michael@0 2772 continue;
michael@0 2773 }
michael@0 2774
michael@0 2775 if (strncmp(buf, "[PersonalizationStringLen", 16) == 0) {
michael@0 2776 if (personalizationString) {
michael@0 2777 PORT_ZFree(personalizationString, personalizationStringLen);
michael@0 2778 personalizationString = NULL;
michael@0 2779 personalizationStringLen = 0;
michael@0 2780 }
michael@0 2781
michael@0 2782 if (sscanf(buf, "[PersonalizationStringLen = %d]", &personalizationStringLen) != 1) {
michael@0 2783 goto loser;
michael@0 2784 }
michael@0 2785 personalizationStringLen = personalizationStringLen / 8;
michael@0 2786 if (personalizationStringLen > 0) {
michael@0 2787 personalizationString = PORT_Alloc(personalizationStringLen);
michael@0 2788 }
michael@0 2789 fputs(buf, rngresp);
michael@0 2790
michael@0 2791 continue;
michael@0 2792 }
michael@0 2793
michael@0 2794 if (strncmp(buf, "[AdditionalInputLen", 16) == 0) {
michael@0 2795 if (additionalInput) {
michael@0 2796 PORT_ZFree(additionalInput, additionalInputLen);
michael@0 2797 additionalInput = NULL;
michael@0 2798 additionalInputLen = 0;
michael@0 2799 }
michael@0 2800
michael@0 2801 if (sscanf(buf, "[AdditionalInputLen = %d]", &additionalInputLen) != 1) {
michael@0 2802 goto loser;
michael@0 2803 }
michael@0 2804 additionalInputLen = additionalInputLen/8;
michael@0 2805 if (additionalInputLen > 0) {
michael@0 2806 additionalInput = PORT_Alloc(additionalInputLen);
michael@0 2807 }
michael@0 2808 fputs(buf, rngresp);
michael@0 2809 continue;
michael@0 2810 }
michael@0 2811
michael@0 2812 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 2813 /* zeroize the variables for the test with this data set */
michael@0 2814 if (entropyInput) {
michael@0 2815 memset(entropyInput, 0, entropyInputLen);
michael@0 2816 }
michael@0 2817 if (nonce) {
michael@0 2818 memset(nonce, 0, nonceLen);
michael@0 2819 }
michael@0 2820 if (personalizationString) {
michael@0 2821 memset(personalizationString, 0, personalizationStringLen);
michael@0 2822 }
michael@0 2823 if (additionalInput) {
michael@0 2824 memset(additionalInput, 0, additionalInputLen);
michael@0 2825 }
michael@0 2826 genResult = PR_FALSE;
michael@0 2827
michael@0 2828 fputs(buf, rngresp);
michael@0 2829 continue;
michael@0 2830 }
michael@0 2831
michael@0 2832 /* EntropyInputReseed = ... */
michael@0 2833 if (strncmp(buf, "EntropyInputReseed", 18) == 0) {
michael@0 2834 if (entropyInput) {
michael@0 2835 memset(entropyInput, 0, entropyInputLen);
michael@0 2836 i = 18;
michael@0 2837 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2838 i++;
michael@0 2839 }
michael@0 2840
michael@0 2841 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<entropyInputLen*/
michael@0 2842 hex_to_byteval(&buf[i], &entropyInput[j]);
michael@0 2843 }
michael@0 2844 }
michael@0 2845 fputs(buf, rngresp);
michael@0 2846 continue;
michael@0 2847 }
michael@0 2848
michael@0 2849 /* AttionalInputReseed = ... */
michael@0 2850 if (strncmp(buf, "AdditionalInputReseed", 21) == 0) {
michael@0 2851 if (additionalInput) {
michael@0 2852 memset(additionalInput, 0, additionalInputLen);
michael@0 2853 i = 21;
michael@0 2854 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2855 i++;
michael@0 2856 }
michael@0 2857 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/
michael@0 2858 hex_to_byteval(&buf[i], &additionalInput[j]);
michael@0 2859 }
michael@0 2860 }
michael@0 2861 command = RESEED;
michael@0 2862 fputs(buf, rngresp);
michael@0 2863 continue;
michael@0 2864 }
michael@0 2865
michael@0 2866 /* Entropy input = ... */
michael@0 2867 if (strncmp(buf, "EntropyInput", 12) == 0) {
michael@0 2868 i = 12;
michael@0 2869 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2870 i++;
michael@0 2871 }
michael@0 2872 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<entropyInputLen*/
michael@0 2873 hex_to_byteval(&buf[i], &entropyInput[j]);
michael@0 2874 }
michael@0 2875 fputs(buf, rngresp);
michael@0 2876 continue;
michael@0 2877 }
michael@0 2878
michael@0 2879 /* nouce = ... */
michael@0 2880 if (strncmp(buf, "Nonce", 5) == 0) {
michael@0 2881 i = 5;
michael@0 2882 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2883 i++;
michael@0 2884 }
michael@0 2885 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<nonceLen*/
michael@0 2886 hex_to_byteval(&buf[i], &nonce[j]);
michael@0 2887 }
michael@0 2888 fputs(buf, rngresp);
michael@0 2889 continue;
michael@0 2890 }
michael@0 2891
michael@0 2892 /* Personalization string = ... */
michael@0 2893 if (strncmp(buf, "PersonalizationString", 21) == 0) {
michael@0 2894 if (personalizationString) {
michael@0 2895 i = 21;
michael@0 2896 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2897 i++;
michael@0 2898 }
michael@0 2899 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<personalizationStringLen*/
michael@0 2900 hex_to_byteval(&buf[i], &personalizationString[j]);
michael@0 2901 }
michael@0 2902 }
michael@0 2903 fputs(buf, rngresp);
michael@0 2904 command = INSTANTIATE;
michael@0 2905 continue;
michael@0 2906 }
michael@0 2907
michael@0 2908 /* Additional input = ... */
michael@0 2909 if (strncmp(buf, "AdditionalInput", 15) == 0) {
michael@0 2910 if (additionalInput) {
michael@0 2911 i = 15;
michael@0 2912 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2913 i++;
michael@0 2914 }
michael@0 2915 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/
michael@0 2916 hex_to_byteval(&buf[i], &additionalInput[j]);
michael@0 2917 }
michael@0 2918 }
michael@0 2919 if (genResult) {
michael@0 2920 command = RESULT;
michael@0 2921 } else {
michael@0 2922 command = GENERATE;
michael@0 2923 genResult = PR_TRUE; /* next time generate result */
michael@0 2924 }
michael@0 2925 fputs(buf, rngresp);
michael@0 2926 continue;
michael@0 2927 }
michael@0 2928
michael@0 2929 /* Returned bits = ... */
michael@0 2930 if (strncmp(buf, "ReturnedBits", 12) == 0) {
michael@0 2931 i = 12;
michael@0 2932 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 2933 i++;
michael@0 2934 }
michael@0 2935 for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/
michael@0 2936 hex_to_byteval(&buf[i], &predictedreturn_bytes[j]);
michael@0 2937 }
michael@0 2938
michael@0 2939 if (memcmp(return_bytes,
michael@0 2940 predictedreturn_bytes, return_bytes_len) != 0) {
michael@0 2941 if (debug) {
michael@0 2942 fprintf(rngresp, "# Generate failed:\n");
michael@0 2943 fputs( "# predicted=", rngresp);
michael@0 2944 to_hex_str(buf, predictedreturn_bytes,
michael@0 2945 return_bytes_len);
michael@0 2946 fputs(buf, rngresp);
michael@0 2947 fputs("\n# actual = ", rngresp);
michael@0 2948 fputs(buf2, rngresp);
michael@0 2949 fputc('\n', rngresp);
michael@0 2950
michael@0 2951 } else {
michael@0 2952 fprintf(stderr, "Generate failed:\n");
michael@0 2953 fputs( " predicted=", stderr);
michael@0 2954 to_hex_str(buf, predictedreturn_bytes,
michael@0 2955 return_bytes_len);
michael@0 2956 fputs(buf, stderr);
michael@0 2957 fputs("\n actual = ", stderr);
michael@0 2958 fputs(buf2, stderr);
michael@0 2959 fputc('\n', stderr);
michael@0 2960 }
michael@0 2961 }
michael@0 2962 memset(predictedreturn_bytes, 0 , sizeof predictedreturn_bytes);
michael@0 2963
michael@0 2964 continue;
michael@0 2965 }
michael@0 2966 }
michael@0 2967 loser:
michael@0 2968 fclose(rngreq);
michael@0 2969 }
michael@0 2970
michael@0 2971 /*
michael@0 2972 * Perform the RNG Variable Seed Test (VST) for the RNG algorithm
michael@0 2973 * "DSA - Generation of X", used both as specified and as a generic
michael@0 2974 * purpose RNG. The presence of "Q = ..." in the REQUEST file
michael@0 2975 * indicates we are using the algorithm as specified.
michael@0 2976 *
michael@0 2977 * reqfn is the pathname of the REQUEST file.
michael@0 2978 *
michael@0 2979 * The output RESPONSE file is written to stdout.
michael@0 2980 */
michael@0 2981 void
michael@0 2982 rng_vst(char *reqfn)
michael@0 2983 {
michael@0 2984 char buf[256]; /* holds one line from the input REQUEST file.
michael@0 2985 * needs to be large enough to hold the longest
michael@0 2986 * line "XSeed = <128 hex digits>\n".
michael@0 2987 */
michael@0 2988 FILE *rngreq; /* input stream from the REQUEST file */
michael@0 2989 FILE *rngresp; /* output stream to the RESPONSE file */
michael@0 2990 unsigned int i, j;
michael@0 2991 unsigned char Q[DSA1_SUBPRIME_LEN];
michael@0 2992 PRBool hasQ = PR_FALSE;
michael@0 2993 unsigned int b; /* 160 <= b <= 512, b is a multiple of 8 */
michael@0 2994 unsigned char XKey[512/8];
michael@0 2995 unsigned char XSeed[512/8];
michael@0 2996 unsigned char GENX[DSA1_SIGNATURE_LEN];
michael@0 2997 unsigned char DSAX[DSA1_SUBPRIME_LEN];
michael@0 2998 SECStatus rv;
michael@0 2999
michael@0 3000 rngreq = fopen(reqfn, "r");
michael@0 3001 rngresp = stdout;
michael@0 3002 while (fgets(buf, sizeof buf, rngreq) != NULL) {
michael@0 3003 /* a comment or blank line */
michael@0 3004 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 3005 fputs(buf, rngresp);
michael@0 3006 continue;
michael@0 3007 }
michael@0 3008 /* [Xchange - SHA1] */
michael@0 3009 if (buf[0] == '[') {
michael@0 3010 fputs(buf, rngresp);
michael@0 3011 continue;
michael@0 3012 }
michael@0 3013 /* Q = ... */
michael@0 3014 if (buf[0] == 'Q') {
michael@0 3015 i = 1;
michael@0 3016 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3017 i++;
michael@0 3018 }
michael@0 3019 for (j=0; j<sizeof Q; i+=2,j++) {
michael@0 3020 hex_to_byteval(&buf[i], &Q[j]);
michael@0 3021 }
michael@0 3022 fputs(buf, rngresp);
michael@0 3023 hasQ = PR_TRUE;
michael@0 3024 continue;
michael@0 3025 }
michael@0 3026 /* "COUNT = x" begins a new data set */
michael@0 3027 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 3028 /* zeroize the variables for the test with this data set */
michael@0 3029 b = 0;
michael@0 3030 memset(XKey, 0, sizeof XKey);
michael@0 3031 memset(XSeed, 0, sizeof XSeed);
michael@0 3032 fputs(buf, rngresp);
michael@0 3033 continue;
michael@0 3034 }
michael@0 3035 /* b = ... */
michael@0 3036 if (buf[0] == 'b') {
michael@0 3037 i = 1;
michael@0 3038 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3039 i++;
michael@0 3040 }
michael@0 3041 b = atoi(&buf[i]);
michael@0 3042 if (b < 160 || b > 512 || b%8 != 0) {
michael@0 3043 goto loser;
michael@0 3044 }
michael@0 3045 fputs(buf, rngresp);
michael@0 3046 continue;
michael@0 3047 }
michael@0 3048 /* XKey = ... */
michael@0 3049 if (strncmp(buf, "XKey", 4) == 0) {
michael@0 3050 i = 4;
michael@0 3051 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3052 i++;
michael@0 3053 }
michael@0 3054 for (j=0; j<b/8; i+=2,j++) {
michael@0 3055 hex_to_byteval(&buf[i], &XKey[j]);
michael@0 3056 }
michael@0 3057 fputs(buf, rngresp);
michael@0 3058 continue;
michael@0 3059 }
michael@0 3060 /* XSeed = ... */
michael@0 3061 if (strncmp(buf, "XSeed", 5) == 0) {
michael@0 3062 i = 5;
michael@0 3063 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3064 i++;
michael@0 3065 }
michael@0 3066 for (j=0; j<b/8; i+=2,j++) {
michael@0 3067 hex_to_byteval(&buf[i], &XSeed[j]);
michael@0 3068 }
michael@0 3069 fputs(buf, rngresp);
michael@0 3070
michael@0 3071 rv = FIPS186Change_GenerateX(XKey, XSeed, GENX);
michael@0 3072 if (rv != SECSuccess) {
michael@0 3073 goto loser;
michael@0 3074 }
michael@0 3075 fputs("X = ", rngresp);
michael@0 3076 if (hasQ) {
michael@0 3077 rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
michael@0 3078 if (rv != SECSuccess) {
michael@0 3079 goto loser;
michael@0 3080 }
michael@0 3081 to_hex_str(buf, DSAX, sizeof DSAX);
michael@0 3082 } else {
michael@0 3083 to_hex_str(buf, GENX, sizeof GENX);
michael@0 3084 }
michael@0 3085 fputs(buf, rngresp);
michael@0 3086 fputc('\n', rngresp);
michael@0 3087 continue;
michael@0 3088 }
michael@0 3089 }
michael@0 3090 loser:
michael@0 3091 fclose(rngreq);
michael@0 3092 }
michael@0 3093
michael@0 3094 /*
michael@0 3095 * Perform the RNG Monte Carlo Test (MCT) for the RNG algorithm
michael@0 3096 * "DSA - Generation of X", used both as specified and as a generic
michael@0 3097 * purpose RNG. The presence of "Q = ..." in the REQUEST file
michael@0 3098 * indicates we are using the algorithm as specified.
michael@0 3099 *
michael@0 3100 * reqfn is the pathname of the REQUEST file.
michael@0 3101 *
michael@0 3102 * The output RESPONSE file is written to stdout.
michael@0 3103 */
michael@0 3104 void
michael@0 3105 rng_mct(char *reqfn)
michael@0 3106 {
michael@0 3107 char buf[256]; /* holds one line from the input REQUEST file.
michael@0 3108 * needs to be large enough to hold the longest
michael@0 3109 * line "XSeed = <128 hex digits>\n".
michael@0 3110 */
michael@0 3111 FILE *rngreq; /* input stream from the REQUEST file */
michael@0 3112 FILE *rngresp; /* output stream to the RESPONSE file */
michael@0 3113 unsigned int i, j;
michael@0 3114 unsigned char Q[DSA1_SUBPRIME_LEN];
michael@0 3115 PRBool hasQ = PR_FALSE;
michael@0 3116 unsigned int b; /* 160 <= b <= 512, b is a multiple of 8 */
michael@0 3117 unsigned char XKey[512/8];
michael@0 3118 unsigned char XSeed[512/8];
michael@0 3119 unsigned char GENX[2*SHA1_LENGTH];
michael@0 3120 unsigned char DSAX[DSA1_SUBPRIME_LEN];
michael@0 3121 SECStatus rv;
michael@0 3122
michael@0 3123 rngreq = fopen(reqfn, "r");
michael@0 3124 rngresp = stdout;
michael@0 3125 while (fgets(buf, sizeof buf, rngreq) != NULL) {
michael@0 3126 /* a comment or blank line */
michael@0 3127 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 3128 fputs(buf, rngresp);
michael@0 3129 continue;
michael@0 3130 }
michael@0 3131 /* [Xchange - SHA1] */
michael@0 3132 if (buf[0] == '[') {
michael@0 3133 fputs(buf, rngresp);
michael@0 3134 continue;
michael@0 3135 }
michael@0 3136 /* Q = ... */
michael@0 3137 if (buf[0] == 'Q') {
michael@0 3138 i = 1;
michael@0 3139 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3140 i++;
michael@0 3141 }
michael@0 3142 for (j=0; j<sizeof Q; i+=2,j++) {
michael@0 3143 hex_to_byteval(&buf[i], &Q[j]);
michael@0 3144 }
michael@0 3145 fputs(buf, rngresp);
michael@0 3146 hasQ = PR_TRUE;
michael@0 3147 continue;
michael@0 3148 }
michael@0 3149 /* "COUNT = x" begins a new data set */
michael@0 3150 if (strncmp(buf, "COUNT", 5) == 0) {
michael@0 3151 /* zeroize the variables for the test with this data set */
michael@0 3152 b = 0;
michael@0 3153 memset(XKey, 0, sizeof XKey);
michael@0 3154 memset(XSeed, 0, sizeof XSeed);
michael@0 3155 fputs(buf, rngresp);
michael@0 3156 continue;
michael@0 3157 }
michael@0 3158 /* b = ... */
michael@0 3159 if (buf[0] == 'b') {
michael@0 3160 i = 1;
michael@0 3161 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3162 i++;
michael@0 3163 }
michael@0 3164 b = atoi(&buf[i]);
michael@0 3165 if (b < 160 || b > 512 || b%8 != 0) {
michael@0 3166 goto loser;
michael@0 3167 }
michael@0 3168 fputs(buf, rngresp);
michael@0 3169 continue;
michael@0 3170 }
michael@0 3171 /* XKey = ... */
michael@0 3172 if (strncmp(buf, "XKey", 4) == 0) {
michael@0 3173 i = 4;
michael@0 3174 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3175 i++;
michael@0 3176 }
michael@0 3177 for (j=0; j<b/8; i+=2,j++) {
michael@0 3178 hex_to_byteval(&buf[i], &XKey[j]);
michael@0 3179 }
michael@0 3180 fputs(buf, rngresp);
michael@0 3181 continue;
michael@0 3182 }
michael@0 3183 /* XSeed = ... */
michael@0 3184 if (strncmp(buf, "XSeed", 5) == 0) {
michael@0 3185 unsigned int k;
michael@0 3186 i = 5;
michael@0 3187 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3188 i++;
michael@0 3189 }
michael@0 3190 for (j=0; j<b/8; i+=2,j++) {
michael@0 3191 hex_to_byteval(&buf[i], &XSeed[j]);
michael@0 3192 }
michael@0 3193 fputs(buf, rngresp);
michael@0 3194
michael@0 3195 for (k = 0; k < 10000; k++) {
michael@0 3196 rv = FIPS186Change_GenerateX(XKey, XSeed, GENX);
michael@0 3197 if (rv != SECSuccess) {
michael@0 3198 goto loser;
michael@0 3199 }
michael@0 3200 }
michael@0 3201 fputs("X = ", rngresp);
michael@0 3202 if (hasQ) {
michael@0 3203 rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
michael@0 3204 if (rv != SECSuccess) {
michael@0 3205 goto loser;
michael@0 3206 }
michael@0 3207 to_hex_str(buf, DSAX, sizeof DSAX);
michael@0 3208 } else {
michael@0 3209 to_hex_str(buf, GENX, sizeof GENX);
michael@0 3210 }
michael@0 3211 fputs(buf, rngresp);
michael@0 3212 fputc('\n', rngresp);
michael@0 3213 continue;
michael@0 3214 }
michael@0 3215 }
michael@0 3216 loser:
michael@0 3217 fclose(rngreq);
michael@0 3218 }
michael@0 3219
michael@0 3220 /*
michael@0 3221 * HASH_ functions are available to full NSS apps and internally inside
michael@0 3222 * freebl, but not exported to users of freebl. Create short stubs to
michael@0 3223 * replace the functionality for fipstest.
michael@0 3224 */
michael@0 3225 SECStatus
michael@0 3226 fips_hashBuf(HASH_HashType type, unsigned char *hashBuf,
michael@0 3227 unsigned char *msg, int len)
michael@0 3228 {
michael@0 3229 SECStatus rv = SECFailure;
michael@0 3230
michael@0 3231 switch (type) {
michael@0 3232 case HASH_AlgSHA1:
michael@0 3233 rv = SHA1_HashBuf(hashBuf, msg, len);
michael@0 3234 break;
michael@0 3235 case HASH_AlgSHA224:
michael@0 3236 rv = SHA224_HashBuf(hashBuf, msg, len);
michael@0 3237 break;
michael@0 3238 case HASH_AlgSHA256:
michael@0 3239 rv = SHA256_HashBuf(hashBuf, msg, len);
michael@0 3240 break;
michael@0 3241 case HASH_AlgSHA384:
michael@0 3242 rv = SHA384_HashBuf(hashBuf, msg, len);
michael@0 3243 break;
michael@0 3244 case HASH_AlgSHA512:
michael@0 3245 rv = SHA512_HashBuf(hashBuf, msg, len);
michael@0 3246 break;
michael@0 3247 default:
michael@0 3248 break;
michael@0 3249 }
michael@0 3250 return rv;
michael@0 3251 }
michael@0 3252
michael@0 3253 int
michael@0 3254 fips_hashLen(HASH_HashType type)
michael@0 3255 {
michael@0 3256 int len = 0;
michael@0 3257
michael@0 3258 switch (type) {
michael@0 3259 case HASH_AlgSHA1:
michael@0 3260 len = SHA1_LENGTH;
michael@0 3261 break;
michael@0 3262 case HASH_AlgSHA224:
michael@0 3263 len = SHA224_LENGTH;
michael@0 3264 break;
michael@0 3265 case HASH_AlgSHA256:
michael@0 3266 len = SHA256_LENGTH;
michael@0 3267 break;
michael@0 3268 case HASH_AlgSHA384:
michael@0 3269 len = SHA384_LENGTH;
michael@0 3270 break;
michael@0 3271 case HASH_AlgSHA512:
michael@0 3272 len = SHA512_LENGTH;
michael@0 3273 break;
michael@0 3274 default:
michael@0 3275 break;
michael@0 3276 }
michael@0 3277 return len;
michael@0 3278 }
michael@0 3279
michael@0 3280 SECOidTag
michael@0 3281 fips_hashOid(HASH_HashType type)
michael@0 3282 {
michael@0 3283 SECOidTag oid = SEC_OID_UNKNOWN;
michael@0 3284
michael@0 3285 switch (type) {
michael@0 3286 case HASH_AlgSHA1:
michael@0 3287 oid = SEC_OID_SHA1;
michael@0 3288 break;
michael@0 3289 case HASH_AlgSHA224:
michael@0 3290 oid = SEC_OID_SHA224;
michael@0 3291 break;
michael@0 3292 case HASH_AlgSHA256:
michael@0 3293 oid = SEC_OID_SHA256;
michael@0 3294 break;
michael@0 3295 case HASH_AlgSHA384:
michael@0 3296 oid = SEC_OID_SHA384;
michael@0 3297 break;
michael@0 3298 case HASH_AlgSHA512:
michael@0 3299 oid = SEC_OID_SHA512;
michael@0 3300 break;
michael@0 3301 default:
michael@0 3302 break;
michael@0 3303 }
michael@0 3304 return oid;
michael@0 3305 }
michael@0 3306
michael@0 3307 HASH_HashType
michael@0 3308 sha_get_hashType(int hashbits)
michael@0 3309 {
michael@0 3310 HASH_HashType hashType = HASH_AlgNULL;
michael@0 3311
michael@0 3312 switch (hashbits) {
michael@0 3313 case 1:
michael@0 3314 case (SHA1_LENGTH*PR_BITS_PER_BYTE):
michael@0 3315 hashType = HASH_AlgSHA1;
michael@0 3316 break;
michael@0 3317 case (SHA224_LENGTH*PR_BITS_PER_BYTE):
michael@0 3318 hashType = HASH_AlgSHA224;
michael@0 3319 break;
michael@0 3320 case (SHA256_LENGTH*PR_BITS_PER_BYTE):
michael@0 3321 hashType = HASH_AlgSHA256;
michael@0 3322 break;
michael@0 3323 case (SHA384_LENGTH*PR_BITS_PER_BYTE):
michael@0 3324 hashType = HASH_AlgSHA384;
michael@0 3325 break;
michael@0 3326 case (SHA512_LENGTH*PR_BITS_PER_BYTE):
michael@0 3327 hashType = HASH_AlgSHA512;
michael@0 3328 break;
michael@0 3329 default:
michael@0 3330 break;
michael@0 3331 }
michael@0 3332 return hashType;
michael@0 3333 }
michael@0 3334
michael@0 3335 /*
michael@0 3336 * Calculate the SHA Message Digest
michael@0 3337 *
michael@0 3338 * MD = Message digest
michael@0 3339 * MDLen = length of Message Digest and SHA_Type
michael@0 3340 * msg = message to digest
michael@0 3341 * msgLen = length of message to digest
michael@0 3342 */
michael@0 3343 SECStatus sha_calcMD(unsigned char *MD, unsigned int MDLen, unsigned char *msg, unsigned int msgLen)
michael@0 3344 {
michael@0 3345 HASH_HashType hashType = sha_get_hashType(MDLen*PR_BITS_PER_BYTE);
michael@0 3346
michael@0 3347 return fips_hashBuf(hashType, MD, msg, msgLen);
michael@0 3348 }
michael@0 3349
michael@0 3350 /*
michael@0 3351 * Perform the SHA Monte Carlo Test
michael@0 3352 *
michael@0 3353 * MDLen = length of Message Digest and SHA_Type
michael@0 3354 * seed = input seed value
michael@0 3355 * resp = is the output response file.
michael@0 3356 */
michael@0 3357 SECStatus sha_mct_test(unsigned int MDLen, unsigned char *seed, FILE *resp)
michael@0 3358 {
michael@0 3359 int i, j;
michael@0 3360 unsigned int msgLen = MDLen*3;
michael@0 3361 unsigned char MD_i3[HASH_LENGTH_MAX]; /* MD[i-3] */
michael@0 3362 unsigned char MD_i2[HASH_LENGTH_MAX]; /* MD[i-2] */
michael@0 3363 unsigned char MD_i1[HASH_LENGTH_MAX]; /* MD[i-1] */
michael@0 3364 unsigned char MD_i[HASH_LENGTH_MAX]; /* MD[i] */
michael@0 3365 unsigned char msg[HASH_LENGTH_MAX*3];
michael@0 3366 char buf[HASH_LENGTH_MAX*2 + 1]; /* MAX buf MD_i as a hex string */
michael@0 3367
michael@0 3368 for (j=0; j<100; j++) {
michael@0 3369 /* MD_0 = MD_1 = MD_2 = seed */
michael@0 3370 memcpy(MD_i3, seed, MDLen);
michael@0 3371 memcpy(MD_i2, seed, MDLen);
michael@0 3372 memcpy(MD_i1, seed, MDLen);
michael@0 3373
michael@0 3374 for (i=3; i < 1003; i++) {
michael@0 3375 /* Mi = MD[i-3] || MD [i-2] || MD [i-1] */
michael@0 3376 memcpy(msg, MD_i3, MDLen);
michael@0 3377 memcpy(&msg[MDLen], MD_i2, MDLen);
michael@0 3378 memcpy(&msg[MDLen*2], MD_i1,MDLen);
michael@0 3379
michael@0 3380 /* MDi = SHA(Msg) */
michael@0 3381 if (sha_calcMD(MD_i, MDLen,
michael@0 3382 msg, msgLen) != SECSuccess) {
michael@0 3383 return SECFailure;
michael@0 3384 }
michael@0 3385
michael@0 3386 /* save MD[i-3] MD[i-2] MD[i-1] */
michael@0 3387 memcpy(MD_i3, MD_i2, MDLen);
michael@0 3388 memcpy(MD_i2, MD_i1, MDLen);
michael@0 3389 memcpy(MD_i1, MD_i, MDLen);
michael@0 3390
michael@0 3391 }
michael@0 3392
michael@0 3393 /* seed = MD_i */
michael@0 3394 memcpy(seed, MD_i, MDLen);
michael@0 3395
michael@0 3396 sprintf(buf, "COUNT = %d\n", j);
michael@0 3397 fputs(buf, resp);
michael@0 3398
michael@0 3399 /* output MD_i */
michael@0 3400 fputs("MD = ", resp);
michael@0 3401 to_hex_str(buf, MD_i, MDLen);
michael@0 3402 fputs(buf, resp);
michael@0 3403 fputc('\n', resp);
michael@0 3404 }
michael@0 3405
michael@0 3406 return SECSuccess;
michael@0 3407 }
michael@0 3408
michael@0 3409 /*
michael@0 3410 * Perform the SHA Tests.
michael@0 3411 *
michael@0 3412 * reqfn is the pathname of the input REQUEST file.
michael@0 3413 *
michael@0 3414 * The output RESPONSE file is written to stdout.
michael@0 3415 */
michael@0 3416 void sha_test(char *reqfn)
michael@0 3417 {
michael@0 3418 unsigned int i, j;
michael@0 3419 unsigned int MDlen; /* the length of the Message Digest in Bytes */
michael@0 3420 unsigned int msgLen; /* the length of the input Message in Bytes */
michael@0 3421 unsigned char *msg = NULL; /* holds the message to digest.*/
michael@0 3422 size_t bufSize = 25608; /*MAX buffer size */
michael@0 3423 char *buf = NULL; /* holds one line from the input REQUEST file.*/
michael@0 3424 unsigned char seed[HASH_LENGTH_MAX]; /* max size of seed 64 bytes */
michael@0 3425 unsigned char MD[HASH_LENGTH_MAX]; /* message digest */
michael@0 3426
michael@0 3427 FILE *req = NULL; /* input stream from the REQUEST file */
michael@0 3428 FILE *resp; /* output stream to the RESPONSE file */
michael@0 3429
michael@0 3430 buf = PORT_ZAlloc(bufSize);
michael@0 3431 if (buf == NULL) {
michael@0 3432 goto loser;
michael@0 3433 }
michael@0 3434
michael@0 3435 /* zeroize the variables for the test with this data set */
michael@0 3436 memset(seed, 0, sizeof seed);
michael@0 3437
michael@0 3438 req = fopen(reqfn, "r");
michael@0 3439 resp = stdout;
michael@0 3440 while (fgets(buf, bufSize, req) != NULL) {
michael@0 3441
michael@0 3442 /* a comment or blank line */
michael@0 3443 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 3444 fputs(buf, resp);
michael@0 3445 continue;
michael@0 3446 }
michael@0 3447 /* [L = Length of the Message Digest and sha_type */
michael@0 3448 if (buf[0] == '[') {
michael@0 3449 if (strncmp(&buf[1], "L ", 1) == 0) {
michael@0 3450 i = 2;
michael@0 3451 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3452 i++;
michael@0 3453 }
michael@0 3454 MDlen = atoi(&buf[i]);
michael@0 3455 fputs(buf, resp);
michael@0 3456 continue;
michael@0 3457 }
michael@0 3458 }
michael@0 3459 /* Len = Length of the Input Message Length ... */
michael@0 3460 if (strncmp(buf, "Len", 3) == 0) {
michael@0 3461 i = 3;
michael@0 3462 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3463 i++;
michael@0 3464 }
michael@0 3465 if (msg) {
michael@0 3466 PORT_ZFree(msg,msgLen);
michael@0 3467 msg = NULL;
michael@0 3468 }
michael@0 3469 msgLen = atoi(&buf[i]); /* in bits */
michael@0 3470 if (msgLen%8 != 0) {
michael@0 3471 fprintf(stderr, "SHA tests are incorrectly configured for "
michael@0 3472 "BIT oriented implementations\n");
michael@0 3473 goto loser;
michael@0 3474 }
michael@0 3475 msgLen = msgLen/8; /* convert to bytes */
michael@0 3476 fputs(buf, resp);
michael@0 3477 msg = PORT_ZAlloc(msgLen);
michael@0 3478 if (msg == NULL && msgLen != 0) {
michael@0 3479 goto loser;
michael@0 3480 }
michael@0 3481 continue;
michael@0 3482 }
michael@0 3483 /* MSG = ... */
michael@0 3484 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 3485 i = 3;
michael@0 3486 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3487 i++;
michael@0 3488 }
michael@0 3489 for (j=0; j< msgLen; i+=2,j++) {
michael@0 3490 hex_to_byteval(&buf[i], &msg[j]);
michael@0 3491 }
michael@0 3492 fputs(buf, resp);
michael@0 3493 /* calculate the Message Digest */
michael@0 3494 memset(MD, 0, sizeof MD);
michael@0 3495 if (sha_calcMD(MD, MDlen,
michael@0 3496 msg, msgLen) != SECSuccess) {
michael@0 3497 goto loser;
michael@0 3498 }
michael@0 3499
michael@0 3500 fputs("MD = ", resp);
michael@0 3501 to_hex_str(buf, MD, MDlen);
michael@0 3502 fputs(buf, resp);
michael@0 3503 fputc('\n', resp);
michael@0 3504
michael@0 3505 continue;
michael@0 3506 }
michael@0 3507 /* Seed = ... */
michael@0 3508 if (strncmp(buf, "Seed", 4) == 0) {
michael@0 3509 i = 4;
michael@0 3510 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3511 i++;
michael@0 3512 }
michael@0 3513 for (j=0; j<sizeof seed; i+=2,j++) {
michael@0 3514 hex_to_byteval(&buf[i], &seed[j]);
michael@0 3515 }
michael@0 3516
michael@0 3517 fputs(buf, resp);
michael@0 3518 fputc('\n', resp);
michael@0 3519
michael@0 3520 /* do the Monte Carlo test */
michael@0 3521 if (sha_mct_test(MDlen, seed, resp) != SECSuccess) {
michael@0 3522 goto loser;
michael@0 3523 }
michael@0 3524
michael@0 3525 continue;
michael@0 3526 }
michael@0 3527 }
michael@0 3528 loser:
michael@0 3529 if (req) {
michael@0 3530 fclose(req);
michael@0 3531 }
michael@0 3532 if (buf) {
michael@0 3533 PORT_ZFree(buf, bufSize);
michael@0 3534 }
michael@0 3535 if (msg) {
michael@0 3536 PORT_ZFree(msg, msgLen);
michael@0 3537 }
michael@0 3538 }
michael@0 3539
michael@0 3540 /****************************************************/
michael@0 3541 /* HMAC SHA-X calc */
michael@0 3542 /* hmac_computed - the computed HMAC */
michael@0 3543 /* hmac_length - the length of the computed HMAC */
michael@0 3544 /* secret_key - secret key to HMAC */
michael@0 3545 /* secret_key_length - length of secret key, */
michael@0 3546 /* message - message to HMAC */
michael@0 3547 /* message_length - length ofthe message */
michael@0 3548 /****************************************************/
michael@0 3549 static SECStatus
michael@0 3550 hmac_calc(unsigned char *hmac_computed,
michael@0 3551 const unsigned int hmac_length,
michael@0 3552 const unsigned char *secret_key,
michael@0 3553 const unsigned int secret_key_length,
michael@0 3554 const unsigned char *message,
michael@0 3555 const unsigned int message_length,
michael@0 3556 const HASH_HashType hashAlg )
michael@0 3557 {
michael@0 3558 SECStatus hmac_status = SECFailure;
michael@0 3559 HMACContext *cx = NULL;
michael@0 3560 SECHashObject *hashObj = NULL;
michael@0 3561 unsigned int bytes_hashed = 0;
michael@0 3562
michael@0 3563 hashObj = (SECHashObject *) HASH_GetRawHashObject(hashAlg);
michael@0 3564
michael@0 3565 if (!hashObj)
michael@0 3566 return( SECFailure );
michael@0 3567
michael@0 3568 cx = HMAC_Create(hashObj, secret_key,
michael@0 3569 secret_key_length,
michael@0 3570 PR_TRUE); /* PR_TRUE for in FIPS mode */
michael@0 3571
michael@0 3572 if (cx == NULL)
michael@0 3573 return( SECFailure );
michael@0 3574
michael@0 3575 HMAC_Begin(cx);
michael@0 3576 HMAC_Update(cx, message, message_length);
michael@0 3577 hmac_status = HMAC_Finish(cx, hmac_computed, &bytes_hashed,
michael@0 3578 hmac_length);
michael@0 3579
michael@0 3580 HMAC_Destroy(cx, PR_TRUE);
michael@0 3581
michael@0 3582 return( hmac_status );
michael@0 3583 }
michael@0 3584
michael@0 3585 /*
michael@0 3586 * Perform the HMAC Tests.
michael@0 3587 *
michael@0 3588 * reqfn is the pathname of the input REQUEST file.
michael@0 3589 *
michael@0 3590 * The output RESPONSE file is written to stdout.
michael@0 3591 */
michael@0 3592 void hmac_test(char *reqfn)
michael@0 3593 {
michael@0 3594 unsigned int i, j;
michael@0 3595 size_t bufSize = 400; /* MAX buffer size */
michael@0 3596 char *buf = NULL; /* holds one line from the input REQUEST file.*/
michael@0 3597 unsigned int keyLen; /* Key Length */
michael@0 3598 unsigned char key[200]; /* key MAX size = 184 */
michael@0 3599 unsigned int msgLen = 128; /* the length of the input */
michael@0 3600 /* Message is always 128 Bytes */
michael@0 3601 unsigned char *msg = NULL; /* holds the message to digest.*/
michael@0 3602 unsigned int HMACLen; /* the length of the HMAC Bytes */
michael@0 3603 unsigned int TLen; /* the length of the requested */
michael@0 3604 /* truncated HMAC Bytes */
michael@0 3605 unsigned char HMAC[HASH_LENGTH_MAX]; /* computed HMAC */
michael@0 3606 unsigned char expectedHMAC[HASH_LENGTH_MAX]; /* for .fax files that have */
michael@0 3607 /* supplied known answer */
michael@0 3608 HASH_HashType hash_alg; /* HMAC type */
michael@0 3609
michael@0 3610
michael@0 3611 FILE *req = NULL; /* input stream from the REQUEST file */
michael@0 3612 FILE *resp; /* output stream to the RESPONSE file */
michael@0 3613
michael@0 3614 buf = PORT_ZAlloc(bufSize);
michael@0 3615 if (buf == NULL) {
michael@0 3616 goto loser;
michael@0 3617 }
michael@0 3618 msg = PORT_ZAlloc(msgLen);
michael@0 3619 if (msg == NULL) {
michael@0 3620 goto loser;
michael@0 3621 }
michael@0 3622
michael@0 3623 req = fopen(reqfn, "r");
michael@0 3624 resp = stdout;
michael@0 3625 while (fgets(buf, bufSize, req) != NULL) {
michael@0 3626 if (strncmp(buf, "Mac", 3) == 0) {
michael@0 3627 i = 3;
michael@0 3628 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3629 i++;
michael@0 3630 }
michael@0 3631 memset(expectedHMAC, 0, HASH_LENGTH_MAX);
michael@0 3632 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 3633 hex_to_byteval(&buf[i], &expectedHMAC[j]);
michael@0 3634 }
michael@0 3635 if (memcmp(HMAC, expectedHMAC, TLen) != 0) {
michael@0 3636 fprintf(stderr, "Generate failed:\n");
michael@0 3637 fputs( " expected=", stderr);
michael@0 3638 to_hex_str(buf, expectedHMAC,
michael@0 3639 TLen);
michael@0 3640 fputs(buf, stderr);
michael@0 3641 fputs("\n generated=", stderr);
michael@0 3642 to_hex_str(buf, HMAC,
michael@0 3643 TLen);
michael@0 3644 fputs(buf, stderr);
michael@0 3645 fputc('\n', stderr);
michael@0 3646 }
michael@0 3647 }
michael@0 3648
michael@0 3649 /* a comment or blank line */
michael@0 3650 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 3651 fputs(buf, resp);
michael@0 3652 continue;
michael@0 3653 }
michael@0 3654 /* [L = Length of the MAC and HASH_type */
michael@0 3655 if (buf[0] == '[') {
michael@0 3656 if (strncmp(&buf[1], "L ", 1) == 0) {
michael@0 3657 i = 2;
michael@0 3658 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3659 i++;
michael@0 3660 }
michael@0 3661 /* HMACLen will get reused for Tlen */
michael@0 3662 HMACLen = atoi(&buf[i]);
michael@0 3663 hash_alg = sha_get_hashType(HMACLen*PR_BITS_PER_BYTE);
michael@0 3664 if (hash_alg == HASH_AlgNULL) {
michael@0 3665 goto loser;
michael@0 3666 }
michael@0 3667 fputs(buf, resp);
michael@0 3668 continue;
michael@0 3669 }
michael@0 3670 }
michael@0 3671 /* Count = test iteration number*/
michael@0 3672 if (strncmp(buf, "Count ", 5) == 0) {
michael@0 3673 /* count can just be put into resp file */
michael@0 3674 fputs(buf, resp);
michael@0 3675 /* zeroize the variables for the test with this data set */
michael@0 3676 keyLen = 0;
michael@0 3677 TLen = 0;
michael@0 3678 memset(key, 0, sizeof key);
michael@0 3679 memset(msg, 0, msgLen);
michael@0 3680 memset(HMAC, 0, sizeof HMAC);
michael@0 3681 continue;
michael@0 3682 }
michael@0 3683 /* KLen = Length of the Input Secret Key ... */
michael@0 3684 if (strncmp(buf, "Klen", 4) == 0) {
michael@0 3685 i = 4;
michael@0 3686 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3687 i++;
michael@0 3688 }
michael@0 3689 keyLen = atoi(&buf[i]); /* in bytes */
michael@0 3690 fputs(buf, resp);
michael@0 3691 continue;
michael@0 3692 }
michael@0 3693 /* key = the secret key for the key to MAC */
michael@0 3694 if (strncmp(buf, "Key", 3) == 0) {
michael@0 3695 i = 3;
michael@0 3696 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3697 i++;
michael@0 3698 }
michael@0 3699 for (j=0; j< keyLen; i+=2,j++) {
michael@0 3700 hex_to_byteval(&buf[i], &key[j]);
michael@0 3701 }
michael@0 3702 fputs(buf, resp);
michael@0 3703 }
michael@0 3704 /* TLen = Length of the calculated HMAC */
michael@0 3705 if (strncmp(buf, "Tlen", 4) == 0) {
michael@0 3706 i = 4;
michael@0 3707 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3708 i++;
michael@0 3709 }
michael@0 3710 TLen = atoi(&buf[i]); /* in bytes */
michael@0 3711 fputs(buf, resp);
michael@0 3712 continue;
michael@0 3713 }
michael@0 3714 /* MSG = to HMAC always 128 bytes for these tests */
michael@0 3715 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 3716 i = 3;
michael@0 3717 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3718 i++;
michael@0 3719 }
michael@0 3720 for (j=0; j< msgLen; i+=2,j++) {
michael@0 3721 hex_to_byteval(&buf[i], &msg[j]);
michael@0 3722 }
michael@0 3723 fputs(buf, resp);
michael@0 3724 /* calculate the HMAC and output */
michael@0 3725 if (hmac_calc(HMAC, HMACLen, key, keyLen,
michael@0 3726 msg, msgLen, hash_alg) != SECSuccess) {
michael@0 3727 goto loser;
michael@0 3728 }
michael@0 3729 fputs("MAC = ", resp);
michael@0 3730 to_hex_str(buf, HMAC, TLen);
michael@0 3731 fputs(buf, resp);
michael@0 3732 fputc('\n', resp);
michael@0 3733 continue;
michael@0 3734 }
michael@0 3735 }
michael@0 3736 loser:
michael@0 3737 if (req) {
michael@0 3738 fclose(req);
michael@0 3739 }
michael@0 3740 if (buf) {
michael@0 3741 PORT_ZFree(buf, bufSize);
michael@0 3742 }
michael@0 3743 if (msg) {
michael@0 3744 PORT_ZFree(msg, msgLen);
michael@0 3745 }
michael@0 3746 }
michael@0 3747
michael@0 3748 /*
michael@0 3749 * Perform the DSA Key Pair Generation Test.
michael@0 3750 *
michael@0 3751 * reqfn is the pathname of the REQUEST file.
michael@0 3752 *
michael@0 3753 * The output RESPONSE file is written to stdout.
michael@0 3754 */
michael@0 3755 void
michael@0 3756 dsa_keypair_test(char *reqfn)
michael@0 3757 {
michael@0 3758 char buf[800]; /* holds one line from the input REQUEST file
michael@0 3759 * or to the output RESPONSE file.
michael@0 3760 * 800 to hold (384 public key (x2 for HEX) + 1'\n'
michael@0 3761 */
michael@0 3762 FILE *dsareq; /* input stream from the REQUEST file */
michael@0 3763 FILE *dsaresp; /* output stream to the RESPONSE file */
michael@0 3764 int count;
michael@0 3765 int N;
michael@0 3766 int L;
michael@0 3767 int i;
michael@0 3768 PQGParams *pqg = NULL;
michael@0 3769 PQGVerify *vfy = NULL;
michael@0 3770 PRBool use_dsa1 = PR_FALSE;
michael@0 3771 int keySizeIndex; /* index for valid key sizes */
michael@0 3772
michael@0 3773 dsareq = fopen(reqfn, "r");
michael@0 3774 dsaresp = stdout;
michael@0 3775 while (fgets(buf, sizeof buf, dsareq) != NULL) {
michael@0 3776 /* a comment or blank line */
michael@0 3777 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 3778 fputs(buf, dsaresp);
michael@0 3779 continue;
michael@0 3780 }
michael@0 3781
michael@0 3782 /* [Mod = x] */
michael@0 3783 if (buf[0] == '[') {
michael@0 3784 if(pqg!=NULL) {
michael@0 3785 PQG_DestroyParams(pqg);
michael@0 3786 pqg = NULL;
michael@0 3787 }
michael@0 3788 if(vfy!=NULL) {
michael@0 3789 PQG_DestroyVerify(vfy);
michael@0 3790 vfy = NULL;
michael@0 3791 }
michael@0 3792
michael@0 3793 if (sscanf(buf, "[mod = L=%d, N=%d]", &L, &N) != 2) {
michael@0 3794 use_dsa1 = PR_TRUE;
michael@0 3795 if (sscanf(buf, "[mod = %d]", &L) != 1) {
michael@0 3796 goto loser;
michael@0 3797 }
michael@0 3798 }
michael@0 3799 fputs(buf, dsaresp);
michael@0 3800 fputc('\n', dsaresp);
michael@0 3801
michael@0 3802 if (use_dsa1) {
michael@0 3803 /*************************************************************
michael@0 3804 * PQG_ParamGenSeedLen doesn't take a key size, it takes an
michael@0 3805 * index that points to a valid key size.
michael@0 3806 */
michael@0 3807 keySizeIndex = PQG_PBITS_TO_INDEX(L);
michael@0 3808 if(keySizeIndex == -1 || L<512 || L>1024) {
michael@0 3809 fprintf(dsaresp,
michael@0 3810 "DSA key size must be a multiple of 64 between 512 "
michael@0 3811 "and 1024, inclusive");
michael@0 3812 goto loser;
michael@0 3813 }
michael@0 3814
michael@0 3815 /* Generate the parameters P, Q, and G */
michael@0 3816 if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
michael@0 3817 &pqg, &vfy) != SECSuccess) {
michael@0 3818 fprintf(dsaresp,
michael@0 3819 "ERROR: Unable to generate PQG parameters");
michael@0 3820 goto loser;
michael@0 3821 }
michael@0 3822 } else {
michael@0 3823 if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
michael@0 3824 fprintf(dsaresp,
michael@0 3825 "ERROR: Unable to generate PQG parameters");
michael@0 3826 goto loser;
michael@0 3827 }
michael@0 3828 }
michael@0 3829
michael@0 3830 /* output P, Q, and G */
michael@0 3831 to_hex_str(buf, pqg->prime.data, pqg->prime.len);
michael@0 3832 fprintf(dsaresp, "P = %s\n", buf);
michael@0 3833 to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
michael@0 3834 fprintf(dsaresp, "Q = %s\n", buf);
michael@0 3835 to_hex_str(buf, pqg->base.data, pqg->base.len);
michael@0 3836 fprintf(dsaresp, "G = %s\n\n", buf);
michael@0 3837 continue;
michael@0 3838 }
michael@0 3839 /* N = ...*/
michael@0 3840 if (buf[0] == 'N') {
michael@0 3841
michael@0 3842 if (sscanf(buf, "N = %d", &count) != 1) {
michael@0 3843 goto loser;
michael@0 3844 }
michael@0 3845 /* Generate a DSA key, and output the key pair for N times */
michael@0 3846 for (i = 0; i < count; i++) {
michael@0 3847 DSAPrivateKey *dsakey = NULL;
michael@0 3848 if (DSA_NewKey(pqg, &dsakey) != SECSuccess) {
michael@0 3849 fprintf(dsaresp, "ERROR: Unable to generate DSA key");
michael@0 3850 goto loser;
michael@0 3851 }
michael@0 3852 to_hex_str(buf, dsakey->privateValue.data,
michael@0 3853 dsakey->privateValue.len);
michael@0 3854 fprintf(dsaresp, "X = %s\n", buf);
michael@0 3855 to_hex_str(buf, dsakey->publicValue.data,
michael@0 3856 dsakey->publicValue.len);
michael@0 3857 fprintf(dsaresp, "Y = %s\n\n", buf);
michael@0 3858 PORT_FreeArena(dsakey->params.arena, PR_TRUE);
michael@0 3859 dsakey = NULL;
michael@0 3860 }
michael@0 3861 continue;
michael@0 3862 }
michael@0 3863
michael@0 3864 }
michael@0 3865 loser:
michael@0 3866 fclose(dsareq);
michael@0 3867 }
michael@0 3868
michael@0 3869 /*
michael@0 3870 * pqg generation type
michael@0 3871 */
michael@0 3872 typedef enum {
michael@0 3873 FIPS186_1,/* Generate/Verify P,Q & G according to FIPS 186-1 */
michael@0 3874 A_1_1_2, /* Generate Probable P & Q */
michael@0 3875 A_1_1_3, /* Verify Probable P & Q */
michael@0 3876 A_1_2_2, /* Verify Provable P & Q */
michael@0 3877 A_2_1, /* Generate Unverifiable G */
michael@0 3878 A_2_2, /* Assure Unverifiable G */
michael@0 3879 A_2_3, /* Generate Verifiable G */
michael@0 3880 A_2_4 /* Verify Verifiable G */
michael@0 3881 } dsa_pqg_type;
michael@0 3882
michael@0 3883 /*
michael@0 3884 * Perform the DSA Domain Parameter Validation Test.
michael@0 3885 *
michael@0 3886 * reqfn is the pathname of the REQUEST file.
michael@0 3887 *
michael@0 3888 * The output RESPONSE file is written to stdout.
michael@0 3889 */
michael@0 3890 void
michael@0 3891 dsa_pqgver_test(char *reqfn)
michael@0 3892 {
michael@0 3893 char buf[800]; /* holds one line from the input REQUEST file
michael@0 3894 * or to the output RESPONSE file.
michael@0 3895 * 800 to hold (384 public key (x2 for HEX) + P = ...
michael@0 3896 */
michael@0 3897 FILE *dsareq; /* input stream from the REQUEST file */
michael@0 3898 FILE *dsaresp; /* output stream to the RESPONSE file */
michael@0 3899 int N;
michael@0 3900 int L;
michael@0 3901 unsigned int i, j;
michael@0 3902 PQGParams pqg;
michael@0 3903 PQGVerify vfy;
michael@0 3904 unsigned int pghSize; /* size for p, g, and h */
michael@0 3905 dsa_pqg_type type = FIPS186_1;
michael@0 3906
michael@0 3907 dsareq = fopen(reqfn, "r");
michael@0 3908 dsaresp = stdout;
michael@0 3909 memset(&pqg, 0, sizeof(pqg));
michael@0 3910 memset(&vfy, 0, sizeof(vfy));
michael@0 3911
michael@0 3912 while (fgets(buf, sizeof buf, dsareq) != NULL) {
michael@0 3913 /* a comment or blank line */
michael@0 3914 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 3915 fputs(buf, dsaresp);
michael@0 3916 continue;
michael@0 3917 }
michael@0 3918
michael@0 3919 /* [A.xxxxx ] */
michael@0 3920 if (buf[0] == '[' && buf[1] == 'A') {
michael@0 3921
michael@0 3922 if (strncmp(&buf[1],"A.1.1.3",7) == 0) {
michael@0 3923 type = A_1_1_3;
michael@0 3924 } else if (strncmp(&buf[1],"A.2.2",5) == 0) {
michael@0 3925 type = A_2_2;
michael@0 3926 } else if (strncmp(&buf[1],"A.2.4",5) == 0) {
michael@0 3927 type = A_2_4;
michael@0 3928 } else if (strncmp(&buf[1],"A.1.2.2",7) == 0) {
michael@0 3929 type = A_1_2_2;
michael@0 3930 /* validate our output from PQGGEN */
michael@0 3931 } else if (strncmp(&buf[1],"A.1.1.2",7) == 0) {
michael@0 3932 type = A_2_4; /* validate PQ and G together */
michael@0 3933 } else {
michael@0 3934 fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]);
michael@0 3935 exit(1);
michael@0 3936 }
michael@0 3937
michael@0 3938 fputs(buf, dsaresp);
michael@0 3939 continue;
michael@0 3940 }
michael@0 3941
michael@0 3942
michael@0 3943 /* [Mod = x] */
michael@0 3944 if (buf[0] == '[') {
michael@0 3945
michael@0 3946 if (type == FIPS186_1) {
michael@0 3947 N=160;
michael@0 3948 if (sscanf(buf, "[mod = %d]", &L) != 1) {
michael@0 3949 goto loser;
michael@0 3950 }
michael@0 3951 } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) {
michael@0 3952 goto loser;
michael@0 3953 }
michael@0 3954
michael@0 3955 if (pqg.prime.data) { /* P */
michael@0 3956 SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
michael@0 3957 }
michael@0 3958 if (pqg.subPrime.data) { /* Q */
michael@0 3959 SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
michael@0 3960 }
michael@0 3961 if (pqg.base.data) { /* G */
michael@0 3962 SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
michael@0 3963 }
michael@0 3964 if (vfy.seed.data) { /* seed */
michael@0 3965 SECITEM_ZfreeItem(&vfy.seed, PR_FALSE);
michael@0 3966 }
michael@0 3967 if (vfy.h.data) { /* H */
michael@0 3968 SECITEM_ZfreeItem(&vfy.h, PR_FALSE);
michael@0 3969 }
michael@0 3970
michael@0 3971 fputs(buf, dsaresp);
michael@0 3972
michael@0 3973 /*calculate the size of p, g, and h then allocate items */
michael@0 3974 pghSize = L/8;
michael@0 3975
michael@0 3976 pqg.base.data = vfy.h.data = NULL;
michael@0 3977 vfy.seed.len = pqg.base.len = vfy.h.len = 0;
michael@0 3978 SECITEM_AllocItem(NULL, &pqg.prime, pghSize);
michael@0 3979 SECITEM_AllocItem(NULL, &vfy.seed, pghSize*3);
michael@0 3980 if (type == A_2_2) {
michael@0 3981 SECITEM_AllocItem(NULL, &vfy.h, pghSize);
michael@0 3982 vfy.h.len = pghSize;
michael@0 3983 } else if (type == A_2_4) {
michael@0 3984 SECITEM_AllocItem(NULL, &vfy.h, 1);
michael@0 3985 vfy.h.len = 1;
michael@0 3986 }
michael@0 3987 pqg.prime.len = pghSize;
michael@0 3988 /* q is always N bits */
michael@0 3989 SECITEM_AllocItem(NULL, &pqg.subPrime, N/8);
michael@0 3990 pqg.subPrime.len = N/8;
michael@0 3991 vfy.counter = -1;
michael@0 3992
michael@0 3993 continue;
michael@0 3994 }
michael@0 3995 /* P = ... */
michael@0 3996 if (buf[0] == 'P') {
michael@0 3997 i = 1;
michael@0 3998 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 3999 i++;
michael@0 4000 }
michael@0 4001 for (j=0; j< pqg.prime.len; i+=2,j++) {
michael@0 4002 hex_to_byteval(&buf[i], &pqg.prime.data[j]);
michael@0 4003 }
michael@0 4004
michael@0 4005 fputs(buf, dsaresp);
michael@0 4006 continue;
michael@0 4007 }
michael@0 4008
michael@0 4009 /* Q = ... */
michael@0 4010 if (buf[0] == 'Q') {
michael@0 4011 i = 1;
michael@0 4012 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4013 i++;
michael@0 4014 }
michael@0 4015 for (j=0; j< pqg.subPrime.len; i+=2,j++) {
michael@0 4016 hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
michael@0 4017 }
michael@0 4018
michael@0 4019 fputs(buf, dsaresp);
michael@0 4020 continue;
michael@0 4021 }
michael@0 4022
michael@0 4023 /* G = ... */
michael@0 4024 if (buf[0] == 'G') {
michael@0 4025 i = 1;
michael@0 4026 if (pqg.base.data) {
michael@0 4027 SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
michael@0 4028 }
michael@0 4029 SECITEM_AllocItem(NULL, &pqg.base, pghSize);
michael@0 4030 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4031 i++;
michael@0 4032 }
michael@0 4033 for (j=0; j< pqg.base.len; i+=2,j++) {
michael@0 4034 hex_to_byteval(&buf[i], &pqg.base.data[j]);
michael@0 4035 }
michael@0 4036
michael@0 4037 fputs(buf, dsaresp);
michael@0 4038 continue;
michael@0 4039 }
michael@0 4040
michael@0 4041 /* Seed = ... or domain_parameter_seed = ... */
michael@0 4042 if (strncmp(buf, "Seed", 4) == 0) {
michael@0 4043 i = 4;
michael@0 4044 } else if (strncmp(buf, "domain_parameter_seed", 21) == 0) {
michael@0 4045 i = 21;
michael@0 4046 } else if (strncmp(buf,"firstseed",9) == 0) {
michael@0 4047 i = 9;
michael@0 4048 } else {
michael@0 4049 i = 0;
michael@0 4050 }
michael@0 4051 if (i) {
michael@0 4052 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4053 i++;
michael@0 4054 }
michael@0 4055 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 4056 hex_to_byteval(&buf[i], &vfy.seed.data[j]);
michael@0 4057 }
michael@0 4058 vfy.seed.len = j;
michael@0 4059
michael@0 4060 fputs(buf, dsaresp);
michael@0 4061 if (type == A_2_4) {
michael@0 4062 SECStatus result;
michael@0 4063
michael@0 4064 /* Verify the Parameters */
michael@0 4065 SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result);
michael@0 4066 if (rv != SECSuccess) {
michael@0 4067 goto loser;
michael@0 4068 }
michael@0 4069 if (result == SECSuccess) {
michael@0 4070 fprintf(dsaresp, "Result = P\n");
michael@0 4071 } else {
michael@0 4072 fprintf(dsaresp, "Result = F\n");
michael@0 4073 }
michael@0 4074 }
michael@0 4075 continue;
michael@0 4076 }
michael@0 4077 if ((strncmp(buf,"pseed",5) == 0) ||
michael@0 4078 (strncmp(buf,"qseed",5) == 0))
michael@0 4079 {
michael@0 4080 i = 5;
michael@0 4081 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4082 i++;
michael@0 4083 }
michael@0 4084 for (j=vfy.seed.len; isxdigit(buf[i]); i+=2,j++) {
michael@0 4085 hex_to_byteval(&buf[i], &vfy.seed.data[j]);
michael@0 4086 }
michael@0 4087 vfy.seed.len = j;
michael@0 4088 fputs(buf, dsaresp);
michael@0 4089
michael@0 4090 continue;
michael@0 4091 }
michael@0 4092 if (strncmp(buf, "index", 4) == 0) {
michael@0 4093 i=5;
michael@0 4094 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4095 i++;
michael@0 4096 }
michael@0 4097 hex_to_byteval(&buf[i], &vfy.h.data[0]);
michael@0 4098 vfy.h.len = 1;
michael@0 4099 fputs(buf, dsaresp);
michael@0 4100 }
michael@0 4101
michael@0 4102 /* c = ... or counter=*/
michael@0 4103 if (buf[0] == 'c') {
michael@0 4104 if (strncmp(buf,"counter", 7) == 0) {
michael@0 4105 if (sscanf(buf, "counter = %u", &vfy.counter) != 1) {
michael@0 4106 goto loser;
michael@0 4107 }
michael@0 4108 } else {
michael@0 4109 if (sscanf(buf, "c = %u", &vfy.counter) != 1) {
michael@0 4110 goto loser;
michael@0 4111 }
michael@0 4112 }
michael@0 4113
michael@0 4114 fputs(buf, dsaresp);
michael@0 4115 if (type == A_1_1_3) {
michael@0 4116 SECStatus result;
michael@0 4117 /* only verify P and Q, we have everything now. do it */
michael@0 4118 SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result);
michael@0 4119 if (rv != SECSuccess) {
michael@0 4120 goto loser;
michael@0 4121 }
michael@0 4122 if (result == SECSuccess) {
michael@0 4123 fprintf(dsaresp, "Result = P\n");
michael@0 4124 } else {
michael@0 4125 fprintf(dsaresp, "Result = F\n");
michael@0 4126 }
michael@0 4127 fprintf(dsaresp, "\n");
michael@0 4128 }
michael@0 4129 continue;
michael@0 4130 }
michael@0 4131 if (strncmp(buf,"pgen_counter", 12) == 0) {
michael@0 4132 if (sscanf(buf, "pgen_counter = %u", &vfy.counter) != 1) {
michael@0 4133 goto loser;
michael@0 4134 }
michael@0 4135 fputs(buf, dsaresp);
michael@0 4136 continue;
michael@0 4137 }
michael@0 4138 if (strncmp(buf,"qgen_counter", 12) == 0) {
michael@0 4139 fputs(buf, dsaresp);
michael@0 4140 if (type == A_1_2_2) {
michael@0 4141 SECStatus result;
michael@0 4142 /* only verify P and Q, we have everything now. do it */
michael@0 4143 SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result);
michael@0 4144 if (rv != SECSuccess) {
michael@0 4145 goto loser;
michael@0 4146 }
michael@0 4147 if (result == SECSuccess) {
michael@0 4148 fprintf(dsaresp, "Result = P\n");
michael@0 4149 } else {
michael@0 4150 fprintf(dsaresp, "Result = F\n");
michael@0 4151 }
michael@0 4152 fprintf(dsaresp, "\n");
michael@0 4153 }
michael@0 4154 continue;
michael@0 4155 }
michael@0 4156 /* H = ... */
michael@0 4157 if (buf[0] == 'H') {
michael@0 4158 SECStatus rv, result = SECFailure;
michael@0 4159
michael@0 4160 i = 1;
michael@0 4161 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4162 i++;
michael@0 4163 }
michael@0 4164 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 4165 hex_to_byteval(&buf[i], &vfy.h.data[j]);
michael@0 4166 }
michael@0 4167 vfy.h.len = j;
michael@0 4168 fputs(buf, dsaresp);
michael@0 4169
michael@0 4170 /* this should be a byte value. Remove the leading zeros. If
michael@0 4171 * it doesn't reduce to a byte, PQG_VerifyParams will catch it
michael@0 4172 if (type == A_2_2) {
michael@0 4173 data_save = vfy.h.data;
michael@0 4174 while(vfy.h.data[0] && (vfy.h.len > 1)) {
michael@0 4175 vfy.h.data++;
michael@0 4176 vfy.h.len--;
michael@0 4177 }
michael@0 4178 } */
michael@0 4179
michael@0 4180 /* Verify the Parameters */
michael@0 4181 rv = PQG_VerifyParams(&pqg, &vfy, &result);
michael@0 4182 if (rv != SECSuccess) {
michael@0 4183 goto loser;
michael@0 4184 }
michael@0 4185 if (result == SECSuccess) {
michael@0 4186 fprintf(dsaresp, "Result = P\n");
michael@0 4187 } else {
michael@0 4188 fprintf(dsaresp, "Result = F\n");
michael@0 4189 }
michael@0 4190 fprintf(dsaresp, "\n");
michael@0 4191 continue;
michael@0 4192 }
michael@0 4193 }
michael@0 4194 loser:
michael@0 4195 fclose(dsareq);
michael@0 4196 if (pqg.prime.data) { /* P */
michael@0 4197 SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
michael@0 4198 }
michael@0 4199 if (pqg.subPrime.data) { /* Q */
michael@0 4200 SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
michael@0 4201 }
michael@0 4202 if (pqg.base.data) { /* G */
michael@0 4203 SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
michael@0 4204 }
michael@0 4205 if (vfy.seed.data) { /* seed */
michael@0 4206 SECITEM_ZfreeItem(&vfy.seed, PR_FALSE);
michael@0 4207 }
michael@0 4208 if (vfy.h.data) { /* H */
michael@0 4209 SECITEM_ZfreeItem(&vfy.h, PR_FALSE);
michael@0 4210 }
michael@0 4211
michael@0 4212 }
michael@0 4213
michael@0 4214 /*
michael@0 4215 * Perform the DSA Public Key Validation Test.
michael@0 4216 *
michael@0 4217 * reqfn is the pathname of the REQUEST file.
michael@0 4218 *
michael@0 4219 * The output RESPONSE file is written to stdout.
michael@0 4220 */
michael@0 4221 void
michael@0 4222 dsa_pqggen_test(char *reqfn)
michael@0 4223 {
michael@0 4224 char buf[800]; /* holds one line from the input REQUEST file
michael@0 4225 * or to the output RESPONSE file.
michael@0 4226 * 800 to hold seed = (384 public key (x2 for HEX)
michael@0 4227 */
michael@0 4228 FILE *dsareq; /* input stream from the REQUEST file */
michael@0 4229 FILE *dsaresp; /* output stream to the RESPONSE file */
michael@0 4230 int count; /* number of times to generate parameters */
michael@0 4231 int N;
michael@0 4232 int L;
michael@0 4233 int i;
michael@0 4234 unsigned int j;
michael@0 4235 PQGParams *pqg = NULL;
michael@0 4236 PQGVerify *vfy = NULL;
michael@0 4237 unsigned int keySizeIndex;
michael@0 4238 dsa_pqg_type type = FIPS186_1;
michael@0 4239
michael@0 4240 dsareq = fopen(reqfn, "r");
michael@0 4241 dsaresp = stdout;
michael@0 4242 while (fgets(buf, sizeof buf, dsareq) != NULL) {
michael@0 4243 /* a comment or blank line */
michael@0 4244 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 4245 fputs(buf, dsaresp);
michael@0 4246 continue;
michael@0 4247 }
michael@0 4248
michael@0 4249 /* [A.xxxxx ] */
michael@0 4250 if (buf[0] == '[' && buf[1] == 'A') {
michael@0 4251 if (strncmp(&buf[1],"A.1.1.2",7) == 0) {
michael@0 4252 type = A_1_1_2;
michael@0 4253 } else if (strncmp(&buf[1],"A.2.1",5) == 0) {
michael@0 4254 fprintf(stderr, "NSS only Generates G with P&Q\n");
michael@0 4255 exit(1);
michael@0 4256 } else if (strncmp(&buf[1],"A.2.3",5) == 0) {
michael@0 4257 fprintf(stderr, "NSS only Generates G with P&Q\n");
michael@0 4258 exit(1);
michael@0 4259 } else if (strncmp(&buf[1],"A.1.2.1",7) == 0) {
michael@0 4260 fprintf(stderr, "NSS does not support Shawe-Taylor Primes\n");
michael@0 4261 exit(1);
michael@0 4262 } else {
michael@0 4263 fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]);
michael@0 4264 exit(1);
michael@0 4265 }
michael@0 4266 fputs(buf, dsaresp);
michael@0 4267 continue;
michael@0 4268 }
michael@0 4269
michael@0 4270 /* [Mod = ... ] */
michael@0 4271 if (buf[0] == '[') {
michael@0 4272
michael@0 4273 if (type == FIPS186_1) {
michael@0 4274 N=160;
michael@0 4275 if (sscanf(buf, "[mod = %d]", &L) != 1) {
michael@0 4276 goto loser;
michael@0 4277 }
michael@0 4278 } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) {
michael@0 4279 goto loser;
michael@0 4280 }
michael@0 4281
michael@0 4282 fputs(buf, dsaresp);
michael@0 4283 fputc('\n', dsaresp);
michael@0 4284
michael@0 4285 if (type == FIPS186_1) {
michael@0 4286 /************************************************************
michael@0 4287 * PQG_ParamGenSeedLen doesn't take a key size, it takes an
michael@0 4288 * index that points to a valid key size.
michael@0 4289 */
michael@0 4290 keySizeIndex = PQG_PBITS_TO_INDEX(L);
michael@0 4291 if(keySizeIndex == -1 || L<512 || L>1024) {
michael@0 4292 fprintf(dsaresp,
michael@0 4293 "DSA key size must be a multiple of 64 between 512 "
michael@0 4294 "and 1024, inclusive");
michael@0 4295 goto loser;
michael@0 4296 }
michael@0 4297 }
michael@0 4298 continue;
michael@0 4299 }
michael@0 4300 /* N = ... */
michael@0 4301 if (buf[0] == 'N') {
michael@0 4302 if (sscanf(buf, "N = %d", &count) != 1) {
michael@0 4303 goto loser;
michael@0 4304 }
michael@0 4305 for (i = 0; i < count; i++) {
michael@0 4306 SECStatus rv;
michael@0 4307
michael@0 4308 if (type == FIPS186_1) {
michael@0 4309 rv = PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
michael@0 4310 &pqg, &vfy);
michael@0 4311 } else {
michael@0 4312 rv = PQG_ParamGenV2(L, N, N, &pqg, &vfy);
michael@0 4313 }
michael@0 4314 if (rv != SECSuccess) {
michael@0 4315 fprintf(dsaresp,
michael@0 4316 "ERROR: Unable to generate PQG parameters");
michael@0 4317 goto loser;
michael@0 4318 }
michael@0 4319 to_hex_str(buf, pqg->prime.data, pqg->prime.len);
michael@0 4320 fprintf(dsaresp, "P = %s\n", buf);
michael@0 4321 to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
michael@0 4322 fprintf(dsaresp, "Q = %s\n", buf);
michael@0 4323 to_hex_str(buf, pqg->base.data, pqg->base.len);
michael@0 4324 fprintf(dsaresp, "G = %s\n", buf);
michael@0 4325 if (type == FIPS186_1) {
michael@0 4326 to_hex_str(buf, vfy->seed.data, vfy->seed.len);
michael@0 4327 fprintf(dsaresp, "Seed = %s\n", buf);
michael@0 4328 fprintf(dsaresp, "c = %d\n", vfy->counter);
michael@0 4329 to_hex_str(buf, vfy->h.data, vfy->h.len);
michael@0 4330 fputs("H = ", dsaresp);
michael@0 4331 for (j=vfy->h.len; j< pqg->prime.len; j++) {
michael@0 4332 fprintf(dsaresp, "00");
michael@0 4333 }
michael@0 4334 fprintf(dsaresp, "%s\n", buf);
michael@0 4335 } else {
michael@0 4336 fprintf(dsaresp, "counter = %d\n", vfy->counter);
michael@0 4337 fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]);
michael@0 4338 to_hex_str(buf, vfy->seed.data, vfy->seed.len);
michael@0 4339 fprintf(dsaresp, "domain_parameter_seed = %s\n", buf);
michael@0 4340 }
michael@0 4341 fputc('\n', dsaresp);
michael@0 4342 if(pqg!=NULL) {
michael@0 4343 PQG_DestroyParams(pqg);
michael@0 4344 pqg = NULL;
michael@0 4345 }
michael@0 4346 if(vfy!=NULL) {
michael@0 4347 PQG_DestroyVerify(vfy);
michael@0 4348 vfy = NULL;
michael@0 4349 }
michael@0 4350 }
michael@0 4351
michael@0 4352 continue;
michael@0 4353 }
michael@0 4354
michael@0 4355 }
michael@0 4356 loser:
michael@0 4357 fclose(dsareq);
michael@0 4358 if(pqg!=NULL) {
michael@0 4359 PQG_DestroyParams(pqg);
michael@0 4360 }
michael@0 4361 if(vfy!=NULL) {
michael@0 4362 PQG_DestroyVerify(vfy);
michael@0 4363 }
michael@0 4364 }
michael@0 4365
michael@0 4366
michael@0 4367 /*
michael@0 4368 * Perform the DSA Signature Generation Test.
michael@0 4369 *
michael@0 4370 * reqfn is the pathname of the REQUEST file.
michael@0 4371 *
michael@0 4372 * The output RESPONSE file is written to stdout.
michael@0 4373 */
michael@0 4374 void
michael@0 4375 dsa_siggen_test(char *reqfn)
michael@0 4376 {
michael@0 4377 char buf[800]; /* holds one line from the input REQUEST file
michael@0 4378 * or to the output RESPONSE file.
michael@0 4379 * max for Msg = ....
michael@0 4380 */
michael@0 4381 FILE *dsareq; /* input stream from the REQUEST file */
michael@0 4382 FILE *dsaresp; /* output stream to the RESPONSE file */
michael@0 4383 int modulus;
michael@0 4384 int L;
michael@0 4385 int N;
michael@0 4386 int i, j;
michael@0 4387 PRBool use_dsa1 = PR_FALSE;
michael@0 4388 PQGParams *pqg = NULL;
michael@0 4389 PQGVerify *vfy = NULL;
michael@0 4390 DSAPrivateKey *dsakey = NULL;
michael@0 4391 int keySizeIndex; /* index for valid key sizes */
michael@0 4392 unsigned char hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */
michael@0 4393 unsigned char sig[DSA_MAX_SIGNATURE_LEN];
michael@0 4394 SECItem digest, signature;
michael@0 4395 HASH_HashType hashType = HASH_AlgNULL;
michael@0 4396 int hashNum = 0;
michael@0 4397
michael@0 4398 dsareq = fopen(reqfn, "r");
michael@0 4399 dsaresp = stdout;
michael@0 4400
michael@0 4401 while (fgets(buf, sizeof buf, dsareq) != NULL) {
michael@0 4402 /* a comment or blank line */
michael@0 4403 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 4404 fputs(buf, dsaresp);
michael@0 4405 continue;
michael@0 4406 }
michael@0 4407
michael@0 4408 /* [Mod = x] */
michael@0 4409 if (buf[0] == '[') {
michael@0 4410 if(pqg!=NULL) {
michael@0 4411 PQG_DestroyParams(pqg);
michael@0 4412 pqg = NULL;
michael@0 4413 }
michael@0 4414 if(vfy!=NULL) {
michael@0 4415 PQG_DestroyVerify(vfy);
michael@0 4416 vfy = NULL;
michael@0 4417 }
michael@0 4418 if (dsakey != NULL) {
michael@0 4419 PORT_FreeArena(dsakey->params.arena, PR_TRUE);
michael@0 4420 dsakey = NULL;
michael@0 4421 }
michael@0 4422
michael@0 4423 if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d]", &L, & N,
michael@0 4424 &hashNum) != 3) {
michael@0 4425 use_dsa1 = PR_TRUE;
michael@0 4426 hashNum = 1;
michael@0 4427 if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
michael@0 4428 goto loser;
michael@0 4429 }
michael@0 4430 }
michael@0 4431 fputs(buf, dsaresp);
michael@0 4432 fputc('\n', dsaresp);
michael@0 4433
michael@0 4434 /****************************************************************
michael@0 4435 * PQG_ParamGenSeedLen doesn't take a key size, it takes an index
michael@0 4436 * that points to a valid key size.
michael@0 4437 */
michael@0 4438 if (use_dsa1) {
michael@0 4439 keySizeIndex = PQG_PBITS_TO_INDEX(modulus);
michael@0 4440 if(keySizeIndex == -1 || modulus<512 || modulus>1024) {
michael@0 4441 fprintf(dsaresp,
michael@0 4442 "DSA key size must be a multiple of 64 between 512 "
michael@0 4443 "and 1024, inclusive");
michael@0 4444 goto loser;
michael@0 4445 }
michael@0 4446 /* Generate PQG and output PQG */
michael@0 4447 if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
michael@0 4448 &pqg, &vfy) != SECSuccess) {
michael@0 4449 fprintf(dsaresp,
michael@0 4450 "ERROR: Unable to generate PQG parameters");
michael@0 4451 goto loser;
michael@0 4452 }
michael@0 4453 } else {
michael@0 4454 if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
michael@0 4455 fprintf(dsaresp,
michael@0 4456 "ERROR: Unable to generate PQG parameters");
michael@0 4457 goto loser;
michael@0 4458 }
michael@0 4459 }
michael@0 4460 to_hex_str(buf, pqg->prime.data, pqg->prime.len);
michael@0 4461 fprintf(dsaresp, "P = %s\n", buf);
michael@0 4462 to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
michael@0 4463 fprintf(dsaresp, "Q = %s\n", buf);
michael@0 4464 to_hex_str(buf, pqg->base.data, pqg->base.len);
michael@0 4465 fprintf(dsaresp, "G = %s\n", buf);
michael@0 4466
michael@0 4467 /* create DSA Key */
michael@0 4468 if (DSA_NewKey(pqg, &dsakey) != SECSuccess) {
michael@0 4469 fprintf(dsaresp, "ERROR: Unable to generate DSA key");
michael@0 4470 goto loser;
michael@0 4471 }
michael@0 4472
michael@0 4473 hashType = sha_get_hashType(hashNum);
michael@0 4474 if (hashType == HASH_AlgNULL) {
michael@0 4475 fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum);
michael@0 4476 goto loser;
michael@0 4477 }
michael@0 4478 continue;
michael@0 4479 }
michael@0 4480
michael@0 4481 /* Msg = ... */
michael@0 4482 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 4483 unsigned char msg[128]; /* MAX msg 128 */
michael@0 4484 unsigned int len = 0;
michael@0 4485
michael@0 4486 if (hashType == HASH_AlgNULL) {
michael@0 4487 fprintf(dsaresp, "ERROR: Hash Alg not set");
michael@0 4488 goto loser;
michael@0 4489 }
michael@0 4490
michael@0 4491 memset(hashBuf, 0, sizeof hashBuf);
michael@0 4492 memset(sig, 0, sizeof sig);
michael@0 4493
michael@0 4494 i = 3;
michael@0 4495 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4496 i++;
michael@0 4497 }
michael@0 4498 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 4499 hex_to_byteval(&buf[i], &msg[j]);
michael@0 4500 }
michael@0 4501 if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) {
michael@0 4502 fprintf(dsaresp, "ERROR: Unable to generate SHA% digest",
michael@0 4503 hashNum);
michael@0 4504 goto loser;
michael@0 4505 }
michael@0 4506
michael@0 4507
michael@0 4508 digest.type = siBuffer;
michael@0 4509 digest.data = hashBuf;
michael@0 4510 digest.len = fips_hashLen(hashType);
michael@0 4511 signature.type = siBuffer;
michael@0 4512 signature.data = sig;
michael@0 4513 signature.len = sizeof sig;
michael@0 4514
michael@0 4515 if (DSA_SignDigest(dsakey, &signature, &digest) != SECSuccess) {
michael@0 4516 fprintf(dsaresp, "ERROR: Unable to generate DSA signature");
michael@0 4517 goto loser;
michael@0 4518 }
michael@0 4519 len = signature.len;
michael@0 4520 if (len%2 != 0) {
michael@0 4521 goto loser;
michael@0 4522 }
michael@0 4523 len = len/2;
michael@0 4524
michael@0 4525 /* output the orginal Msg, and generated Y, R, and S */
michael@0 4526 fputs(buf, dsaresp);
michael@0 4527 to_hex_str(buf, dsakey->publicValue.data,
michael@0 4528 dsakey->publicValue.len);
michael@0 4529 fprintf(dsaresp, "Y = %s\n", buf);
michael@0 4530 to_hex_str(buf, &signature.data[0], len);
michael@0 4531 fprintf(dsaresp, "R = %s\n", buf);
michael@0 4532 to_hex_str(buf, &signature.data[len], len);
michael@0 4533 fprintf(dsaresp, "S = %s\n", buf);
michael@0 4534 fputc('\n', dsaresp);
michael@0 4535 continue;
michael@0 4536 }
michael@0 4537
michael@0 4538 }
michael@0 4539 loser:
michael@0 4540 fclose(dsareq);
michael@0 4541 if(pqg != NULL) {
michael@0 4542 PQG_DestroyParams(pqg);
michael@0 4543 pqg = NULL;
michael@0 4544 }
michael@0 4545 if(vfy != NULL) {
michael@0 4546 PQG_DestroyVerify(vfy);
michael@0 4547 vfy = NULL;
michael@0 4548 }
michael@0 4549 if (dsakey) {
michael@0 4550 PORT_FreeArena(dsakey->params.arena, PR_TRUE);
michael@0 4551 dsakey = NULL;
michael@0 4552 }
michael@0 4553 }
michael@0 4554
michael@0 4555 /*
michael@0 4556 * Perform the DSA Signature Verification Test.
michael@0 4557 *
michael@0 4558 * reqfn is the pathname of the REQUEST file.
michael@0 4559 *
michael@0 4560 * The output RESPONSE file is written to stdout.
michael@0 4561 */
michael@0 4562 void
michael@0 4563 dsa_sigver_test(char *reqfn)
michael@0 4564 {
michael@0 4565 char buf[800]; /* holds one line from the input REQUEST file
michael@0 4566 * or to the output RESPONSE file.
michael@0 4567 * max for Msg = ....
michael@0 4568 */
michael@0 4569 FILE *dsareq; /* input stream from the REQUEST file */
michael@0 4570 FILE *dsaresp; /* output stream to the RESPONSE file */
michael@0 4571 int L;
michael@0 4572 int N;
michael@0 4573 unsigned int i, j;
michael@0 4574 SECItem digest, signature;
michael@0 4575 DSAPublicKey pubkey;
michael@0 4576 unsigned int pgySize; /* size for p, g, and y */
michael@0 4577 unsigned char hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */
michael@0 4578 unsigned char sig[DSA_MAX_SIGNATURE_LEN];
michael@0 4579 HASH_HashType hashType = HASH_AlgNULL;
michael@0 4580 int hashNum = 0;
michael@0 4581
michael@0 4582 dsareq = fopen(reqfn, "r");
michael@0 4583 dsaresp = stdout;
michael@0 4584 memset(&pubkey, 0, sizeof(pubkey));
michael@0 4585
michael@0 4586 while (fgets(buf, sizeof buf, dsareq) != NULL) {
michael@0 4587 /* a comment or blank line */
michael@0 4588 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 4589 fputs(buf, dsaresp);
michael@0 4590 continue;
michael@0 4591 }
michael@0 4592
michael@0 4593 /* [Mod = x] */
michael@0 4594 if (buf[0] == '[') {
michael@0 4595
michael@0 4596 if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d]", &L, & N,
michael@0 4597 &hashNum) != 3) {
michael@0 4598 N=160;
michael@0 4599 hashNum = 1;
michael@0 4600 if (sscanf(buf, "[mod = %d]", &L) != 1) {
michael@0 4601 goto loser;
michael@0 4602 }
michael@0 4603 }
michael@0 4604
michael@0 4605 if (pubkey.params.prime.data) { /* P */
michael@0 4606 SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE);
michael@0 4607 }
michael@0 4608 if (pubkey.params.subPrime.data) { /* Q */
michael@0 4609 SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE);
michael@0 4610 }
michael@0 4611 if (pubkey.params.base.data) { /* G */
michael@0 4612 SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE);
michael@0 4613 }
michael@0 4614 if (pubkey.publicValue.data) { /* Y */
michael@0 4615 SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE);
michael@0 4616 }
michael@0 4617 fputs(buf, dsaresp);
michael@0 4618
michael@0 4619 /* calculate the size of p, g, and y then allocate items */
michael@0 4620 pgySize = L/8;
michael@0 4621 SECITEM_AllocItem(NULL, &pubkey.params.prime, pgySize);
michael@0 4622 SECITEM_AllocItem(NULL, &pubkey.params.base, pgySize);
michael@0 4623 SECITEM_AllocItem(NULL, &pubkey.publicValue, pgySize);
michael@0 4624 pubkey.params.prime.len = pubkey.params.base.len = pgySize;
michael@0 4625 pubkey.publicValue.len = pgySize;
michael@0 4626
michael@0 4627 /* q always N/8 bytes */
michael@0 4628 SECITEM_AllocItem(NULL, &pubkey.params.subPrime, N/8);
michael@0 4629 pubkey.params.subPrime.len = N/8;
michael@0 4630
michael@0 4631 hashType = sha_get_hashType(hashNum);
michael@0 4632 if (hashType == HASH_AlgNULL) {
michael@0 4633 fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum);
michael@0 4634 goto loser;
michael@0 4635 }
michael@0 4636
michael@0 4637 continue;
michael@0 4638 }
michael@0 4639 /* P = ... */
michael@0 4640 if (buf[0] == 'P') {
michael@0 4641 i = 1;
michael@0 4642 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4643 i++;
michael@0 4644 }
michael@0 4645 memset(pubkey.params.prime.data, 0, pubkey.params.prime.len);
michael@0 4646 for (j=0; j< pubkey.params.prime.len; i+=2,j++) {
michael@0 4647 hex_to_byteval(&buf[i], &pubkey.params.prime.data[j]);
michael@0 4648 }
michael@0 4649
michael@0 4650 fputs(buf, dsaresp);
michael@0 4651 continue;
michael@0 4652 }
michael@0 4653
michael@0 4654 /* Q = ... */
michael@0 4655 if (buf[0] == 'Q') {
michael@0 4656 i = 1;
michael@0 4657 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4658 i++;
michael@0 4659 }
michael@0 4660 memset(pubkey.params.subPrime.data, 0, pubkey.params.subPrime.len);
michael@0 4661 for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) {
michael@0 4662 hex_to_byteval(&buf[i], &pubkey.params.subPrime.data[j]);
michael@0 4663 }
michael@0 4664
michael@0 4665 fputs(buf, dsaresp);
michael@0 4666 continue;
michael@0 4667 }
michael@0 4668
michael@0 4669 /* G = ... */
michael@0 4670 if (buf[0] == 'G') {
michael@0 4671 i = 1;
michael@0 4672 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4673 i++;
michael@0 4674 }
michael@0 4675 memset(pubkey.params.base.data, 0, pubkey.params.base.len);
michael@0 4676 for (j=0; j< pubkey.params.base.len; i+=2,j++) {
michael@0 4677 hex_to_byteval(&buf[i], &pubkey.params.base.data[j]);
michael@0 4678 }
michael@0 4679
michael@0 4680 fputs(buf, dsaresp);
michael@0 4681 continue;
michael@0 4682 }
michael@0 4683
michael@0 4684 /* Msg = ... */
michael@0 4685 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 4686 unsigned char msg[128]; /* MAX msg 128 */
michael@0 4687 memset(hashBuf, 0, sizeof hashBuf);
michael@0 4688
michael@0 4689 if (hashType == HASH_AlgNULL) {
michael@0 4690 fprintf(dsaresp, "ERROR: Hash Alg not set");
michael@0 4691 goto loser;
michael@0 4692 }
michael@0 4693
michael@0 4694 i = 3;
michael@0 4695 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4696 i++;
michael@0 4697 }
michael@0 4698 for (j=0; isxdigit(buf[i]); i+=2,j++) {
michael@0 4699 hex_to_byteval(&buf[i], &msg[j]);
michael@0 4700 }
michael@0 4701 if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) {
michael@0 4702 fprintf(dsaresp, "ERROR: Unable to generate SHA-%d digest",
michael@0 4703 hashNum);
michael@0 4704 goto loser;
michael@0 4705 }
michael@0 4706
michael@0 4707 fputs(buf, dsaresp);
michael@0 4708 continue;
michael@0 4709 }
michael@0 4710
michael@0 4711 /* Y = ... */
michael@0 4712 if (buf[0] == 'Y') {
michael@0 4713 i = 1;
michael@0 4714 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4715 i++;
michael@0 4716 }
michael@0 4717 memset(pubkey.publicValue.data, 0, pubkey.params.subPrime.len);
michael@0 4718 for (j=0; j< pubkey.publicValue.len; i+=2,j++) {
michael@0 4719 hex_to_byteval(&buf[i], &pubkey.publicValue.data[j]);
michael@0 4720 }
michael@0 4721
michael@0 4722 fputs(buf, dsaresp);
michael@0 4723 continue;
michael@0 4724 }
michael@0 4725
michael@0 4726 /* R = ... */
michael@0 4727 if (buf[0] == 'R') {
michael@0 4728 memset(sig, 0, sizeof sig);
michael@0 4729 i = 1;
michael@0 4730 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4731 i++;
michael@0 4732 }
michael@0 4733 for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) {
michael@0 4734 hex_to_byteval(&buf[i], &sig[j]);
michael@0 4735 }
michael@0 4736
michael@0 4737 fputs(buf, dsaresp);
michael@0 4738 continue;
michael@0 4739 }
michael@0 4740
michael@0 4741 /* S = ... */
michael@0 4742 if (buf[0] == 'S') {
michael@0 4743 if (hashType == HASH_AlgNULL) {
michael@0 4744 fprintf(dsaresp, "ERROR: Hash Alg not set");
michael@0 4745 goto loser;
michael@0 4746 }
michael@0 4747
michael@0 4748 i = 1;
michael@0 4749 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4750 i++;
michael@0 4751 }
michael@0 4752 for (j=pubkey.params.subPrime.len;
michael@0 4753 j< pubkey.params.subPrime.len*2; i+=2,j++) {
michael@0 4754 hex_to_byteval(&buf[i], &sig[j]);
michael@0 4755 }
michael@0 4756 fputs(buf, dsaresp);
michael@0 4757
michael@0 4758 digest.type = siBuffer;
michael@0 4759 digest.data = hashBuf;
michael@0 4760 digest.len = fips_hashLen(hashType);
michael@0 4761 signature.type = siBuffer;
michael@0 4762 signature.data = sig;
michael@0 4763 signature.len = pubkey.params.subPrime.len*2;
michael@0 4764
michael@0 4765 if (DSA_VerifyDigest(&pubkey, &signature, &digest) == SECSuccess) {
michael@0 4766 fprintf(dsaresp, "Result = P\n");
michael@0 4767 } else {
michael@0 4768 fprintf(dsaresp, "Result = F\n");
michael@0 4769 }
michael@0 4770 fprintf(dsaresp, "\n");
michael@0 4771 continue;
michael@0 4772 }
michael@0 4773 }
michael@0 4774 loser:
michael@0 4775 fclose(dsareq);
michael@0 4776 if (pubkey.params.prime.data) { /* P */
michael@0 4777 SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE);
michael@0 4778 }
michael@0 4779 if (pubkey.params.subPrime.data) { /* Q */
michael@0 4780 SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE);
michael@0 4781 }
michael@0 4782 if (pubkey.params.base.data) { /* G */
michael@0 4783 SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE);
michael@0 4784 }
michael@0 4785 if (pubkey.publicValue.data) { /* Y */
michael@0 4786 SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE);
michael@0 4787 }
michael@0 4788 }
michael@0 4789
michael@0 4790 /*
michael@0 4791 * Perform the RSA Signature Generation Test.
michael@0 4792 *
michael@0 4793 * reqfn is the pathname of the REQUEST file.
michael@0 4794 *
michael@0 4795 * The output RESPONSE file is written to stdout.
michael@0 4796 */
michael@0 4797 void
michael@0 4798 rsa_siggen_test(char *reqfn)
michael@0 4799 {
michael@0 4800 char buf[2*RSA_MAX_TEST_MODULUS_BYTES+1];
michael@0 4801 /* buf holds one line from the input REQUEST file
michael@0 4802 * or to the output RESPONSE file.
michael@0 4803 * 2x for HEX output + 1 for \n
michael@0 4804 */
michael@0 4805 FILE *rsareq; /* input stream from the REQUEST file */
michael@0 4806 FILE *rsaresp; /* output stream to the RESPONSE file */
michael@0 4807 int i, j;
michael@0 4808 unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */
michael@0 4809 unsigned int shaLength = 0; /* length of SHA */
michael@0 4810 HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */
michael@0 4811 SECOidTag shaOid = SEC_OID_UNKNOWN;
michael@0 4812 int modulus; /* the Modulus size */
michael@0 4813 int publicExponent = DEFAULT_RSA_PUBLIC_EXPONENT;
michael@0 4814 SECItem pe = {0, 0, 0 };
michael@0 4815 unsigned char pubEx[4];
michael@0 4816 int peCount = 0;
michael@0 4817
michael@0 4818 RSAPrivateKey *rsaBlapiPrivKey = NULL; /* holds RSA private and
michael@0 4819 * public keys */
michael@0 4820 RSAPublicKey *rsaBlapiPublicKey = NULL; /* hold RSA public key */
michael@0 4821
michael@0 4822 rsareq = fopen(reqfn, "r");
michael@0 4823 rsaresp = stdout;
michael@0 4824
michael@0 4825 /* calculate the exponent */
michael@0 4826 for (i=0; i < 4; i++) {
michael@0 4827 if (peCount || (publicExponent &
michael@0 4828 ((unsigned long)0xff000000L >> (i*8)))) {
michael@0 4829 pubEx[peCount] =
michael@0 4830 (unsigned char)((publicExponent >> (3-i)*8) & 0xff);
michael@0 4831 peCount++;
michael@0 4832 }
michael@0 4833 }
michael@0 4834 pe.len = peCount;
michael@0 4835 pe.data = &pubEx[0];
michael@0 4836 pe.type = siBuffer;
michael@0 4837
michael@0 4838 while (fgets(buf, sizeof buf, rsareq) != NULL) {
michael@0 4839 /* a comment or blank line */
michael@0 4840 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 4841 fputs(buf, rsaresp);
michael@0 4842 continue;
michael@0 4843 }
michael@0 4844
michael@0 4845 /* [mod = ...] */
michael@0 4846 if (buf[0] == '[') {
michael@0 4847
michael@0 4848 if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
michael@0 4849 goto loser;
michael@0 4850 }
michael@0 4851 if (modulus > RSA_MAX_TEST_MODULUS_BITS) {
michael@0 4852 fprintf(rsaresp,"ERROR: modulus greater than test maximum\n");
michael@0 4853 goto loser;
michael@0 4854 }
michael@0 4855
michael@0 4856 fputs(buf, rsaresp);
michael@0 4857
michael@0 4858 if (rsaBlapiPrivKey != NULL) {
michael@0 4859 PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE);
michael@0 4860 rsaBlapiPrivKey = NULL;
michael@0 4861 rsaBlapiPublicKey = NULL;
michael@0 4862 }
michael@0 4863
michael@0 4864 rsaBlapiPrivKey = RSA_NewKey(modulus, &pe);
michael@0 4865 if (rsaBlapiPrivKey == NULL) {
michael@0 4866 fprintf(rsaresp, "Error unable to create RSA key\n");
michael@0 4867 goto loser;
michael@0 4868 }
michael@0 4869
michael@0 4870 to_hex_str(buf, rsaBlapiPrivKey->modulus.data,
michael@0 4871 rsaBlapiPrivKey->modulus.len);
michael@0 4872 fprintf(rsaresp, "\nn = %s\n\n", buf);
michael@0 4873 to_hex_str(buf, rsaBlapiPrivKey->publicExponent.data,
michael@0 4874 rsaBlapiPrivKey->publicExponent.len);
michael@0 4875 fprintf(rsaresp, "e = %s\n", buf);
michael@0 4876 /* convert private key to public key. Memory
michael@0 4877 * is freed with private key's arena */
michael@0 4878 rsaBlapiPublicKey = (RSAPublicKey *)PORT_ArenaAlloc(
michael@0 4879 rsaBlapiPrivKey->arena,
michael@0 4880 sizeof(RSAPublicKey));
michael@0 4881
michael@0 4882 rsaBlapiPublicKey->modulus.len = rsaBlapiPrivKey->modulus.len;
michael@0 4883 rsaBlapiPublicKey->modulus.data = rsaBlapiPrivKey->modulus.data;
michael@0 4884 rsaBlapiPublicKey->publicExponent.len =
michael@0 4885 rsaBlapiPrivKey->publicExponent.len;
michael@0 4886 rsaBlapiPublicKey->publicExponent.data =
michael@0 4887 rsaBlapiPrivKey->publicExponent.data;
michael@0 4888 continue;
michael@0 4889 }
michael@0 4890
michael@0 4891 /* SHAAlg = ... */
michael@0 4892 if (strncmp(buf, "SHAAlg", 6) == 0) {
michael@0 4893 i = 6;
michael@0 4894 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4895 i++;
michael@0 4896 }
michael@0 4897 /* set the SHA Algorithm */
michael@0 4898 if (strncmp(&buf[i], "SHA1", 4) == 0) {
michael@0 4899 shaAlg = HASH_AlgSHA1;
michael@0 4900 } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
michael@0 4901 shaAlg = HASH_AlgSHA224;
michael@0 4902 } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
michael@0 4903 shaAlg = HASH_AlgSHA256;
michael@0 4904 } else if (strncmp(&buf[i], "SHA384", 6)== 0) {
michael@0 4905 shaAlg = HASH_AlgSHA384;
michael@0 4906 } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
michael@0 4907 shaAlg = HASH_AlgSHA512;
michael@0 4908 } else {
michael@0 4909 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
michael@0 4910 goto loser;
michael@0 4911 }
michael@0 4912 fputs(buf, rsaresp);
michael@0 4913 continue;
michael@0 4914
michael@0 4915 }
michael@0 4916 /* Msg = ... */
michael@0 4917 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 4918
michael@0 4919 unsigned char msg[128]; /* MAX msg 128 */
michael@0 4920 unsigned int rsa_bytes_signed;
michael@0 4921 unsigned char rsa_computed_signature[RSA_MAX_TEST_MODULUS_BYTES];
michael@0 4922 SECStatus rv = SECFailure;
michael@0 4923 NSSLOWKEYPublicKey * rsa_public_key;
michael@0 4924 NSSLOWKEYPrivateKey * rsa_private_key;
michael@0 4925 NSSLOWKEYPrivateKey low_RSA_private_key = { NULL,
michael@0 4926 NSSLOWKEYRSAKey, };
michael@0 4927 NSSLOWKEYPublicKey low_RSA_public_key = { NULL,
michael@0 4928 NSSLOWKEYRSAKey, };
michael@0 4929
michael@0 4930 low_RSA_private_key.u.rsa = *rsaBlapiPrivKey;
michael@0 4931 low_RSA_public_key.u.rsa = *rsaBlapiPublicKey;
michael@0 4932
michael@0 4933 rsa_private_key = &low_RSA_private_key;
michael@0 4934 rsa_public_key = &low_RSA_public_key;
michael@0 4935
michael@0 4936 memset(sha, 0, sizeof sha);
michael@0 4937 memset(msg, 0, sizeof msg);
michael@0 4938 rsa_bytes_signed = 0;
michael@0 4939 memset(rsa_computed_signature, 0, sizeof rsa_computed_signature);
michael@0 4940
michael@0 4941 i = 3;
michael@0 4942 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 4943 i++;
michael@0 4944 }
michael@0 4945 for (j=0; isxdigit(buf[i]) && j < sizeof(msg); i+=2,j++) {
michael@0 4946 hex_to_byteval(&buf[i], &msg[j]);
michael@0 4947 }
michael@0 4948 shaLength = fips_hashLen(shaAlg);
michael@0 4949 if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) {
michael@0 4950 if (shaLength == 0) {
michael@0 4951 fprintf(rsaresp, "ERROR: SHAAlg not defined.");
michael@0 4952 }
michael@0 4953 fprintf(rsaresp, "ERROR: Unable to generate SHA%x",
michael@0 4954 shaLength == 160 ? 1 : shaLength);
michael@0 4955 goto loser;
michael@0 4956 }
michael@0 4957 shaOid = fips_hashOid(shaAlg);
michael@0 4958
michael@0 4959 /* Perform RSA signature with the RSA private key. */
michael@0 4960 rv = RSA_HashSign( shaOid,
michael@0 4961 rsa_private_key,
michael@0 4962 rsa_computed_signature,
michael@0 4963 &rsa_bytes_signed,
michael@0 4964 nsslowkey_PrivateModulusLen(rsa_private_key),
michael@0 4965 sha,
michael@0 4966 shaLength);
michael@0 4967
michael@0 4968 if( rv != SECSuccess ) {
michael@0 4969 fprintf(rsaresp, "ERROR: RSA_HashSign failed");
michael@0 4970 goto loser;
michael@0 4971 }
michael@0 4972
michael@0 4973 /* Output the signature */
michael@0 4974 fputs(buf, rsaresp);
michael@0 4975 to_hex_str(buf, rsa_computed_signature, rsa_bytes_signed);
michael@0 4976 fprintf(rsaresp, "S = %s\n", buf);
michael@0 4977
michael@0 4978 /* Perform RSA verification with the RSA public key. */
michael@0 4979 rv = RSA_HashCheckSign( shaOid,
michael@0 4980 rsa_public_key,
michael@0 4981 rsa_computed_signature,
michael@0 4982 rsa_bytes_signed,
michael@0 4983 sha,
michael@0 4984 shaLength);
michael@0 4985 if( rv != SECSuccess ) {
michael@0 4986 fprintf(rsaresp, "ERROR: RSA_HashCheckSign failed");
michael@0 4987 goto loser;
michael@0 4988 }
michael@0 4989 continue;
michael@0 4990 }
michael@0 4991 }
michael@0 4992 loser:
michael@0 4993 fclose(rsareq);
michael@0 4994
michael@0 4995 if (rsaBlapiPrivKey != NULL) {
michael@0 4996 /* frees private and public key */
michael@0 4997 PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE);
michael@0 4998 rsaBlapiPrivKey = NULL;
michael@0 4999 rsaBlapiPublicKey = NULL;
michael@0 5000 }
michael@0 5001
michael@0 5002 }
michael@0 5003 /*
michael@0 5004 * Perform the RSA Signature Verification Test.
michael@0 5005 *
michael@0 5006 * reqfn is the pathname of the REQUEST file.
michael@0 5007 *
michael@0 5008 * The output RESPONSE file is written to stdout.
michael@0 5009 */
michael@0 5010 void
michael@0 5011 rsa_sigver_test(char *reqfn)
michael@0 5012 {
michael@0 5013 char buf[2*RSA_MAX_TEST_MODULUS_BYTES+7];
michael@0 5014 /* buf holds one line from the input REQUEST file
michael@0 5015 * or to the output RESPONSE file.
michael@0 5016 * s = 2x for HEX output + 1 for \n
michael@0 5017 */
michael@0 5018 FILE *rsareq; /* input stream from the REQUEST file */
michael@0 5019 FILE *rsaresp; /* output stream to the RESPONSE file */
michael@0 5020 int i, j;
michael@0 5021 unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */
michael@0 5022 unsigned int shaLength = 0; /* actual length of the digest */
michael@0 5023 HASH_HashType shaAlg = HASH_AlgNULL;
michael@0 5024 SECOidTag shaOid = SEC_OID_UNKNOWN;
michael@0 5025 int modulus = 0; /* the Modulus size */
michael@0 5026 unsigned char signature[513]; /* largest signature size + '\n' */
michael@0 5027 unsigned int signatureLength = 0; /* actual length of the signature */
michael@0 5028 PRBool keyvalid = PR_TRUE;
michael@0 5029
michael@0 5030 RSAPublicKey rsaBlapiPublicKey; /* hold RSA public key */
michael@0 5031
michael@0 5032 rsareq = fopen(reqfn, "r");
michael@0 5033 rsaresp = stdout;
michael@0 5034 memset(&rsaBlapiPublicKey, 0, sizeof(RSAPublicKey));
michael@0 5035
michael@0 5036 while (fgets(buf, sizeof buf, rsareq) != NULL) {
michael@0 5037 /* a comment or blank line */
michael@0 5038 if (buf[0] == '#' || buf[0] == '\n') {
michael@0 5039 fputs(buf, rsaresp);
michael@0 5040 continue;
michael@0 5041 }
michael@0 5042
michael@0 5043 /* [Mod = ...] */
michael@0 5044 if (buf[0] == '[') {
michael@0 5045 unsigned int flen; /* length in bytes of the field size */
michael@0 5046
michael@0 5047 if (rsaBlapiPublicKey.modulus.data) { /* n */
michael@0 5048 SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE);
michael@0 5049 }
michael@0 5050 if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
michael@0 5051 goto loser;
michael@0 5052 }
michael@0 5053
michael@0 5054 if (modulus > RSA_MAX_TEST_MODULUS_BITS) {
michael@0 5055 fprintf(rsaresp,"ERROR: modulus greater than test maximum\n");
michael@0 5056 goto loser;
michael@0 5057 }
michael@0 5058
michael@0 5059 fputs(buf, rsaresp);
michael@0 5060
michael@0 5061 signatureLength = flen = modulus/8;
michael@0 5062
michael@0 5063 SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.modulus, flen);
michael@0 5064 if (rsaBlapiPublicKey.modulus.data == NULL) {
michael@0 5065 goto loser;
michael@0 5066 }
michael@0 5067 continue;
michael@0 5068 }
michael@0 5069
michael@0 5070 /* n = ... modulus */
michael@0 5071 if (buf[0] == 'n') {
michael@0 5072 i = 1;
michael@0 5073 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 5074 i++;
michael@0 5075 }
michael@0 5076 keyvalid = from_hex_str(&rsaBlapiPublicKey.modulus.data[0],
michael@0 5077 rsaBlapiPublicKey.modulus.len,
michael@0 5078 &buf[i]);
michael@0 5079
michael@0 5080 if (!keyvalid) {
michael@0 5081 fprintf(rsaresp, "ERROR: rsa_sigver n not valid.\n");
michael@0 5082 goto loser;
michael@0 5083 }
michael@0 5084 fputs(buf, rsaresp);
michael@0 5085 continue;
michael@0 5086 }
michael@0 5087
michael@0 5088 /* SHAAlg = ... */
michael@0 5089 if (strncmp(buf, "SHAAlg", 6) == 0) {
michael@0 5090 i = 6;
michael@0 5091 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 5092 i++;
michael@0 5093 }
michael@0 5094 /* set the SHA Algorithm */
michael@0 5095 if (strncmp(&buf[i], "SHA1", 4) == 0) {
michael@0 5096 shaAlg = HASH_AlgSHA1;
michael@0 5097 } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
michael@0 5098 shaAlg = HASH_AlgSHA224;
michael@0 5099 } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
michael@0 5100 shaAlg = HASH_AlgSHA256;
michael@0 5101 } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
michael@0 5102 shaAlg = HASH_AlgSHA384;
michael@0 5103 } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
michael@0 5104 shaAlg = HASH_AlgSHA512;
michael@0 5105 } else {
michael@0 5106 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
michael@0 5107 goto loser;
michael@0 5108 }
michael@0 5109 fputs(buf, rsaresp);
michael@0 5110 continue;
michael@0 5111 }
michael@0 5112
michael@0 5113 /* e = ... public Key */
michael@0 5114 if (buf[0] == 'e') {
michael@0 5115 unsigned char data[RSA_MAX_TEST_EXPONENT_BYTES];
michael@0 5116 unsigned char t;
michael@0 5117
michael@0 5118 memset(data, 0, sizeof data);
michael@0 5119
michael@0 5120 if (rsaBlapiPublicKey.publicExponent.data) { /* e */
michael@0 5121 SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE);
michael@0 5122 }
michael@0 5123
michael@0 5124 i = 1;
michael@0 5125 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 5126 i++;
michael@0 5127 }
michael@0 5128 /* skip leading zero's */
michael@0 5129 while (isxdigit(buf[i])) {
michael@0 5130 hex_to_byteval(&buf[i], &t);
michael@0 5131 if (t == 0) {
michael@0 5132 i+=2;
michael@0 5133 } else break;
michael@0 5134 }
michael@0 5135
michael@0 5136 /* get the exponent */
michael@0 5137 for (j=0; isxdigit(buf[i]) && j < sizeof data; i+=2,j++) {
michael@0 5138 hex_to_byteval(&buf[i], &data[j]);
michael@0 5139 }
michael@0 5140
michael@0 5141 if (j == 0) { j = 1; } /* to handle 1 byte length exponents */
michael@0 5142
michael@0 5143 SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.publicExponent, j);
michael@0 5144 if (rsaBlapiPublicKey.publicExponent.data == NULL) {
michael@0 5145 goto loser;
michael@0 5146 }
michael@0 5147
michael@0 5148 for (i=0; i < j; i++) {
michael@0 5149 rsaBlapiPublicKey.publicExponent.data[i] = data[i];
michael@0 5150 }
michael@0 5151
michael@0 5152 fputs(buf, rsaresp);
michael@0 5153 continue;
michael@0 5154 }
michael@0 5155
michael@0 5156 /* Msg = ... */
michael@0 5157 if (strncmp(buf, "Msg", 3) == 0) {
michael@0 5158 unsigned char msg[128]; /* MAX msg 128 */
michael@0 5159
michael@0 5160 memset(sha, 0, sizeof sha);
michael@0 5161 memset(msg, 0, sizeof msg);
michael@0 5162
michael@0 5163 i = 3;
michael@0 5164 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 5165 i++;
michael@0 5166 }
michael@0 5167
michael@0 5168 for (j=0; isxdigit(buf[i]) && j < sizeof msg; i+=2,j++) {
michael@0 5169 hex_to_byteval(&buf[i], &msg[j]);
michael@0 5170 }
michael@0 5171
michael@0 5172 shaLength = fips_hashLen(shaAlg);
michael@0 5173 if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) {
michael@0 5174 if (shaLength == 0) {
michael@0 5175 fprintf(rsaresp, "ERROR: SHAAlg not defined.");
michael@0 5176 }
michael@0 5177 fprintf(rsaresp, "ERROR: Unable to generate SHA%x",
michael@0 5178 shaLength == 160 ? 1 : shaLength);
michael@0 5179 goto loser;
michael@0 5180 }
michael@0 5181
michael@0 5182 fputs(buf, rsaresp);
michael@0 5183 continue;
michael@0 5184
michael@0 5185 }
michael@0 5186
michael@0 5187 /* S = ... */
michael@0 5188 if (buf[0] == 'S') {
michael@0 5189 SECStatus rv = SECFailure;
michael@0 5190 NSSLOWKEYPublicKey * rsa_public_key;
michael@0 5191 NSSLOWKEYPublicKey low_RSA_public_key = { NULL,
michael@0 5192 NSSLOWKEYRSAKey, };
michael@0 5193
michael@0 5194 /* convert to a low RSA public key */
michael@0 5195 low_RSA_public_key.u.rsa = rsaBlapiPublicKey;
michael@0 5196 rsa_public_key = &low_RSA_public_key;
michael@0 5197
michael@0 5198 memset(signature, 0, sizeof(signature));
michael@0 5199 i = 1;
michael@0 5200 while (isspace(buf[i]) || buf[i] == '=') {
michael@0 5201 i++;
michael@0 5202 }
michael@0 5203
michael@0 5204 for (j=0; isxdigit(buf[i]) && j < sizeof signature; i+=2,j++) {
michael@0 5205 hex_to_byteval(&buf[i], &signature[j]);
michael@0 5206 }
michael@0 5207
michael@0 5208 signatureLength = j;
michael@0 5209 fputs(buf, rsaresp);
michael@0 5210
michael@0 5211 /* Perform RSA verification with the RSA public key. */
michael@0 5212 rv = RSA_HashCheckSign( shaOid,
michael@0 5213 rsa_public_key,
michael@0 5214 signature,
michael@0 5215 signatureLength,
michael@0 5216 sha,
michael@0 5217 shaLength);
michael@0 5218 if( rv == SECSuccess ) {
michael@0 5219 fputs("Result = P\n", rsaresp);
michael@0 5220 } else {
michael@0 5221 fputs("Result = F\n", rsaresp);
michael@0 5222 }
michael@0 5223 continue;
michael@0 5224 }
michael@0 5225 }
michael@0 5226 loser:
michael@0 5227 fclose(rsareq);
michael@0 5228 if (rsaBlapiPublicKey.modulus.data) { /* n */
michael@0 5229 SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE);
michael@0 5230 }
michael@0 5231 if (rsaBlapiPublicKey.publicExponent.data) { /* e */
michael@0 5232 SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE);
michael@0 5233 }
michael@0 5234 }
michael@0 5235
michael@0 5236 int main(int argc, char **argv)
michael@0 5237 {
michael@0 5238 if (argc < 2) exit (-1);
michael@0 5239
michael@0 5240 RNG_RNGInit();
michael@0 5241 SECOID_Init();
michael@0 5242
michael@0 5243 /*************/
michael@0 5244 /* TDEA */
michael@0 5245 /*************/
michael@0 5246 if (strcmp(argv[1], "tdea") == 0) {
michael@0 5247 /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
michael@0 5248 if (strcmp(argv[2], "kat") == 0) {
michael@0 5249 /* Known Answer Test (KAT) */
michael@0 5250 tdea_kat_mmt(argv[4]);
michael@0 5251 } else if (strcmp(argv[2], "mmt") == 0) {
michael@0 5252 /* Multi-block Message Test (MMT) */
michael@0 5253 tdea_kat_mmt(argv[4]);
michael@0 5254 } else if (strcmp(argv[2], "mct") == 0) {
michael@0 5255 /* Monte Carlo Test (MCT) */
michael@0 5256 if (strcmp(argv[3], "ecb") == 0) {
michael@0 5257 /* ECB mode */
michael@0 5258 tdea_mct(NSS_DES_EDE3, argv[4]);
michael@0 5259 } else if (strcmp(argv[3], "cbc") == 0) {
michael@0 5260 /* CBC mode */
michael@0 5261 tdea_mct(NSS_DES_EDE3_CBC, argv[4]);
michael@0 5262 }
michael@0 5263 }
michael@0 5264 /*************/
michael@0 5265 /* AES */
michael@0 5266 /*************/
michael@0 5267 } else if (strcmp(argv[1], "aes") == 0) {
michael@0 5268 /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
michael@0 5269 if ( strcmp(argv[2], "kat") == 0) {
michael@0 5270 /* Known Answer Test (KAT) */
michael@0 5271 aes_kat_mmt(argv[4]);
michael@0 5272 } else if (strcmp(argv[2], "mmt") == 0) {
michael@0 5273 /* Multi-block Message Test (MMT) */
michael@0 5274 aes_kat_mmt(argv[4]);
michael@0 5275 } else if (strcmp(argv[2], "mct") == 0) {
michael@0 5276 /* Monte Carlo Test (MCT) */
michael@0 5277 if ( strcmp(argv[3], "ecb") == 0) {
michael@0 5278 /* ECB mode */
michael@0 5279 aes_ecb_mct(argv[4]);
michael@0 5280 } else if (strcmp(argv[3], "cbc") == 0) {
michael@0 5281 /* CBC mode */
michael@0 5282 aes_cbc_mct(argv[4]);
michael@0 5283 }
michael@0 5284 }
michael@0 5285 /*************/
michael@0 5286 /* SHA */
michael@0 5287 /*************/
michael@0 5288 } else if (strcmp(argv[1], "sha") == 0) {
michael@0 5289 sha_test(argv[2]);
michael@0 5290 /*************/
michael@0 5291 /* RSA */
michael@0 5292 /*************/
michael@0 5293 } else if (strcmp(argv[1], "rsa") == 0) {
michael@0 5294 /* argv[2]=siggen|sigver */
michael@0 5295 /* argv[3]=<test name>.req */
michael@0 5296 if (strcmp(argv[2], "siggen") == 0) {
michael@0 5297 /* Signature Generation Test */
michael@0 5298 rsa_siggen_test(argv[3]);
michael@0 5299 } else if (strcmp(argv[2], "sigver") == 0) {
michael@0 5300 /* Signature Verification Test */
michael@0 5301 rsa_sigver_test(argv[3]);
michael@0 5302 }
michael@0 5303 /*************/
michael@0 5304 /* HMAC */
michael@0 5305 /*************/
michael@0 5306 } else if (strcmp(argv[1], "hmac") == 0) {
michael@0 5307 hmac_test(argv[2]);
michael@0 5308 /*************/
michael@0 5309 /* DSA */
michael@0 5310 /*************/
michael@0 5311 } else if (strcmp(argv[1], "dsa") == 0) {
michael@0 5312 /* argv[2]=keypair|pqggen|pqgver|siggen|sigver */
michael@0 5313 /* argv[3]=<test name>.req */
michael@0 5314 if (strcmp(argv[2], "keypair") == 0) {
michael@0 5315 /* Key Pair Generation Test */
michael@0 5316 dsa_keypair_test(argv[3]);
michael@0 5317 } else if (strcmp(argv[2], "pqggen") == 0) {
michael@0 5318 /* Domain Parameter Generation Test */
michael@0 5319 dsa_pqggen_test(argv[3]);
michael@0 5320 } else if (strcmp(argv[2], "pqgver") == 0) {
michael@0 5321 /* Domain Parameter Validation Test */
michael@0 5322 dsa_pqgver_test(argv[3]);
michael@0 5323 } else if (strcmp(argv[2], "siggen") == 0) {
michael@0 5324 /* Signature Generation Test */
michael@0 5325 dsa_siggen_test(argv[3]);
michael@0 5326 } else if (strcmp(argv[2], "sigver") == 0) {
michael@0 5327 /* Signature Verification Test */
michael@0 5328 dsa_sigver_test(argv[3]);
michael@0 5329 }
michael@0 5330 #ifndef NSS_DISABLE_ECC
michael@0 5331 /*************/
michael@0 5332 /* ECDSA */
michael@0 5333 /*************/
michael@0 5334 } else if (strcmp(argv[1], "ecdsa") == 0) {
michael@0 5335 /* argv[2]=keypair|pkv|siggen|sigver argv[3]=<test name>.req */
michael@0 5336 if ( strcmp(argv[2], "keypair") == 0) {
michael@0 5337 /* Key Pair Generation Test */
michael@0 5338 ecdsa_keypair_test(argv[3]);
michael@0 5339 } else if (strcmp(argv[2], "pkv") == 0) {
michael@0 5340 /* Public Key Validation Test */
michael@0 5341 ecdsa_pkv_test(argv[3]);
michael@0 5342 } else if (strcmp(argv[2], "siggen") == 0) {
michael@0 5343 /* Signature Generation Test */
michael@0 5344 ecdsa_siggen_test(argv[3]);
michael@0 5345 } else if (strcmp(argv[2], "sigver") == 0) {
michael@0 5346 /* Signature Verification Test */
michael@0 5347 ecdsa_sigver_test(argv[3]);
michael@0 5348 }
michael@0 5349 #endif /* NSS_DISABLE_ECC */
michael@0 5350 /*************/
michael@0 5351 /* RNG */
michael@0 5352 /*************/
michael@0 5353 } else if (strcmp(argv[1], "rng") == 0) {
michael@0 5354 /* argv[2]=vst|mct argv[3]=<test name>.req */
michael@0 5355 if ( strcmp(argv[2], "vst") == 0) {
michael@0 5356 /* Variable Seed Test */
michael@0 5357 rng_vst(argv[3]);
michael@0 5358 } else if (strcmp(argv[2], "mct") == 0) {
michael@0 5359 /* Monte Carlo Test */
michael@0 5360 rng_mct(argv[3]);
michael@0 5361 }
michael@0 5362 } else if (strcmp(argv[1], "drbg") == 0) {
michael@0 5363 /* Variable Seed Test */
michael@0 5364 drbg(argv[2]);
michael@0 5365 } else if (strcmp(argv[1], "ddrbg") == 0) {
michael@0 5366 debug = 1;
michael@0 5367 drbg(argv[2]);
michael@0 5368 }
michael@0 5369 return 0;
michael@0 5370 }

mercurial