text: /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <ctype.h>
  
  #include "secitem.h"
  #include "blapi.h"
  #include "nssutil.h"
  #include "secerr.h"
  #include "secder.h"
  #include "secdig.h"
  #include "secoid.h"
  #include "ec.h"
  #include "hasht.h"
  #include "lowkeyi.h"
  #include "softoken.h"
  
  #if 0
  #include "../../lib/freebl/mpi/mpi.h"
  #endif
  
  #ifndef NSS_DISABLE_ECC
  extern SECStatus
  EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
  extern SECStatus
  EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
                const ECParams *srcParams);
  #endif
  
  #define ENCRYPT 1
  #define DECRYPT 0
  #define BYTE unsigned char
  #define DEFAULT_RSA_PUBLIC_EXPONENT   0x10001
  #define RSA_MAX_TEST_MODULUS_BITS     4096
  #define RSA_MAX_TEST_MODULUS_BYTES    RSA_MAX_TEST_MODULUS_BITS/8
  #define RSA_MAX_TEST_EXPONENT_BYTES   8
  #define PQG_TEST_SEED_BYTES           20
  
  SECStatus
  hex_to_byteval(const char *c2, unsigned char *byteval)
  {
      int i;
      unsigned char offset;
      *byteval = 0;
      for (i=0; i<2; i++) {
  	if (c2[i] >= '0' && c2[i] <= '9') {
  	    offset = c2[i] - '0';
  	    *byteval |= offset << 4*(1-i);
  	} else if (c2[i] >= 'a' && c2[i] <= 'f') {
  	    offset = c2[i] - 'a';
  	    *byteval |= (offset + 10) << 4*(1-i);
  	} else if (c2[i] >= 'A' && c2[i] <= 'F') {
  	    offset = c2[i] - 'A';
  	    *byteval |= (offset + 10) << 4*(1-i);
  	} else {
  	    return SECFailure;
  	}
      }
      return SECSuccess;
  }
  
  SECStatus
  byteval_to_hex(unsigned char byteval, char *c2, char a)
  {
      int i;
      unsigned char offset;
      for (i=0; i<2; i++) {
  	offset = (byteval >> 4*(1-i)) & 0x0f;
  	if (offset < 10) {
  	    c2[i] = '0' + offset;
  	} else {
  	    c2[i] = a + offset - 10;
  	}
      }
      return SECSuccess;
  }
  
  void
  to_hex_str(char *str, const unsigned char *buf, unsigned int len)
  {
      unsigned int i;
      for (i=0; i<len; i++) {
  	byteval_to_hex(buf[i], &str[2*i], 'a');
      }
      str[2*len] = '\0';
  }
  
  void
  to_hex_str_cap(char *str, const unsigned char *buf, unsigned int len)
  {
      unsigned int i;
      for (i=0; i<len; i++) {
  	byteval_to_hex(buf[i], &str[2*i], 'A');
      }
      str[2*len] = '\0';
  }
  
  /*
   * Convert a string of hex digits (str) to an array (buf) of len bytes.
   * Return PR_TRUE if the hex string can fit in the byte array.  Return
   * PR_FALSE if the hex string is empty or is too long.
   */
  PRBool
  from_hex_str(unsigned char *buf, unsigned int len, const char *str)
  {
      unsigned int nxdigit;  /* number of hex digits in str */
      unsigned int i;  /* index into buf */
      unsigned int j;  /* index into str */
  
      /* count the hex digits */
      nxdigit = 0;
      for (nxdigit = 0; isxdigit(str[nxdigit]); nxdigit++) {
  	/* empty body */
      }
      if (nxdigit == 0) {
  	return PR_FALSE;
      }
      if (nxdigit > 2*len) {
  	/*
  	 * The input hex string is too long, but we allow it if the
  	 * extra digits are leading 0's.
  	 */
  	for (j = 0; j < nxdigit-2*len; j++) {
  	    if (str[j] != '0') {
  		return PR_FALSE;
  	    }
  	}
  	/* skip leading 0's */
  	str += nxdigit-2*len;
  	nxdigit = 2*len;
      }
      for (i=0, j=0; i< len; i++) {
  	if (2*i < 2*len-nxdigit) {
  	    /* Handle a short input as if we padded it with leading 0's. */
  	    if (2*i+1 < 2*len-nxdigit) {
  		buf[i] = 0;
  	    } else {
  		char tmp[2];
  		tmp[0] = '0';
  		tmp[1] = str[j];
  		hex_to_byteval(tmp, &buf[i]);
  		j++;
  	    }
  	} else {
  	    hex_to_byteval(&str[j], &buf[i]);
  	    j += 2;
  	}
      }
      return PR_TRUE;
  }
  
  SECStatus
  tdea_encrypt_buf(
      int mode,
      const unsigned char *key, 
      const unsigned char *iv,
      unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
      const unsigned char *input, unsigned int inputlen)
  {
      SECStatus rv = SECFailure;
      DESContext *cx;
      unsigned char doublecheck[8*20];  /* 1 to 20 blocks */
      unsigned int doublechecklen = 0;
  
      cx = DES_CreateContext(key, iv, mode, PR_TRUE);
      if (cx == NULL) {
          goto loser;
      }
      rv = DES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
      if (rv != SECSuccess) {
          goto loser;
      }
      if (*outputlen != inputlen) {
          goto loser;
      }
      DES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
  
      /*
       * Doublecheck our result by decrypting the ciphertext and
       * compare the output with the input plaintext.
       */
      cx = DES_CreateContext(key, iv, mode, PR_FALSE);
      if (cx == NULL) {
          goto loser;
      }
      rv = DES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
                      output, *outputlen);
      if (rv != SECSuccess) {
          goto loser;
      }
      if (doublechecklen != *outputlen) {
          goto loser;
      }
      DES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
      if (memcmp(doublecheck, input, inputlen) != 0) {
          goto loser;
      }
      rv = SECSuccess;
  
  loser:
      if (cx != NULL) {
          DES_DestroyContext(cx, PR_TRUE);
      }
      return rv;
  }
  
  SECStatus
  tdea_decrypt_buf(
      int mode,
      const unsigned char *key, 
      const unsigned char *iv,
      unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
      const unsigned char *input, unsigned int inputlen)
  {
      SECStatus rv = SECFailure;
      DESContext *cx;
      unsigned char doublecheck[8*20];  /* 1 to 20 blocks */
      unsigned int doublechecklen = 0;
  
      cx = DES_CreateContext(key, iv, mode, PR_FALSE);
      if (cx == NULL) {
          goto loser;
      }
      rv = DES_Decrypt(cx, output, outputlen, maxoutputlen,
                      input, inputlen);
      if (rv != SECSuccess) {
          goto loser;
      }
      if (*outputlen != inputlen) {
          goto loser;
      }
      DES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
  
      /*
       * Doublecheck our result by encrypting the plaintext and
       * compare the output with the input ciphertext.
       */
      cx = DES_CreateContext(key, iv, mode, PR_TRUE);
      if (cx == NULL) {
          goto loser;
      }
      rv = DES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
          output, *outputlen);
      if (rv != SECSuccess) {
          goto loser;
      }
      if (doublechecklen != *outputlen) {
          goto loser;
      }
      DES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
      if (memcmp(doublecheck, input, inputlen) != 0) {
          goto loser;
      }
      rv = SECSuccess;
  
  loser:
      if (cx != NULL) {
          DES_DestroyContext(cx, PR_TRUE);
      }
      return rv;
  }
  
  /*
   * Perform the TDEA Known Answer Test (KAT) or Multi-block Message
   * Test (MMT) in ECB or CBC mode.  The KAT (there are five types)
   * and MMT have the same structure: given the key and IV (CBC mode
   * only), encrypt the given plaintext or decrypt the given ciphertext.
   * So we can handle them the same way.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  tdea_kat_mmt(char *reqfn)
  {
      char buf[180];      /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "CIPHERTEXT = <180 hex digits>\n".
                           */
      FILE *req;       /* input stream from the REQUEST file */
      FILE *resp;      /* output stream to the RESPONSE file */
      int i, j;
      int mode;           /* NSS_DES_EDE3 (ECB) or NSS_DES_EDE3_CBC */
      int crypt = DECRYPT;    /* 1 means encrypt, 0 means decrypt */
      unsigned char key[24];              /* TDEA 3 key bundle */
      unsigned int numKeys = 0;
      unsigned char iv[8];		/* for all modes except ECB */
      unsigned char plaintext[8*20];     /* 1 to 20 blocks */
      unsigned int plaintextlen;
      unsigned char ciphertext[8*20];   /* 1 to 20 blocks */  
      unsigned int ciphertextlen;
      SECStatus rv;
  
      req = fopen(reqfn, "r");
      resp = stdout;
      while (fgets(buf, sizeof buf, req) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, resp);
              continue;
          }
          /* [ENCRYPT] or [DECRYPT] */
          if (buf[0] == '[') {
              if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
                  crypt = ENCRYPT;
              } else {
                  crypt = DECRYPT;
              }
              fputs(buf, resp);
              continue;
          }
          /* NumKeys */
          if (strncmp(&buf[0], "NumKeys", 7) == 0) {
              i = 7;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              numKeys = buf[i];
              fputs(buf, resp);
              continue;
          }
          /* "COUNT = x" begins a new data set */
          if (strncmp(buf, "COUNT", 5) == 0) {
              /* mode defaults to ECB, if dataset has IV mode will be set CBC */
              mode = NSS_DES_EDE3;
              /* zeroize the variables for the test with this data set */
              memset(key, 0, sizeof key);
              memset(iv, 0, sizeof iv);
              memset(plaintext, 0, sizeof plaintext);
              plaintextlen = 0;
              memset(ciphertext, 0, sizeof ciphertext);
              ciphertextlen = 0;
              fputs(buf, resp);
              continue;
          }
          if (numKeys == 0) {
              if (strncmp(buf, "KEYs", 4) == 0) {
                  i = 4;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=0; isxdigit(buf[i]); i+=2,j++) {
                      hex_to_byteval(&buf[i], &key[j]);
                      key[j+8] = key[j];
                      key[j+16] = key[j];
                  }
                  fputs(buf, resp);
                  continue;
              }
          } else {
              /* KEY1 = ... */
              if (strncmp(buf, "KEY1", 4) == 0) {
                  i = 4;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=0; isxdigit(buf[i]); i+=2,j++) {
                      hex_to_byteval(&buf[i], &key[j]);
                  }
                  fputs(buf, resp);
                  continue;
              }
              /* KEY2 = ... */
              if (strncmp(buf, "KEY2", 4) == 0) {
                  i = 4;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=8; isxdigit(buf[i]); i+=2,j++) {
                      hex_to_byteval(&buf[i], &key[j]);
                  }
                  fputs(buf, resp);
                  continue;
              }
              /* KEY3 = ... */
              if (strncmp(buf, "KEY3", 4) == 0) {
                  i = 4;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=16; isxdigit(buf[i]); i+=2,j++) {
                      hex_to_byteval(&buf[i], &key[j]);
                  }
                  fputs(buf, resp);
                  continue;
              }
          }
  
          /* IV = ... */
          if (strncmp(buf, "IV", 2) == 0) {
              mode = NSS_DES_EDE3_CBC;
              i = 2;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j<sizeof iv; i+=2,j++) {
                  hex_to_byteval(&buf[i], &iv[j]);
              }
              fputs(buf, resp);
              continue;
          }
  
          /* PLAINTEXT = ... */
          if (strncmp(buf, "PLAINTEXT", 9) == 0) {
              /* sanity check */
              if (crypt != ENCRYPT) {
                  goto loser;
              }
              i = 9;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &plaintext[j]);
              }
              plaintextlen = j;
              rv = tdea_encrypt_buf(mode, key,
                              (mode == NSS_DES_EDE3) ? NULL : iv,
                              ciphertext, &ciphertextlen, sizeof ciphertext,
                              plaintext, plaintextlen);
              if (rv != SECSuccess) {
                  goto loser;
              }
      
              fputs(buf, resp);
              fputs("CIPHERTEXT = ", resp);
              to_hex_str(buf, ciphertext, ciphertextlen);
              fputs(buf, resp);
              fputc('\n', resp);
              continue;
          }
          /* CIPHERTEXT = ... */
          if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
              /* sanity check */
              if (crypt != DECRYPT) {
                  goto loser;
              }
   
              i = 10;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &ciphertext[j]);
              }
              ciphertextlen = j;
   
              rv = tdea_decrypt_buf(mode, key,
                              (mode == NSS_DES_EDE3) ? NULL : iv,
                              plaintext, &plaintextlen, sizeof plaintext,
                              ciphertext, ciphertextlen);
              if (rv != SECSuccess) {
                  goto loser;
              }
   
              fputs(buf, resp);
              fputs("PLAINTEXT = ", resp);
              to_hex_str(buf, plaintext, plaintextlen);
              fputs(buf, resp);
              fputc('\n', resp);
              continue;
          }
      }
  
  loser:
      fclose(req);
  }
  
  /*
  * Set the parity bit for the given byte
  */
  BYTE odd_parity( BYTE in)
  {
      BYTE out = in;
      in ^= in >> 4;
      in ^= in >> 2;
      in ^= in >> 1;
      return (BYTE)(out ^ !(in & 1));
  }
  
  /*
   * Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j] 
   * for TDEA Monte Carlo Test (MCT) in ECB and CBC modes.
   */
  void
  tdea_mct_next_keys(unsigned char *key,
      const unsigned char *text_2, const unsigned char *text_1, 
      const unsigned char *text, unsigned int numKeys)
  {
      int k;
  
      /* key1[i+1] = key1[i] xor PT/CT[j] */
      for (k=0; k<8; k++) {
          key[k] ^= text[k];
      }
      /* key2 */
      if (numKeys == 2 || numKeys == 3)  {
          /* key2 independent */
          for (k=8; k<16; k++) {
              /* key2[i+1] = KEY2[i] xor PT/CT[j-1] */
              key[k] ^= text_1[k-8];
          }
      } else {
          /* key2 == key 1 */
          for (k=8; k<16; k++) {
              /* key2[i+1] = KEY2[i] xor PT/CT[j] */
              key[k] = key[k-8];
          }
      }
      /* key3 */
      if (numKeys == 1 || numKeys == 2) {
          /* key3 == key 1 */
          for (k=16; k<24; k++) {
              /* key3[i+1] = KEY3[i] xor PT/CT[j] */
              key[k] = key[k-16];
          }
      } else {
          /* key3 independent */ 
          for (k=16; k<24; k++) {
              /* key3[i+1] = KEY3[i] xor PT/CT[j-2] */
              key[k] ^= text_2[k-16];
          }
      }
      /* set the parity bits */            
      for (k=0; k<24; k++) {
          key[k] = odd_parity(key[k]);
      }
  }
  
  /*
   * Perform the Monte Carlo Test
   *
   * mode = NSS_DES_EDE3 or NSS_DES_EDE3_CBC
   * crypt = ENCRYPT || DECRYPT
   * inputtext = plaintext or Cyphertext depending on the value of crypt
   * inputlength is expected to be size 8 bytes 
   * iv = needs to be set for NSS_DES_EDE3_CBC mode
   * resp = is the output response file. 
   */
   void                                                       
  tdea_mct_test(int mode, unsigned char* key, unsigned int numKeys, 
                unsigned int crypt, unsigned char* inputtext, 
                unsigned int inputlength, unsigned char* iv, FILE *resp) { 
  
      int i, j;
      unsigned char outputtext_1[8];      /* PT/CT[j-1] */
      unsigned char outputtext_2[8];      /* PT/CT[j-2] */
      char buf[80];       /* holds one line from the input REQUEST file. */
      unsigned int outputlen;
      unsigned char outputtext[8];
      
          
      SECStatus rv;
  
      if (mode == NSS_DES_EDE3 && iv != NULL) {
          printf("IV must be NULL for NSS_DES_EDE3 mode");
          goto loser;
      } else if (mode == NSS_DES_EDE3_CBC && iv == NULL) {
          printf("IV must not be NULL for NSS_DES_EDE3_CBC mode");
          goto loser;
      }
  
      /* loop 400 times */
      for (i=0; i<400; i++) {
          /* if i == 0 CV[0] = IV  not necessary */        
          /* record the count and key values and plainText */
          sprintf(buf, "COUNT = %d\n", i);
          fputs(buf, resp);
          /* Output KEY1[i] */
          fputs("KEY1 = ", resp);
          to_hex_str(buf, key, 8);
          fputs(buf, resp);
          fputc('\n', resp);
          /* Output KEY2[i] */
          fputs("KEY2 = ", resp);
          to_hex_str(buf, &key[8], 8);
          fputs(buf, resp);
          fputc('\n', resp);
          /* Output KEY3[i] */
          fputs("KEY3 = ", resp);
          to_hex_str(buf, &key[16], 8);
          fputs(buf, resp);
          fputc('\n', resp);
          if (mode == NSS_DES_EDE3_CBC) {
              /* Output CV[i] */
              fputs("IV = ", resp);
              to_hex_str(buf, iv, 8);
              fputs(buf, resp);
              fputc('\n', resp);
          }
          if (crypt == ENCRYPT) {
              /* Output PT[0] */
              fputs("PLAINTEXT = ", resp);
          } else {
              /* Output CT[0] */
              fputs("CIPHERTEXT = ", resp);
          }
  
          to_hex_str(buf, inputtext, inputlength);
          fputs(buf, resp);
          fputc('\n', resp);
  
          /* loop 10,000 times */
          for (j=0; j<10000; j++) {
  
              outputlen = 0;
              if (crypt == ENCRYPT) {
                  /* inputtext == ciphertext outputtext == plaintext*/
                  rv = tdea_encrypt_buf(mode, key,
                              (mode == NSS_DES_EDE3) ? NULL : iv,
                              outputtext, &outputlen, 8,
                              inputtext, 8);
              } else {
                  /* inputtext == plaintext outputtext == ciphertext */
                  rv = tdea_decrypt_buf(mode, key,
                              (mode == NSS_DES_EDE3) ? NULL : iv,
                              outputtext, &outputlen, 8,
                              inputtext, 8);
              }
  
              if (rv != SECSuccess) {
                  goto loser;
              }
              if (outputlen != inputlength) {
                  goto loser;
              }
  
              if (mode == NSS_DES_EDE3_CBC) {
                  if (crypt == ENCRYPT) {
                      if (j == 0) {
                          /*P[j+1] = CV[0] */
                          memcpy(inputtext, iv, 8);
                      } else {
                          /* p[j+1] = C[j-1] */
                          memcpy(inputtext, outputtext_1, 8);
                      }
                      /* CV[j+1] = C[j] */
                      memcpy(iv, outputtext, 8);
                      if (j != 9999) {
                          /* save C[j-1] */
                          memcpy(outputtext_1, outputtext, 8);
                      }
                  } else { /* DECRYPT */
                      /* CV[j+1] = C[j] */
                      memcpy(iv, inputtext, 8);
                      /* C[j+1] = P[j] */
                      memcpy(inputtext, outputtext, 8);
                  }
              } else {
                  /* ECB mode PT/CT[j+1] = CT/PT[j] */
                  memcpy(inputtext, outputtext, 8);
              }
  
              /* Save PT/CT[j-2] and PT/CT[j-1] */
              if (j==9997) memcpy(outputtext_2, outputtext, 8);
              if (j==9998) memcpy(outputtext_1, outputtext, 8);
              /* done at the end of the for(j) loop */
          }
  
  
          if (crypt == ENCRYPT) {
              /* Output CT[j] */
              fputs("CIPHERTEXT = ", resp);
          } else {
              /* Output PT[j] */
              fputs("PLAINTEXT = ", resp);
          }
          to_hex_str(buf, outputtext, 8);
          fputs(buf, resp);
          fputc('\n', resp);
  
          /* Key[i+1] = Key[i] xor ...  outputtext_2 == PT/CT[j-2] 
           *  outputtext_1 == PT/CT[j-1] outputtext == PT/CT[j] 
           */
          tdea_mct_next_keys(key, outputtext_2, 
                             outputtext_1, outputtext, numKeys);
  
          if (mode == NSS_DES_EDE3_CBC) {
              /* taken care of in the j=9999 iteration */
              if (crypt == ENCRYPT) {
                  /* P[i] = C[j-1] */
                  /* CV[i] = C[j] */
              } else {
                  /* taken care of in the j=9999 iteration */
                  /* CV[i] = C[j] */
                  /* C[i] = P[j]  */
              }
          } else {
              /* ECB PT/CT[i] = PT/CT[j]  */
              memcpy(inputtext, outputtext, 8);
          }
          /* done at the end of the for(i) loop */
          fputc('\n', resp);
      }
  
  loser:
      return;
  }
  
  /*
   * Perform the TDEA Monte Carlo Test (MCT) in ECB/CBC modes.
   * by gathering the input from the request file, and then 
   * calling tdea_mct_test.
   *
   * reqfn is the pathname of the input REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  tdea_mct(int mode, char *reqfn)
  {
      int i, j;
      char buf[80];    /* holds one line from the input REQUEST file. */
      FILE *req;       /* input stream from the REQUEST file */
      FILE *resp;      /* output stream to the RESPONSE file */
      unsigned int crypt = 0;    /* 1 means encrypt, 0 means decrypt */
      unsigned char key[24];              /* TDEA 3 key bundle */
      unsigned int numKeys = 0;
      unsigned char plaintext[8];        /* PT[j] */
      unsigned char ciphertext[8];       /* CT[j] */
      unsigned char iv[8];
  
      /* zeroize the variables for the test with this data set */
      memset(key, 0, sizeof key);
      memset(plaintext, 0, sizeof plaintext);
      memset(ciphertext, 0, sizeof ciphertext);
      memset(iv, 0, sizeof iv);
  
      req = fopen(reqfn, "r");
      resp = stdout;
      while (fgets(buf, sizeof buf, req) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, resp);
              continue;
          }
          /* [ENCRYPT] or [DECRYPT] */
          if (buf[0] == '[') {
              if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
                  crypt = ENCRYPT;
              } else {
                  crypt = DECRYPT;
             }
             fputs(buf, resp);
             continue;
          }
          /* NumKeys */
          if (strncmp(&buf[0], "NumKeys", 7) == 0) {
              i = 7;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              numKeys = atoi(&buf[i]);
              continue;
          }
          /* KEY1 = ... */
          if (strncmp(buf, "KEY1", 4) == 0) {
              i = 4;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &key[j]);
              }
              continue;
          }
          /* KEY2 = ... */
          if (strncmp(buf, "KEY2", 4) == 0) {
              i = 4;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=8; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &key[j]);
              }
              continue;
          }
          /* KEY3 = ... */
          if (strncmp(buf, "KEY3", 4) == 0) {
              i = 4;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=16; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &key[j]);
              }
              continue;
          }
  
          /* IV = ... */
          if (strncmp(buf, "IV", 2) == 0) {
              i = 2;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j<sizeof iv; i+=2,j++) {
                  hex_to_byteval(&buf[i], &iv[j]);
              }
              continue;
          }
  
         /* PLAINTEXT = ... */
         if (strncmp(buf, "PLAINTEXT", 9) == 0) {
  
              /* sanity check */
              if (crypt != ENCRYPT) {
                  goto loser;
              }
              /* PT[0] = PT */
              i = 9;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j<sizeof plaintext; i+=2,j++) {
                  hex_to_byteval(&buf[i], &plaintext[j]);
              }                                     
  
              /* do the Monte Carlo test */
              if (mode==NSS_DES_EDE3) {
                  tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, plaintext, sizeof plaintext, NULL, resp);
              } else {
                  tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, plaintext, sizeof plaintext, iv, resp);
              }
              continue;
          }
          /* CIPHERTEXT = ... */
          if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
              /* sanity check */
              if (crypt != DECRYPT) {
                  goto loser;
              }
              /* CT[0] = CT */
              i = 10;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &ciphertext[j]);
              }
              
              /* do the Monte Carlo test */
              if (mode==NSS_DES_EDE3) {
                  tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, ciphertext, sizeof ciphertext, NULL, resp); 
              } else {
                  tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, ciphertext, sizeof ciphertext, iv, resp); 
              }
              continue;
          }
      }
  
  loser:
      fclose(req);
  }
  
  
  SECStatus
  aes_encrypt_buf(
      int mode,
      const unsigned char *key, unsigned int keysize,
      const unsigned char *iv,
      unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
      const unsigned char *input, unsigned int inputlen)
  {
      SECStatus rv = SECFailure;
      AESContext *cx;
      unsigned char doublecheck[10*16];  /* 1 to 10 blocks */
      unsigned int doublechecklen = 0;
  
      cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
      if (cx == NULL) {
  	goto loser;
      }
      rv = AES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
      if (rv != SECSuccess) {
  	goto loser;
      }
      if (*outputlen != inputlen) {
  	goto loser;
      }
      AES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
  
      /*
       * Doublecheck our result by decrypting the ciphertext and
       * compare the output with the input plaintext.
       */
      cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
      if (cx == NULL) {
  	goto loser;
      }
      rv = AES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
  	output, *outputlen);
      if (rv != SECSuccess) {
  	goto loser;
      }
      if (doublechecklen != *outputlen) {
  	goto loser;
      }
      AES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
      if (memcmp(doublecheck, input, inputlen) != 0) {
  	goto loser;
      }
      rv = SECSuccess;
  
  loser:
      if (cx != NULL) {
  	AES_DestroyContext(cx, PR_TRUE);
      }
      return rv;
  }
  
  SECStatus
  aes_decrypt_buf(
      int mode,
      const unsigned char *key, unsigned int keysize,
      const unsigned char *iv,
      unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
      const unsigned char *input, unsigned int inputlen)
  {
      SECStatus rv = SECFailure;
      AESContext *cx;
      unsigned char doublecheck[10*16];  /* 1 to 10 blocks */
      unsigned int doublechecklen = 0;
  
      cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
      if (cx == NULL) {
  	goto loser;
      }
      rv = AES_Decrypt(cx, output, outputlen, maxoutputlen,
  	input, inputlen);
      if (rv != SECSuccess) {
  	goto loser;
      }
      if (*outputlen != inputlen) {
  	goto loser;
      }
      AES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
  
      /*
       * Doublecheck our result by encrypting the plaintext and
       * compare the output with the input ciphertext.
       */
      cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
      if (cx == NULL) {
  	goto loser;
      }
      rv = AES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
  	output, *outputlen);
      if (rv != SECSuccess) {
  	goto loser;
      }
      if (doublechecklen != *outputlen) {
  	goto loser;
      }
      AES_DestroyContext(cx, PR_TRUE);
      cx = NULL;
      if (memcmp(doublecheck, input, inputlen) != 0) {
  	goto loser;
      }
      rv = SECSuccess;
  
  loser:
      if (cx != NULL) {
  	AES_DestroyContext(cx, PR_TRUE);
      }
      return rv;
  }
  
  /*
   * Perform the AES Known Answer Test (KAT) or Multi-block Message
   * Test (MMT) in ECB or CBC mode.  The KAT (there are four types)
   * and MMT have the same structure: given the key and IV (CBC mode
   * only), encrypt the given plaintext or decrypt the given ciphertext.
   * So we can handle them the same way.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  aes_kat_mmt(char *reqfn)
  {
      char buf[512];      /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "CIPHERTEXT = <320 hex digits>\n".
                           */
      FILE *aesreq;       /* input stream from the REQUEST file */
      FILE *aesresp;      /* output stream to the RESPONSE file */
      int i, j;
      int mode;           /* NSS_AES (ECB) or NSS_AES_CBC */
      int encrypt = 0;    /* 1 means encrypt, 0 means decrypt */
      unsigned char key[32];              /* 128, 192, or 256 bits */
      unsigned int keysize;
      unsigned char iv[16];		/* for all modes except ECB */
      unsigned char plaintext[10*16];     /* 1 to 10 blocks */
      unsigned int plaintextlen;
      unsigned char ciphertext[10*16];    /* 1 to 10 blocks */
      unsigned int ciphertextlen;
      SECStatus rv;
  
      aesreq = fopen(reqfn, "r");
      aesresp = stdout;
      while (fgets(buf, sizeof buf, aesreq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* [ENCRYPT] or [DECRYPT] */
  	if (buf[0] == '[') {
  	    if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
  		encrypt = 1;
  	    } else {
  		encrypt = 0;
  	    }
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* "COUNT = x" begins a new data set */
  	if (strncmp(buf, "COUNT", 5) == 0) {
  	    mode = NSS_AES;
  	    /* zeroize the variables for the test with this data set */
  	    memset(key, 0, sizeof key);
  	    keysize = 0;
  	    memset(iv, 0, sizeof iv);
  	    memset(plaintext, 0, sizeof plaintext);
  	    plaintextlen = 0;
  	    memset(ciphertext, 0, sizeof ciphertext);
  	    ciphertextlen = 0;
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* KEY = ... */
  	if (strncmp(buf, "KEY", 3) == 0) {
  	    i = 3;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &key[j]);
  	    }
  	    keysize = j;
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* IV = ... */
  	if (strncmp(buf, "IV", 2) == 0) {
  	    mode = NSS_AES_CBC;
  	    i = 2;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<sizeof iv; i+=2,j++) {
  		hex_to_byteval(&buf[i], &iv[j]);
  	    }
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* PLAINTEXT = ... */
  	if (strncmp(buf, "PLAINTEXT", 9) == 0) {
  	    /* sanity check */
  	    if (!encrypt) {
  		goto loser;
  	    }
  
  	    i = 9;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &plaintext[j]);
  	    }
  	    plaintextlen = j;
  
  	    rv = aes_encrypt_buf(mode, key, keysize,
  		(mode == NSS_AES) ? NULL : iv,
  		ciphertext, &ciphertextlen, sizeof ciphertext,
  		plaintext, plaintextlen);
  	    if (rv != SECSuccess) {
  		goto loser;
  	    }
  
  	    fputs(buf, aesresp);
  	    fputs("CIPHERTEXT = ", aesresp);
  	    to_hex_str(buf, ciphertext, ciphertextlen);
  	    fputs(buf, aesresp);
  	    fputc('\n', aesresp);
  	    continue;
  	}
  	/* CIPHERTEXT = ... */
  	if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
  	    /* sanity check */
  	    if (encrypt) {
  		goto loser;
  	    }
  
  	    i = 10;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &ciphertext[j]);
  	    }
  	    ciphertextlen = j;
  
  	    rv = aes_decrypt_buf(mode, key, keysize,
  		(mode == NSS_AES) ? NULL : iv,
  		plaintext, &plaintextlen, sizeof plaintext,
  		ciphertext, ciphertextlen);
  	    if (rv != SECSuccess) {
  		goto loser;
  	    }
  
  	    fputs(buf, aesresp);
  	    fputs("PLAINTEXT = ", aesresp);
  	    to_hex_str(buf, plaintext, plaintextlen);
  	    fputs(buf, aesresp);
  	    fputc('\n', aesresp);
  	    continue;
  	}
      }
  loser:
      fclose(aesreq);
  }
  
  /*
   * Generate Key[i+1] from Key[i], CT[j-1], and CT[j] for AES Monte Carlo
   * Test (MCT) in ECB and CBC modes.
   */
  void
  aes_mct_next_key(unsigned char *key, unsigned int keysize,
      const unsigned char *ciphertext_1, const unsigned char *ciphertext)
  {
      int k;
  
      switch (keysize) {
      case 16:  /* 128-bit key */
  	/* Key[i+1] = Key[i] xor CT[j] */
  	for (k=0; k<16; k++) {
  	    key[k] ^= ciphertext[k];
  	}
  	break;
      case 24:  /* 192-bit key */
  	/*
  	 * Key[i+1] = Key[i] xor (last 64-bits of
  	 *            CT[j-1] || CT[j])
  	 */
  	for (k=0; k<8; k++) {
  	    key[k] ^= ciphertext_1[k+8];
  	}
  	for (k=8; k<24; k++) {
  	    key[k] ^= ciphertext[k-8];
  	}
  	break;
      case 32:  /* 256-bit key */
  	/* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */
  	for (k=0; k<16; k++) {
  	    key[k] ^= ciphertext_1[k];
  	}
  	for (k=16; k<32; k++) {
  	    key[k] ^= ciphertext[k-16];
  	}
  	break;
      }
  }
  
  /*
   * Perform the AES Monte Carlo Test (MCT) in ECB mode.  MCT exercises
   * our AES code in streaming mode because the plaintext or ciphertext
   * is generated block by block as we go, so we can't collect all the
   * plaintext or ciphertext in one buffer and encrypt or decrypt it in
   * one shot.
   *
   * reqfn is the pathname of the input REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  aes_ecb_mct(char *reqfn)
  {
      char buf[80];       /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "KEY = <64 hex digits>\n".
                           */
      FILE *aesreq;       /* input stream from the REQUEST file */
      FILE *aesresp;      /* output stream to the RESPONSE file */
      int i, j;
      int encrypt = 0;    /* 1 means encrypt, 0 means decrypt */
      unsigned char key[32];              /* 128, 192, or 256 bits */
      unsigned int keysize;
      unsigned char plaintext[16];        /* PT[j] */
      unsigned char plaintext_1[16];      /* PT[j-1] */
      unsigned char ciphertext[16];       /* CT[j] */
      unsigned char ciphertext_1[16];     /* CT[j-1] */
      unsigned char doublecheck[16];
      unsigned int outputlen;
      AESContext *cx = NULL;	/* the operation being tested */
      AESContext *cx2 = NULL;     /* the inverse operation done in parallel
                                   * to doublecheck our result.
                                   */
      SECStatus rv;
  
      aesreq = fopen(reqfn, "r");
      aesresp = stdout;
      while (fgets(buf, sizeof buf, aesreq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* [ENCRYPT] or [DECRYPT] */
  	if (buf[0] == '[') {
  	    if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
  		encrypt = 1;
  	    } else {
  		encrypt = 0;
  	    }
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* "COUNT = x" begins a new data set */
  	if (strncmp(buf, "COUNT", 5) == 0) {
  	    /* zeroize the variables for the test with this data set */
  	    memset(key, 0, sizeof key);
  	    keysize = 0;
  	    memset(plaintext, 0, sizeof plaintext);
  	    memset(ciphertext, 0, sizeof ciphertext);
  	    continue;
  	}
  	/* KEY = ... */
  	if (strncmp(buf, "KEY", 3) == 0) {
  	    /* Key[0] = Key */
  	    i = 3;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &key[j]);
  	    }
  	    keysize = j;
  	    continue;
  	}
  	/* PLAINTEXT = ... */
  	if (strncmp(buf, "PLAINTEXT", 9) == 0) {
  	    /* sanity check */
  	    if (!encrypt) {
  		goto loser;
  	    }
  	    /* PT[0] = PT */
  	    i = 9;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<sizeof plaintext; i+=2,j++) {
  		hex_to_byteval(&buf[i], &plaintext[j]);
  	    }
  
  	    for (i=0; i<100; i++) {
  		sprintf(buf, "COUNT = %d\n", i);
  	        fputs(buf, aesresp);
  		/* Output Key[i] */
  		fputs("KEY = ", aesresp);
  		to_hex_str(buf, key, keysize);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  		/* Output PT[0] */
  		fputs("PLAINTEXT = ", aesresp);
  		to_hex_str(buf, plaintext, sizeof plaintext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		cx = AES_CreateContext(key, NULL, NSS_AES,
  		    PR_TRUE, keysize, 16);
  		if (cx == NULL) {
  		    goto loser;
  		}
  		/*
  		 * doublecheck our result by decrypting the result
  		 * and comparing the output with the plaintext.
  		 */
  		cx2 = AES_CreateContext(key, NULL, NSS_AES,
  		    PR_FALSE, keysize, 16);
  		if (cx2 == NULL) {
  		    goto loser;
  		}
  		for (j=0; j<1000; j++) {
  		    /* Save CT[j-1] */
  		    memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
  
  		    /* CT[j] = AES(Key[i], PT[j]) */
  		    outputlen = 0;
  		    rv = AES_Encrypt(cx,
  			ciphertext, &outputlen, sizeof ciphertext,
  			plaintext, sizeof plaintext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof plaintext) {
  			goto loser;
  		    }
  
  		    /* doublecheck our result */
  		    outputlen = 0;
  		    rv = AES_Decrypt(cx2,
  			doublecheck, &outputlen, sizeof doublecheck,
  			ciphertext, sizeof ciphertext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof ciphertext) {
  			goto loser;
  		    }
  		    if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
  			goto loser;
  		    }
  
  		    /* PT[j+1] = CT[j] */
  		    memcpy(plaintext, ciphertext, sizeof plaintext);
  		}
  		AES_DestroyContext(cx, PR_TRUE);
  		cx = NULL;
  		AES_DestroyContext(cx2, PR_TRUE);
  		cx2 = NULL;
  
  		/* Output CT[j] */
  		fputs("CIPHERTEXT = ", aesresp);
  		to_hex_str(buf, ciphertext, sizeof ciphertext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		/* Key[i+1] = Key[i] xor ... */
  		aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
  		/* PT[0] = CT[j] */
  		/* done at the end of the for(j) loop */
  
  		fputc('\n', aesresp);
  	    }
  
  	    continue;
  	}
  	/* CIPHERTEXT = ... */
  	if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
  	    /* sanity check */
  	    if (encrypt) {
  		goto loser;
  	    }
  	    /* CT[0] = CT */
  	    i = 10;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &ciphertext[j]);
  	    }
  
  	    for (i=0; i<100; i++) {
  		sprintf(buf, "COUNT = %d\n", i);
  	        fputs(buf, aesresp);
  		/* Output Key[i] */
  		fputs("KEY = ", aesresp);
  		to_hex_str(buf, key, keysize);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  		/* Output CT[0] */
  		fputs("CIPHERTEXT = ", aesresp);
  		to_hex_str(buf, ciphertext, sizeof ciphertext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		cx = AES_CreateContext(key, NULL, NSS_AES,
  		    PR_FALSE, keysize, 16);
  		if (cx == NULL) {
  		    goto loser;
  		}
  		/*
  		 * doublecheck our result by encrypting the result
  		 * and comparing the output with the ciphertext.
  		 */
  		cx2 = AES_CreateContext(key, NULL, NSS_AES,
  		    PR_TRUE, keysize, 16);
  		if (cx2 == NULL) {
  		    goto loser;
  		}
  		for (j=0; j<1000; j++) {
  		    /* Save PT[j-1] */
  		    memcpy(plaintext_1, plaintext, sizeof plaintext);
  
  		    /* PT[j] = AES(Key[i], CT[j]) */
  		    outputlen = 0;
  		    rv = AES_Decrypt(cx,
  			plaintext, &outputlen, sizeof plaintext,
  			ciphertext, sizeof ciphertext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof ciphertext) {
  			goto loser;
  		    }
  
  		    /* doublecheck our result */
  		    outputlen = 0;
  		    rv = AES_Encrypt(cx2,
  			doublecheck, &outputlen, sizeof doublecheck,
  			plaintext, sizeof plaintext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof plaintext) {
  			goto loser;
  		    }
  		    if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
  			goto loser;
  		    }
  
  		    /* CT[j+1] = PT[j] */
  		    memcpy(ciphertext, plaintext, sizeof ciphertext);
  		}
  		AES_DestroyContext(cx, PR_TRUE);
  		cx = NULL;
  		AES_DestroyContext(cx2, PR_TRUE);
  		cx2 = NULL;
  
  		/* Output PT[j] */
  		fputs("PLAINTEXT = ", aesresp);
  		to_hex_str(buf, plaintext, sizeof plaintext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		/* Key[i+1] = Key[i] xor ... */
  		aes_mct_next_key(key, keysize, plaintext_1, plaintext);
  		/* CT[0] = PT[j] */
  		/* done at the end of the for(j) loop */
  
  		fputc('\n', aesresp);
  	    }
  
  	    continue;
  	}
      }
  loser:
      if (cx != NULL) {
  	AES_DestroyContext(cx, PR_TRUE);
      }
      if (cx2 != NULL) {
  	AES_DestroyContext(cx2, PR_TRUE);
      }
      fclose(aesreq);
  }
  
  /*
   * Perform the AES Monte Carlo Test (MCT) in CBC mode.  MCT exercises
   * our AES code in streaming mode because the plaintext or ciphertext
   * is generated block by block as we go, so we can't collect all the
   * plaintext or ciphertext in one buffer and encrypt or decrypt it in
   * one shot.
   *
   * reqfn is the pathname of the input REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  aes_cbc_mct(char *reqfn)
  {
      char buf[80];       /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "KEY = <64 hex digits>\n".
                           */
      FILE *aesreq;       /* input stream from the REQUEST file */
      FILE *aesresp;      /* output stream to the RESPONSE file */
      int i, j;
      int encrypt = 0;    /* 1 means encrypt, 0 means decrypt */
      unsigned char key[32];              /* 128, 192, or 256 bits */
      unsigned int keysize;
      unsigned char iv[16];
      unsigned char plaintext[16];        /* PT[j] */
      unsigned char plaintext_1[16];      /* PT[j-1] */
      unsigned char ciphertext[16];       /* CT[j] */
      unsigned char ciphertext_1[16];     /* CT[j-1] */
      unsigned char doublecheck[16];
      unsigned int outputlen;
      AESContext *cx = NULL;	/* the operation being tested */
      AESContext *cx2 = NULL;     /* the inverse operation done in parallel
                                   * to doublecheck our result.
                                   */
      SECStatus rv;
  
      aesreq = fopen(reqfn, "r");
      aesresp = stdout;
      while (fgets(buf, sizeof buf, aesreq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* [ENCRYPT] or [DECRYPT] */
  	if (buf[0] == '[') {
  	    if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
  		encrypt = 1;
  	    } else {
  		encrypt = 0;
  	    }
  	    fputs(buf, aesresp);
  	    continue;
  	}
  	/* "COUNT = x" begins a new data set */
  	if (strncmp(buf, "COUNT", 5) == 0) {
  	    /* zeroize the variables for the test with this data set */
  	    memset(key, 0, sizeof key);
  	    keysize = 0;
  	    memset(iv, 0, sizeof iv);
  	    memset(plaintext, 0, sizeof plaintext);
  	    memset(ciphertext, 0, sizeof ciphertext);
  	    continue;
  	}
  	/* KEY = ... */
  	if (strncmp(buf, "KEY", 3) == 0) {
  	    /* Key[0] = Key */
  	    i = 3;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &key[j]);
  	    }
  	    keysize = j;
  	    continue;
  	}
  	/* IV = ... */
  	if (strncmp(buf, "IV", 2) == 0) {
  	    /* IV[0] = IV */
  	    i = 2;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<sizeof iv; i+=2,j++) {
  		hex_to_byteval(&buf[i], &iv[j]);
  	    }
  	    continue;
  	}
  	/* PLAINTEXT = ... */
  	if (strncmp(buf, "PLAINTEXT", 9) == 0) {
  	    /* sanity check */
  	    if (!encrypt) {
  		goto loser;
  	    }
  	    /* PT[0] = PT */
  	    i = 9;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<sizeof plaintext; i+=2,j++) {
  		hex_to_byteval(&buf[i], &plaintext[j]);
  	    }
  
  	    for (i=0; i<100; i++) {
  		sprintf(buf, "COUNT = %d\n", i);
  	        fputs(buf, aesresp);
  		/* Output Key[i] */
  		fputs("KEY = ", aesresp);
  		to_hex_str(buf, key, keysize);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  		/* Output IV[i] */
  		fputs("IV = ", aesresp);
  		to_hex_str(buf, iv, sizeof iv);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  		/* Output PT[0] */
  		fputs("PLAINTEXT = ", aesresp);
  		to_hex_str(buf, plaintext, sizeof plaintext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		cx = AES_CreateContext(key, iv, NSS_AES_CBC,
  		    PR_TRUE, keysize, 16);
  		if (cx == NULL) {
  		    goto loser;
  		}
  		/*
  		 * doublecheck our result by decrypting the result
  		 * and comparing the output with the plaintext.
  		 */
  		cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
  		    PR_FALSE, keysize, 16);
  		if (cx2 == NULL) {
  		    goto loser;
  		}
  		/* CT[-1] = IV[i] */
  		memcpy(ciphertext, iv, sizeof ciphertext);
  		for (j=0; j<1000; j++) {
  		    /* Save CT[j-1] */
  		    memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
  		    /*
  		     * If ( j=0 )
  		     *      CT[j] = AES(Key[i], IV[i], PT[j])
  		     *      PT[j+1] = IV[i] (= CT[j-1])
  		     * Else
  		     *      CT[j] = AES(Key[i], PT[j])
  		     *      PT[j+1] = CT[j-1]
  		     */
  		    outputlen = 0;
  		    rv = AES_Encrypt(cx,
  			ciphertext, &outputlen, sizeof ciphertext,
  			plaintext, sizeof plaintext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof plaintext) {
  			goto loser;
  		    }
  
  		    /* doublecheck our result */
  		    outputlen = 0;
  		    rv = AES_Decrypt(cx2,
  			doublecheck, &outputlen, sizeof doublecheck,
  			ciphertext, sizeof ciphertext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof ciphertext) {
  			goto loser;
  		    }
  		    if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
  			goto loser;
  		    }
  
  		    memcpy(plaintext, ciphertext_1, sizeof plaintext);
  		}
  		AES_DestroyContext(cx, PR_TRUE);
  		cx = NULL;
  		AES_DestroyContext(cx2, PR_TRUE);
  		cx2 = NULL;
  
  		/* Output CT[j] */
  		fputs("CIPHERTEXT = ", aesresp);
  		to_hex_str(buf, ciphertext, sizeof ciphertext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		/* Key[i+1] = Key[i] xor ... */
  		aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
  		/* IV[i+1] = CT[j] */
  		memcpy(iv, ciphertext, sizeof iv);
  		/* PT[0] = CT[j-1] */
  		/* done at the end of the for(j) loop */
  
  		fputc('\n', aesresp);
  	    }
  
  	    continue;
  	}
  	/* CIPHERTEXT = ... */
  	if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
  	    /* sanity check */
  	    if (encrypt) {
  		goto loser;
  	    }
  	    /* CT[0] = CT */
  	    i = 10;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &ciphertext[j]);
  	    }
  
  	    for (i=0; i<100; i++) {
  		sprintf(buf, "COUNT = %d\n", i);
  	        fputs(buf, aesresp);
  		/* Output Key[i] */
  		fputs("KEY = ", aesresp);
  		to_hex_str(buf, key, keysize);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  		/* Output IV[i] */
  		fputs("IV = ", aesresp);
  		to_hex_str(buf, iv, sizeof iv);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  		/* Output CT[0] */
  		fputs("CIPHERTEXT = ", aesresp);
  		to_hex_str(buf, ciphertext, sizeof ciphertext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		cx = AES_CreateContext(key, iv, NSS_AES_CBC,
  		    PR_FALSE, keysize, 16);
  		if (cx == NULL) {
  		    goto loser;
  		}
  		/*
  		 * doublecheck our result by encrypting the result
  		 * and comparing the output with the ciphertext.
  		 */
  		cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
  		    PR_TRUE, keysize, 16);
  		if (cx2 == NULL) {
  		    goto loser;
  		}
  		/* PT[-1] = IV[i] */
  		memcpy(plaintext, iv, sizeof plaintext);
  		for (j=0; j<1000; j++) {
  		    /* Save PT[j-1] */
  		    memcpy(plaintext_1, plaintext, sizeof plaintext);
  		    /*
  		     * If ( j=0 )
  		     *      PT[j] = AES(Key[i], IV[i], CT[j])
  		     *      CT[j+1] = IV[i] (= PT[j-1])
  		     * Else
  		     *      PT[j] = AES(Key[i], CT[j])
  		     *      CT[j+1] = PT[j-1]
  		     */
  		    outputlen = 0;
  		    rv = AES_Decrypt(cx,
  			plaintext, &outputlen, sizeof plaintext,
  			ciphertext, sizeof ciphertext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof ciphertext) {
  			goto loser;
  		    }
  
  		    /* doublecheck our result */
  		    outputlen = 0;
  		    rv = AES_Encrypt(cx2,
  			doublecheck, &outputlen, sizeof doublecheck,
  			plaintext, sizeof plaintext);
  		    if (rv != SECSuccess) {
  			goto loser;
  		    }
  		    if (outputlen != sizeof plaintext) {
  			goto loser;
  		    }
  		    if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
  			goto loser;
  		    }
  
  		    memcpy(ciphertext, plaintext_1, sizeof ciphertext);
  		}
  		AES_DestroyContext(cx, PR_TRUE);
  		cx = NULL;
  		AES_DestroyContext(cx2, PR_TRUE);
  		cx2 = NULL;
  
  		/* Output PT[j] */
  		fputs("PLAINTEXT = ", aesresp);
  		to_hex_str(buf, plaintext, sizeof plaintext);
  		fputs(buf, aesresp);
  		fputc('\n', aesresp);
  
  		/* Key[i+1] = Key[i] xor ... */
  		aes_mct_next_key(key, keysize, plaintext_1, plaintext);
  		/* IV[i+1] = PT[j] */
  		memcpy(iv, plaintext, sizeof iv);
  		/* CT[0] = PT[j-1] */
  		/* done at the end of the for(j) loop */
  
  		fputc('\n', aesresp);
  	    }
  
  	    continue;
  	}
      }
  loser:
      if (cx != NULL) {
  	AES_DestroyContext(cx, PR_TRUE);
      }
      if (cx2 != NULL) {
  	AES_DestroyContext(cx2, PR_TRUE);
      }
      fclose(aesreq);
  }
  
  void write_compact_string(FILE *out, unsigned char *hash, unsigned int len)
  {
      unsigned int i;
      int j, count = 0, last = -1, z = 0;
      long start = ftell(out);
      for (i=0; i<len; i++) {
  	for (j=7; j>=0; j--) {
  	    if (last < 0) {
  		last = (hash[i] & (1 << j)) ? 1 : 0;
  		fprintf(out, "%d ", last);
  		count = 1;
  	    } else if (hash[i] & (1 << j)) {
  		if (last) {
  		    count++; 
  		} else { 
  		    last = 0;
  		    fprintf(out, "%d ", count);
  		    count = 1;
  		    z++;
  		}
  	    } else {
  		if (!last) {
  		    count++; 
  		} else { 
  		    last = 1;
  		    fprintf(out, "%d ", count);
  		    count = 1;
  		    z++;
  		}
  	    }
  	}
      }
      fprintf(out, "^\n");
      fseek(out, start, SEEK_SET);
      fprintf(out, "%d ", z);
      fseek(out, 0, SEEK_END);
  }
  
  int get_next_line(FILE *req, char *key, char *val, FILE *rsp)
  {
      int ignore = 0;
      char *writeto = key;
      int w = 0;
      int c;
      while ((c = fgetc(req)) != EOF) {
  	if (ignore) {
  	    fprintf(rsp, "%c", c);
  	    if (c == '\n') return ignore;
  	} else if (c == '\n') {
  	    break;
  	} else if (c == '#') {
  	    ignore = 1;
  	    fprintf(rsp, "%c", c);
  	} else if (c == '=') {
  	    writeto[w] = '\0';
  	    w = 0;
  	    writeto = val;
  	} else if (c == ' ' || c == '[' || c == ']') {
  	    continue;
  	} else {
  	    writeto[w++] = c;
  	}
      }
      writeto[w] = '\0';
      return (c == EOF) ? -1 : ignore;
  }
  
  #ifndef NSS_DISABLE_ECC
  typedef struct curveNameTagPairStr {
      char *curveName;
      SECOidTag curveOidTag;
  } CurveNameTagPair;
  
  #define DEFAULT_CURVE_OID_TAG  SEC_OID_SECG_EC_SECP192R1
  /* #define DEFAULT_CURVE_OID_TAG  SEC_OID_SECG_EC_SECP160R1 */
  
  static CurveNameTagPair nameTagPair[] =
  { 
    { "sect163k1", SEC_OID_SECG_EC_SECT163K1},
    { "nistk163", SEC_OID_SECG_EC_SECT163K1},
    { "sect163r1", SEC_OID_SECG_EC_SECT163R1},
    { "sect163r2", SEC_OID_SECG_EC_SECT163R2},
    { "nistb163", SEC_OID_SECG_EC_SECT163R2},
    { "sect193r1", SEC_OID_SECG_EC_SECT193R1},
    { "sect193r2", SEC_OID_SECG_EC_SECT193R2},
    { "sect233k1", SEC_OID_SECG_EC_SECT233K1},
    { "nistk233", SEC_OID_SECG_EC_SECT233K1},
    { "sect233r1", SEC_OID_SECG_EC_SECT233R1},
    { "nistb233", SEC_OID_SECG_EC_SECT233R1},
    { "sect239k1", SEC_OID_SECG_EC_SECT239K1},
    { "sect283k1", SEC_OID_SECG_EC_SECT283K1},
    { "nistk283", SEC_OID_SECG_EC_SECT283K1},
    { "sect283r1", SEC_OID_SECG_EC_SECT283R1},
    { "nistb283", SEC_OID_SECG_EC_SECT283R1},
    { "sect409k1", SEC_OID_SECG_EC_SECT409K1},
    { "nistk409", SEC_OID_SECG_EC_SECT409K1},
    { "sect409r1", SEC_OID_SECG_EC_SECT409R1},
    { "nistb409", SEC_OID_SECG_EC_SECT409R1},
    { "sect571k1", SEC_OID_SECG_EC_SECT571K1},
    { "nistk571", SEC_OID_SECG_EC_SECT571K1},
    { "sect571r1", SEC_OID_SECG_EC_SECT571R1},
    { "nistb571", SEC_OID_SECG_EC_SECT571R1},
    { "secp160k1", SEC_OID_SECG_EC_SECP160K1},
    { "secp160r1", SEC_OID_SECG_EC_SECP160R1},
    { "secp160r2", SEC_OID_SECG_EC_SECP160R2},
    { "secp192k1", SEC_OID_SECG_EC_SECP192K1},
    { "secp192r1", SEC_OID_SECG_EC_SECP192R1},
    { "nistp192", SEC_OID_SECG_EC_SECP192R1},
    { "secp224k1", SEC_OID_SECG_EC_SECP224K1},
    { "secp224r1", SEC_OID_SECG_EC_SECP224R1},
    { "nistp224", SEC_OID_SECG_EC_SECP224R1},
    { "secp256k1", SEC_OID_SECG_EC_SECP256K1},
    { "secp256r1", SEC_OID_SECG_EC_SECP256R1},
    { "nistp256", SEC_OID_SECG_EC_SECP256R1},
    { "secp384r1", SEC_OID_SECG_EC_SECP384R1},
    { "nistp384", SEC_OID_SECG_EC_SECP384R1},
    { "secp521r1", SEC_OID_SECG_EC_SECP521R1},
    { "nistp521", SEC_OID_SECG_EC_SECP521R1},
  
    { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
    { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
    { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
    { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
    { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
    { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
  
    { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
    { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
    { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
    { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
    { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
    { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
    { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
    { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
    { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
    { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
    { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
    { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
    { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
    { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
    { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
    { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
    { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
    { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
    { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
    { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
  
    { "secp112r1", SEC_OID_SECG_EC_SECP112R1},
    { "secp112r2", SEC_OID_SECG_EC_SECP112R2},
    { "secp128r1", SEC_OID_SECG_EC_SECP128R1},
    { "secp128r2", SEC_OID_SECG_EC_SECP128R2},
  
    { "sect113r1", SEC_OID_SECG_EC_SECT113R1},
    { "sect113r2", SEC_OID_SECG_EC_SECT113R2},
    { "sect131r1", SEC_OID_SECG_EC_SECT131R1},
    { "sect131r2", SEC_OID_SECG_EC_SECT131R2},
  };
  
  static SECItem * 
  getECParams(const char *curve)
  {
      SECItem *ecparams;
      SECOidData *oidData = NULL;
      SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
      int i, numCurves;
  
      if (curve != NULL) {
          numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
  	for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN)); 
  	     i++) {
  	    if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
  	        curveOidTag = nameTagPair[i].curveOidTag;
  	}
      }
  
      /* Return NULL if curve name is not recognized */
      if ((curveOidTag == SEC_OID_UNKNOWN) || 
  	(oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
          fprintf(stderr, "Unrecognized elliptic curve %s\n", curve);
  	return NULL;
      }
  
      ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
  
      /* 
       * ecparams->data needs to contain the ASN encoding of an object ID (OID)
       * representing the named curve. The actual OID is in 
       * oidData->oid.data so we simply prepend 0x06 and OID length
       */
      ecparams->data[0] = SEC_ASN1_OBJECT_ID;
      ecparams->data[1] = oidData->oid.len;
      memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
  
      return ecparams;
  }
  
  /*
   * Perform the ECDSA Key Pair Generation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  ecdsa_keypair_test(char *reqfn)
  {
      char buf[256];      /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * needs to be large enough to hold the longest
                           * line "Qx = <144 hex digits>\n".
                           */
      FILE *ecdsareq;     /* input stream from the REQUEST file */
      FILE *ecdsaresp;    /* output stream to the RESPONSE file */
      char curve[16];     /* "nistxddd" */
      ECParams *ecparams;
      int N;
      int i;
      unsigned int len;
  
      ecdsareq = fopen(reqfn, "r");
      ecdsaresp = stdout;
      strcpy(curve, "nist");
      while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* [X-ddd] */
  	if (buf[0] == '[') {
  	    const char *src;
  	    char *dst;
  	    SECItem *encodedparams;
  
  	    src = &buf[1];
  	    dst = &curve[4];
  	    *dst++ = tolower(*src);
  	    src += 2;  /* skip the hyphen */
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst = '\0';
  	    encodedparams = getECParams(curve);
  	    if (encodedparams == NULL) {
  		goto loser;
  	    }
  	    if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
  		goto loser;
  	    }
  	    SECITEM_FreeItem(encodedparams, PR_TRUE);
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* N = x */
  	if (buf[0] == 'N') {
  	    if (sscanf(buf, "N = %d", &N) != 1) {
  		goto loser;
  	    }
  	    for (i = 0; i < N; i++) {
  		ECPrivateKey *ecpriv;
  
  		if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
  		    goto loser;
  		}
  		fputs("d = ", ecdsaresp);
  		to_hex_str(buf, ecpriv->privateValue.data,
  			   ecpriv->privateValue.len);
  		fputs(buf, ecdsaresp);
  		fputc('\n', ecdsaresp);
  		if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
  		    != SECSuccess) {
  		    goto loser;
  		}
  		len = ecpriv->publicValue.len;
  		if (len%2 == 0) {
  		    goto loser;
  		}
  		len = (len-1)/2;
  		if (ecpriv->publicValue.data[0]
  		    != EC_POINT_FORM_UNCOMPRESSED) {
  		    goto loser;
  		}
  		fputs("Qx = ", ecdsaresp);
  		to_hex_str(buf, &ecpriv->publicValue.data[1], len);
  		fputs(buf, ecdsaresp);
  		fputc('\n', ecdsaresp);
  		fputs("Qy = ", ecdsaresp);
  		to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
  		fputs(buf, ecdsaresp);
  		fputc('\n', ecdsaresp);
  		fputc('\n', ecdsaresp);
  		PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
  	    }
  	    PORT_FreeArena(ecparams->arena, PR_FALSE);
  	    continue;
  	}
      }
  loser:
      fclose(ecdsareq);
  }
  
  /*
   * Perform the ECDSA Public Key Validation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  ecdsa_pkv_test(char *reqfn)
  {
      char buf[256];      /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "Qx = <144 hex digits>\n".
                           */
      FILE *ecdsareq;     /* input stream from the REQUEST file */
      FILE *ecdsaresp;    /* output stream to the RESPONSE file */
      char curve[16];     /* "nistxddd" */
      ECParams *ecparams = NULL;
      SECItem pubkey;
      unsigned int i;
      unsigned int len;
      PRBool keyvalid = PR_TRUE;
  
      ecdsareq = fopen(reqfn, "r");
      ecdsaresp = stdout;
      strcpy(curve, "nist");
      pubkey.data = NULL;
      while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* [X-ddd] */
  	if (buf[0] == '[') {
  	    const char *src;
  	    char *dst;
  	    SECItem *encodedparams;
  
  	    src = &buf[1];
  	    dst = &curve[4];
  	    *dst++ = tolower(*src);
  	    src += 2;  /* skip the hyphen */
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst = '\0';
  	    if (ecparams != NULL) {
  		PORT_FreeArena(ecparams->arena, PR_FALSE);
  		ecparams = NULL;
  	    }
  	    encodedparams = getECParams(curve);
  	    if (encodedparams == NULL) {
  		goto loser;
  	    }
  	    if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
  		goto loser;
  	    }
  	    SECITEM_FreeItem(encodedparams, PR_TRUE);
  	    len = (ecparams->fieldID.size + 7) >> 3;
  	    if (pubkey.data != NULL) {
  		PORT_Free(pubkey.data);
  		pubkey.data = NULL;
  	    }
  	    SECITEM_AllocItem(NULL, &pubkey, 2*len+1);
  	    if (pubkey.data == NULL) {
  		goto loser;
  	    }
  	    pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* Qx = ... */
  	if (strncmp(buf, "Qx", 2) == 0) {
  	    fputs(buf, ecdsaresp);
  	    i = 2;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    keyvalid = from_hex_str(&pubkey.data[1], len, &buf[i]);
  	    continue;
  	}
  	/* Qy = ... */
  	if (strncmp(buf, "Qy", 2) == 0) {
  	    fputs(buf, ecdsaresp);
  	    if (!keyvalid) {
  		fputs("Result = F\n", ecdsaresp);
  		continue;
  	    }
  	    i = 2;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    keyvalid = from_hex_str(&pubkey.data[1+len], len, &buf[i]);
  	    if (!keyvalid) {
  		fputs("Result = F\n", ecdsaresp);
  		continue;
  	    }
  	    if (EC_ValidatePublicKey(ecparams, &pubkey) == SECSuccess) {
  		fputs("Result = P\n", ecdsaresp);
  	    } else if (PORT_GetError() == SEC_ERROR_BAD_KEY) {
  		fputs("Result = F\n", ecdsaresp);
  	    } else {
  		goto loser;
  	    }
  	    continue;
  	}
      }
  loser:
      if (ecparams != NULL) {
  	PORT_FreeArena(ecparams->arena, PR_FALSE);
      }
      if (pubkey.data != NULL) {
  	PORT_Free(pubkey.data);
      }
      fclose(ecdsareq);
  }
  
  /*
   * Perform the ECDSA Signature Generation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  ecdsa_siggen_test(char *reqfn)
  {
      char buf[1024];     /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * needs to be large enough to hold the longest
                           * line "Msg = <256 hex digits>\n".
                           */
      FILE *ecdsareq;     /* input stream from the REQUEST file */
      FILE *ecdsaresp;    /* output stream to the RESPONSE file */
      char curve[16];     /* "nistxddd" */
      ECParams *ecparams = NULL;
      int i, j;
      unsigned int len;
      unsigned char msg[512];  /* message to be signed (<= 128 bytes) */
      unsigned int msglen;
      unsigned char sha1[20];  /* SHA-1 hash (160 bits) */
      unsigned char sig[2*MAX_ECKEY_LEN];
      SECItem signature, digest;
  
      ecdsareq = fopen(reqfn, "r");
      ecdsaresp = stdout;
      strcpy(curve, "nist");
      while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* [X-ddd] */
  	if (buf[0] == '[') {
  	    const char *src;
  	    char *dst;
  	    SECItem *encodedparams;
  
  	    src = &buf[1];
  	    dst = &curve[4];
  	    *dst++ = tolower(*src);
  	    src += 2;  /* skip the hyphen */
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst = '\0';
  	    if (ecparams != NULL) {
  		PORT_FreeArena(ecparams->arena, PR_FALSE);
  		ecparams = NULL;
  	    }
  	    encodedparams = getECParams(curve);
  	    if (encodedparams == NULL) {
  		goto loser;
  	    }
  	    if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
  		goto loser;
  	    }
  	    SECITEM_FreeItem(encodedparams, PR_TRUE);
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* Msg = ... */
  	if (strncmp(buf, "Msg", 3) == 0) {
  	    ECPrivateKey *ecpriv;
  
  	    i = 3;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &msg[j]);
  	    }
  	    msglen = j;
  	    if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
  		goto loser;
  	    }
  	    fputs(buf, ecdsaresp);
  
  	    if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) {
  		goto loser;
  	    }
  	    if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue)
  		!= SECSuccess) {
  		goto loser;
  	    }
  	    len = ecpriv->publicValue.len;
  	    if (len%2 == 0) {
  		goto loser;
  	    }
  	    len = (len-1)/2;
  	    if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
  		goto loser;
  	    }
  	    fputs("Qx = ", ecdsaresp);
  	    to_hex_str(buf, &ecpriv->publicValue.data[1], len);
  	    fputs(buf, ecdsaresp);
  	    fputc('\n', ecdsaresp);
  	    fputs("Qy = ", ecdsaresp);
  	    to_hex_str(buf, &ecpriv->publicValue.data[1+len], len);
  	    fputs(buf, ecdsaresp);
  	    fputc('\n', ecdsaresp);
  
  	    digest.type = siBuffer;
  	    digest.data = sha1;
  	    digest.len = sizeof sha1;
  	    signature.type = siBuffer;
  	    signature.data = sig;
  	    signature.len = sizeof sig;
  	    if (ECDSA_SignDigest(ecpriv, &signature, &digest) != SECSuccess) {
  		goto loser;
  	    }
  	    len = signature.len;
  	    if (len%2 != 0) {
  		goto loser;
  	    }
  	    len = len/2;
  	    fputs("R = ", ecdsaresp);
  	    to_hex_str(buf, &signature.data[0], len);
  	    fputs(buf, ecdsaresp);
  	    fputc('\n', ecdsaresp);
  	    fputs("S = ", ecdsaresp);
  	    to_hex_str(buf, &signature.data[len], len);
  	    fputs(buf, ecdsaresp);
  	    fputc('\n', ecdsaresp);
  
  	    PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
  	    continue;
  	}
      }
  loser:
      if (ecparams != NULL) {
  	PORT_FreeArena(ecparams->arena, PR_FALSE);
      }
      fclose(ecdsareq);
  }
  
  /*
   * Perform the ECDSA Signature Verification Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  ecdsa_sigver_test(char *reqfn)
  {
      char buf[1024];     /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "Msg = <256 hex digits>\n".
                           */
      FILE *ecdsareq;     /* input stream from the REQUEST file */
      FILE *ecdsaresp;    /* output stream to the RESPONSE file */
      char curve[16];     /* "nistxddd" */
      ECPublicKey ecpub;
      unsigned int i, j;
      unsigned int flen;  /* length in bytes of the field size */
      unsigned int olen;  /* length in bytes of the base point order */
      unsigned char msg[512];  /* message that was signed (<= 128 bytes) */
      unsigned int msglen;
      unsigned char sha1[20];  /* SHA-1 hash (160 bits) */
      unsigned char sig[2*MAX_ECKEY_LEN];
      SECItem signature, digest;
      PRBool keyvalid = PR_TRUE;
      PRBool sigvalid = PR_TRUE;
  
      ecdsareq = fopen(reqfn, "r");
      ecdsaresp = stdout;
      ecpub.ecParams.arena = NULL;
      strcpy(curve, "nist");
      while (fgets(buf, sizeof buf, ecdsareq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* [X-ddd] */
  	if (buf[0] == '[') {
  	    const char *src;
  	    char *dst;
  	    SECItem *encodedparams;
  	    ECParams *ecparams;
  
  	    src = &buf[1];
  	    dst = &curve[4];
  	    *dst++ = tolower(*src);
  	    src += 2;  /* skip the hyphen */
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst++ = *src++;
  	    *dst = '\0';
  	    encodedparams = getECParams(curve);
  	    if (encodedparams == NULL) {
  		goto loser;
  	    }
  	    if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
  		goto loser;
  	    }
  	    SECITEM_FreeItem(encodedparams, PR_TRUE);
  	    if (ecpub.ecParams.arena != NULL) {
  		PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
  	    }
  	    ecpub.ecParams.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  	    if (ecpub.ecParams.arena == NULL) {
  		goto loser;
  	    }
  	    if (EC_CopyParams(ecpub.ecParams.arena, &ecpub.ecParams, ecparams)
  		!= SECSuccess) {
  		goto loser;
  	    }
  	    PORT_FreeArena(ecparams->arena, PR_FALSE);
  	    flen = (ecpub.ecParams.fieldID.size + 7) >> 3;
  	    olen = ecpub.ecParams.order.len;
  	    if (2*olen > sizeof sig) {
  		goto loser;
  	    }
  	    ecpub.publicValue.type = siBuffer;
  	    ecpub.publicValue.data = NULL;
  	    ecpub.publicValue.len = 0;
  	    SECITEM_AllocItem(ecpub.ecParams.arena,
  			      &ecpub.publicValue, 2*flen+1);
  	    if (ecpub.publicValue.data == NULL) {
  		goto loser;
  	    }
  	    ecpub.publicValue.data[0] = EC_POINT_FORM_UNCOMPRESSED;
  	    fputs(buf, ecdsaresp);
  	    continue;
  	}
  	/* Msg = ... */
  	if (strncmp(buf, "Msg", 3) == 0) {
  	    i = 3;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
  		hex_to_byteval(&buf[i], &msg[j]);
  	    }
  	    msglen = j;
  	    if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) {
  		goto loser;
  	    }
  	    fputs(buf, ecdsaresp);
  
  	    digest.type = siBuffer;
  	    digest.data = sha1;
  	    digest.len = sizeof sha1;
  
  	    continue;
  	}
  	/* Qx = ... */
  	if (strncmp(buf, "Qx", 2) == 0) {
  	    fputs(buf, ecdsaresp);
  	    i = 2;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    keyvalid = from_hex_str(&ecpub.publicValue.data[1], flen,
  				    &buf[i]);
  	    continue;
  	}
  	/* Qy = ... */
  	if (strncmp(buf, "Qy", 2) == 0) {
  	    fputs(buf, ecdsaresp);
  	    if (!keyvalid) {
  		continue;
  	    }
  	    i = 2;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    keyvalid = from_hex_str(&ecpub.publicValue.data[1+flen], flen,
  				    &buf[i]);
  	    if (!keyvalid) {
  		continue;
  	    }
  	    if (EC_ValidatePublicKey(&ecpub.ecParams, &ecpub.publicValue)
  		!= SECSuccess) {
  		if (PORT_GetError() == SEC_ERROR_BAD_KEY) {
  		    keyvalid = PR_FALSE;
  		} else {
  		    goto loser;
  		}
  	    }
  	    continue;
  	}
  	/* R = ... */
  	if (buf[0] == 'R') {
  	    fputs(buf, ecdsaresp);
  	    i = 1;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    sigvalid = from_hex_str(sig, olen, &buf[i]);
  	    continue;
  	}
  	/* S = ... */
  	if (buf[0] == 'S') {
  	    fputs(buf, ecdsaresp);
  	    i = 1;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    if (sigvalid) {
  		sigvalid = from_hex_str(&sig[olen], olen, &buf[i]);
  	    }
  	    signature.type = siBuffer;
  	    signature.data = sig;
  	    signature.len = 2*olen;
  
  	    if (!keyvalid || !sigvalid) {
  		fputs("Result = F\n", ecdsaresp);
  	    } else if (ECDSA_VerifyDigest(&ecpub, &signature, &digest)
  		== SECSuccess) {
  		fputs("Result = P\n", ecdsaresp);
  	    } else {
  		fputs("Result = F\n", ecdsaresp);
  	    }
  	    continue;
  	}
      }
  loser:
      if (ecpub.ecParams.arena != NULL) {
  	PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
      }
      fclose(ecdsareq);
  }
  #endif /* NSS_DISABLE_ECC */
  
  
  /*
   * Read a value from the test and allocate the result.
   */
  static unsigned char *
  alloc_value(char *buf, int *len)
  {
      unsigned char * value;
      int i, count;
  
      if (strncmp(buf, "<None>", 6) == 0) {
  	*len = 0;
  	return NULL;
      }
  
      /* find the length of the number */
      for (count = 0; isxdigit(buf[count]); count++);
      *len = count/2;
  
      if (*len == 0) {
  	return NULL;
      }
  
      value = PORT_Alloc(*len);
      if (!value) {
  	*len = 0;
  	return NULL;
      }
  	
      for (i=0; i<*len; buf+=2 , i++) {
  	hex_to_byteval(buf, &value[i]);
      }
      
  
      return value;
  }
  
  PRBool
  isblankline(char *b)
  {
     while (isspace(*b)) b++;
     if ((*b == '\n') || (*b == 0)) {
  	return PR_TRUE;
     }
     return PR_FALSE;
  }
  
  static int debug = 0;
  
  /*
   * Perform the Hash_DRBG (CAVS) for the RNG algorithm
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  drbg(char *reqfn)
  {
      char buf[2000];   /* test case has some very long lines, returned bits
       * as high as 800 bytes (6400 bits). That 1600 byte
       * plus a tag */
      char buf2[2000]; 
      FILE *rngreq;       /* input stream from the REQUEST file */
      FILE *rngresp;      /* output stream to the RESPONSE file */
      
      unsigned int i, j;
      PRBool predictionResistance = PR_FALSE;
      unsigned char *nonce =  NULL;
      int nonceLen = 0;
      unsigned char *personalizationString =  NULL;
      int personalizationStringLen = 0;
      unsigned char *additionalInput =  NULL;
      int additionalInputLen = 0;
      unsigned char *entropyInput = NULL;
      int entropyInputLen = 0;
      unsigned char predictedreturn_bytes[SHA256_LENGTH];
      unsigned char return_bytes[SHA256_LENGTH];
      int return_bytes_len = SHA256_LENGTH;
      enum { NONE, INSTANTIATE, GENERATE, RESEED, RESULT } command =
      NONE;
      PRBool genResult = PR_FALSE;
      SECStatus rv;
      
      rngreq = fopen(reqfn, "r");
      rngresp = stdout;
      while (fgets(buf, sizeof buf, rngreq) != NULL) {
         switch (command) {
              case INSTANTIATE:
  		if (debug) {
  		    fputs("# PRNGTEST_Instantiate(",rngresp);
  		    to_hex_str(buf2,entropyInput, entropyInputLen);
  		    fputs(buf2,rngresp);
  		    fprintf(rngresp,",%d,",entropyInputLen);
  		    to_hex_str(buf2,nonce, nonceLen);
  		    fputs(buf2,rngresp);
  		    fprintf(rngresp,",%d,",nonceLen);
  		    to_hex_str(buf2,personalizationString, 
  					personalizationStringLen);
  		    fputs(buf2,rngresp);
  		    fprintf(rngresp,",%d)\n", personalizationStringLen);
  		}
                  rv = PRNGTEST_Instantiate(entropyInput, entropyInputLen,
                                            nonce, nonceLen,
                                            personalizationString, 
  				          personalizationStringLen);
                  if (rv != SECSuccess) {
                      goto loser;
                  }
                  break;
                      
              case GENERATE:
              case RESULT:
                  memset(return_bytes, 0, return_bytes_len);
  		if (debug) {
  		    fputs("# PRNGTEST_Generate(returnbytes",rngresp);
  		    fprintf(rngresp,",%d,", return_bytes_len);
  		    to_hex_str(buf2,additionalInput, additionalInputLen);
  		    fputs(buf2,rngresp);
  		    fprintf(rngresp,",%d)\n",additionalInputLen);
  		}
                  rv = PRNGTEST_Generate((PRUint8 *) return_bytes, 
  					return_bytes_len,
                                         (PRUint8 *) additionalInput, 
  					additionalInputLen);
                  if (rv != SECSuccess) {
                      goto loser;
                  }
                      
                  if (command == RESULT) {
                      fputs("ReturnedBits = ", rngresp);
                      to_hex_str(buf2, return_bytes, return_bytes_len);
                      fputs(buf2, rngresp);
                      fputc('\n', rngresp);
  		    if (debug) {
  			fputs("# PRNGTEST_Uninstantiate()\n",rngresp);
  		    }
                      rv = PRNGTEST_Uninstantiate();
                      if (rv != SECSuccess) {
                          goto loser;
                      }
                  } else if (debug) {
                      fputs("#ReturnedBits = ", rngresp);
                      to_hex_str(buf2, return_bytes, return_bytes_len);
                      fputs(buf2, rngresp);
                      fputc('\n', rngresp);
  		}
                      
                  memset(additionalInput, 0, additionalInputLen);
                  break;
                      
              case RESEED:
                  if (entropyInput || additionalInput) {
  		    if (debug) {
  			fputs("# PRNGTEST_Reseed(",rngresp);
  			fprintf(rngresp,",%d,", return_bytes_len);
  			to_hex_str(buf2,entropyInput, entropyInputLen);
  			fputs(buf2,rngresp);
  			fprintf(rngresp,",%d,", entropyInputLen);
  			to_hex_str(buf2,additionalInput, additionalInputLen);
  			fputs(buf2,rngresp);
  			fprintf(rngresp,",%d)\n",additionalInputLen);
  		    }	
                      rv = PRNGTEST_Reseed(entropyInput, entropyInputLen,
                                               additionalInput, additionalInputLen);
                      if (rv != SECSuccess) {
                          goto loser;
                      }
                  }
                  memset(entropyInput, 0, entropyInputLen);
                  memset(additionalInput, 0, additionalInputLen);
                  break;
              case NONE:
                  break;
                      
          } 
          command = NONE;
          
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r' ) {
              fputs(buf, rngresp);
              continue;
          }
          
          /* [Hash - SHA256] */
          if (strncmp(buf, "[SHA-256]", 9) == 0) {
              fputs(buf, rngresp);
              continue;
          }
          
          if (strncmp(buf, "[PredictionResistance", 21)  == 0) {
              i = 21;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }    
              if (strncmp(buf, "False", 5) == 0) {
                  predictionResistance = PR_FALSE;
              } else {
                  predictionResistance = PR_TRUE;
              }
              
              fputs(buf, rngresp);
              continue;
          }
          
          if (strncmp(buf, "[EntropyInputLen", 16)  == 0) {
              if (entropyInput) {
                  PORT_ZFree(entropyInput, entropyInputLen);
                  entropyInput = NULL;
                  entropyInputLen = 0;
              }
              if (sscanf(buf, "[EntropyInputLen = %d]", &entropyInputLen) != 1) {
                  goto loser;
              }
  	    entropyInputLen = entropyInputLen/8;
              if (entropyInputLen > 0) {
                  entropyInput = PORT_Alloc(entropyInputLen);
              }
              fputs(buf, rngresp);
              continue;
          }
          
          if (strncmp(buf, "[NonceLen", 9)  == 0) {
              if (nonce) {
                  PORT_ZFree(nonce, nonceLen);
                  nonce = NULL;
                  nonceLen = 0;
              }
              
              if (sscanf(buf, "[NonceLen = %d]", &nonceLen) != 1) {
                  goto loser;
              }
  	    nonceLen = nonceLen/8;
              if (nonceLen > 0) {
                  nonce = PORT_Alloc(nonceLen);
              }               
              fputs(buf, rngresp);
              continue;
          }
          
          if (strncmp(buf, "[PersonalizationStringLen", 16)  == 0) {
              if (personalizationString) {
                  PORT_ZFree(personalizationString, personalizationStringLen);
                  personalizationString = NULL;
                  personalizationStringLen = 0;
              }
              
              if (sscanf(buf, "[PersonalizationStringLen = %d]", &personalizationStringLen) != 1) {
                  goto loser;
              }
  	    personalizationStringLen = personalizationStringLen / 8;
              if (personalizationStringLen > 0) {
                  personalizationString = PORT_Alloc(personalizationStringLen);
              }
              fputs(buf, rngresp);
              
              continue;
          }
          
          if (strncmp(buf, "[AdditionalInputLen", 16)  == 0) {
              if (additionalInput) {
                  PORT_ZFree(additionalInput, additionalInputLen);
                  additionalInput = NULL;
                  additionalInputLen = 0;
              }
              
              if (sscanf(buf, "[AdditionalInputLen = %d]", &additionalInputLen) != 1) {
                  goto loser;
              }
  	    additionalInputLen = additionalInputLen/8;
              if (additionalInputLen > 0) {
                  additionalInput = PORT_Alloc(additionalInputLen);
              }
              fputs(buf, rngresp);
              continue;
          }
          
          if (strncmp(buf, "COUNT", 5) == 0) {
              /* zeroize the variables for the test with this data set */
              if (entropyInput) {
                  memset(entropyInput, 0, entropyInputLen);
              }
              if (nonce) {
                  memset(nonce, 0, nonceLen);        
              }
              if (personalizationString) {
                  memset(personalizationString, 0, personalizationStringLen);
              }
              if (additionalInput) {
                  memset(additionalInput, 0, additionalInputLen);
              }
              genResult = PR_FALSE;
              
              fputs(buf, rngresp);
              continue;
          }
          
          /* EntropyInputReseed = ... */
          if (strncmp(buf, "EntropyInputReseed", 18) == 0) {
              if (entropyInput) {
                  memset(entropyInput, 0, entropyInputLen);
                  i = 18;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }            
                  
                  for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<entropyInputLen*/
                      hex_to_byteval(&buf[i], &entropyInput[j]);
                  }           
              }
              fputs(buf, rngresp);
              continue;
          }
          
          /* AttionalInputReseed  = ... */
          if (strncmp(buf, "AdditionalInputReseed", 21) == 0) {
              if (additionalInput) {
                  memset(additionalInput, 0, additionalInputLen);
                  i = 21;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/
                      hex_to_byteval(&buf[i], &additionalInput[j]);
                  }    
              }
              command = RESEED;
              fputs(buf, rngresp);
              continue;
          }
          
          /* Entropy input = ... */
          if (strncmp(buf, "EntropyInput", 12) == 0) {
              i = 12;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<entropyInputLen*/
                  hex_to_byteval(&buf[i], &entropyInput[j]);
              }  
              fputs(buf, rngresp);
              continue;
          }
          
          /* nouce = ... */
          if (strncmp(buf, "Nonce", 5) == 0) {
              i = 5;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<nonceLen*/
                  hex_to_byteval(&buf[i], &nonce[j]);
              }  
              fputs(buf, rngresp);
              continue;
          }
          
          /* Personalization string = ... */
          if (strncmp(buf, "PersonalizationString", 21) == 0) {
              if (personalizationString) {
                  i = 21;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<personalizationStringLen*/
                      hex_to_byteval(&buf[i], &personalizationString[j]);
                  }
              }
              fputs(buf, rngresp);
              command = INSTANTIATE;
              continue;
          }
          
          /* Additional input = ... */
          if (strncmp(buf, "AdditionalInput", 15) == 0) {
              if (additionalInput) {
                  i = 15;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/
                      hex_to_byteval(&buf[i], &additionalInput[j]);
                  } 
              }
              if (genResult) {
                  command = RESULT;
              } else {
                  command = GENERATE;
                  genResult = PR_TRUE; /* next time generate result */
              }
              fputs(buf, rngresp);
              continue;
          }
          
          /* Returned bits = ... */
          if (strncmp(buf, "ReturnedBits", 12) == 0) {
              i = 12;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/
                  hex_to_byteval(&buf[i], &predictedreturn_bytes[j]);
              }          
  
              if (memcmp(return_bytes, 
                         predictedreturn_bytes, return_bytes_len) != 0) {
  		if (debug) {
                  fprintf(rngresp, "# Generate failed:\n");
                  fputs(  "#   predicted=", rngresp);
                  to_hex_str(buf, predictedreturn_bytes, 
                             return_bytes_len);
                  fputs(buf, rngresp);
                  fputs("\n#   actual  = ", rngresp);
                  fputs(buf2, rngresp);
                  fputc('\n', rngresp);
  
  		} else {
                  fprintf(stderr, "Generate failed:\n");
                  fputs(  "   predicted=", stderr);
                  to_hex_str(buf, predictedreturn_bytes, 
                             return_bytes_len);
                  fputs(buf, stderr);
                  fputs("\n   actual  = ", stderr);
                  fputs(buf2, stderr);
                  fputc('\n', stderr);
  		}
              }
              memset(predictedreturn_bytes, 0 , sizeof predictedreturn_bytes);
  
              continue;
          }
      }
  loser:
      fclose(rngreq);
  }
  
  /*
   * Perform the RNG Variable Seed Test (VST) for the RNG algorithm
   * "DSA - Generation of X", used both as specified and as a generic
   * purpose RNG.  The presence of "Q = ..." in the REQUEST file
   * indicates we are using the algorithm as specified.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  rng_vst(char *reqfn)
  {
      char buf[256];      /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "XSeed = <128 hex digits>\n".
                           */
      FILE *rngreq;       /* input stream from the REQUEST file */
      FILE *rngresp;      /* output stream to the RESPONSE file */
      unsigned int i, j;
      unsigned char Q[DSA1_SUBPRIME_LEN];
      PRBool hasQ = PR_FALSE;
      unsigned int b;  /* 160 <= b <= 512, b is a multiple of 8 */
      unsigned char XKey[512/8];
      unsigned char XSeed[512/8];
      unsigned char GENX[DSA1_SIGNATURE_LEN];
      unsigned char DSAX[DSA1_SUBPRIME_LEN];
      SECStatus rv;
  
      rngreq = fopen(reqfn, "r");
      rngresp = stdout;
      while (fgets(buf, sizeof buf, rngreq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* [Xchange - SHA1] */
  	if (buf[0] == '[') {
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* Q = ... */
  	if (buf[0] == 'Q') {
  	    i = 1;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<sizeof Q; i+=2,j++) {
  		hex_to_byteval(&buf[i], &Q[j]);
  	    }
  	    fputs(buf, rngresp);
  	    hasQ = PR_TRUE;
  	    continue;
  	}
  	/* "COUNT = x" begins a new data set */
  	if (strncmp(buf, "COUNT", 5) == 0) {
  	    /* zeroize the variables for the test with this data set */
  	    b = 0;
  	    memset(XKey, 0, sizeof XKey);
  	    memset(XSeed, 0, sizeof XSeed);
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* b = ... */
  	if (buf[0] == 'b') {
  	    i = 1;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    b = atoi(&buf[i]);
  	    if (b < 160 || b > 512 || b%8 != 0) {
  		goto loser;
  	    }
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* XKey = ... */
  	if (strncmp(buf, "XKey", 4) == 0) {
  	    i = 4;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<b/8; i+=2,j++) {
  		hex_to_byteval(&buf[i], &XKey[j]);
  	    }
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* XSeed = ... */
  	if (strncmp(buf, "XSeed", 5) == 0) {
  	    i = 5;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<b/8; i+=2,j++) {
  		hex_to_byteval(&buf[i], &XSeed[j]);
  	    }
  	    fputs(buf, rngresp);
  
  	    rv = FIPS186Change_GenerateX(XKey, XSeed, GENX);
  	    if (rv != SECSuccess) {
  		goto loser;
  	    }
  	    fputs("X = ", rngresp);
  	    if (hasQ) {
  		rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
  		if (rv != SECSuccess) {
  		    goto loser;
  		}
  		to_hex_str(buf, DSAX, sizeof DSAX);
  	    } else {
  		to_hex_str(buf, GENX, sizeof GENX);
  	    }
  	    fputs(buf, rngresp);
  	    fputc('\n', rngresp);
  	    continue;
  	}
      }
  loser:
      fclose(rngreq);
  }
  
  /*
   * Perform the RNG Monte Carlo Test (MCT) for the RNG algorithm
   * "DSA - Generation of X", used both as specified and as a generic
   * purpose RNG.  The presence of "Q = ..." in the REQUEST file
   * indicates we are using the algorithm as specified.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  rng_mct(char *reqfn)
  {
      char buf[256];      /* holds one line from the input REQUEST file.
                           * needs to be large enough to hold the longest
                           * line "XSeed = <128 hex digits>\n".
                           */
      FILE *rngreq;       /* input stream from the REQUEST file */
      FILE *rngresp;      /* output stream to the RESPONSE file */
      unsigned int i, j;
      unsigned char Q[DSA1_SUBPRIME_LEN];
      PRBool hasQ = PR_FALSE;
      unsigned int b;  /* 160 <= b <= 512, b is a multiple of 8 */
      unsigned char XKey[512/8];
      unsigned char XSeed[512/8];
      unsigned char GENX[2*SHA1_LENGTH];
      unsigned char DSAX[DSA1_SUBPRIME_LEN];
      SECStatus rv;
  
      rngreq = fopen(reqfn, "r");
      rngresp = stdout;
      while (fgets(buf, sizeof buf, rngreq) != NULL) {
  	/* a comment or blank line */
  	if (buf[0] == '#' || buf[0] == '\n') {
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* [Xchange - SHA1] */
  	if (buf[0] == '[') {
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* Q = ... */
  	if (buf[0] == 'Q') {
  	    i = 1;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<sizeof Q; i+=2,j++) {
  		hex_to_byteval(&buf[i], &Q[j]);
  	    }
  	    fputs(buf, rngresp);
  	    hasQ = PR_TRUE;
  	    continue;
  	}
  	/* "COUNT = x" begins a new data set */
  	if (strncmp(buf, "COUNT", 5) == 0) {
  	    /* zeroize the variables for the test with this data set */
  	    b = 0;
  	    memset(XKey, 0, sizeof XKey);
  	    memset(XSeed, 0, sizeof XSeed);
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* b = ... */
  	if (buf[0] == 'b') {
  	    i = 1;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    b = atoi(&buf[i]);
  	    if (b < 160 || b > 512 || b%8 != 0) {
  		goto loser;
  	    }
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* XKey = ... */
  	if (strncmp(buf, "XKey", 4) == 0) {
  	    i = 4;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<b/8; i+=2,j++) {
  		hex_to_byteval(&buf[i], &XKey[j]);
  	    }
  	    fputs(buf, rngresp);
  	    continue;
  	}
  	/* XSeed = ... */
  	if (strncmp(buf, "XSeed", 5) == 0) {
  	    unsigned int k;
  	    i = 5;
  	    while (isspace(buf[i]) || buf[i] == '=') {
  		i++;
  	    }
  	    for (j=0; j<b/8; i+=2,j++) {
  		hex_to_byteval(&buf[i], &XSeed[j]);
  	    }
  	    fputs(buf, rngresp);
  
  	    for (k = 0; k < 10000; k++) {
  		rv = FIPS186Change_GenerateX(XKey, XSeed, GENX);
  		if (rv != SECSuccess) {
  		    goto loser;
  		}
  	    }
  	    fputs("X = ", rngresp);
  	    if (hasQ) {
  		rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
  		if (rv != SECSuccess) {
  		    goto loser;
  		}
  		to_hex_str(buf, DSAX, sizeof DSAX);
  	    } else {
  		to_hex_str(buf, GENX, sizeof GENX);
  	    }
  	    fputs(buf, rngresp);
  	    fputc('\n', rngresp);
  	    continue;
  	}
      }
  loser:
      fclose(rngreq);
  }
  
  /*
   * HASH_ functions are available to full NSS apps and internally inside
   * freebl, but not exported to users of freebl. Create short stubs to
   * replace the functionality for fipstest.
   */
  SECStatus
  fips_hashBuf(HASH_HashType type, unsigned char *hashBuf, 
  					unsigned char *msg, int len)
  {
      SECStatus rv = SECFailure;
  
      switch (type) {
      case HASH_AlgSHA1:
  	rv = SHA1_HashBuf(hashBuf, msg, len);
  	break;
      case HASH_AlgSHA224:
  	rv = SHA224_HashBuf(hashBuf, msg, len);
  	break;
      case HASH_AlgSHA256:
  	rv = SHA256_HashBuf(hashBuf, msg, len);
  	break;
      case HASH_AlgSHA384:
  	rv = SHA384_HashBuf(hashBuf, msg, len);
  	break;
      case HASH_AlgSHA512:
  	rv = SHA512_HashBuf(hashBuf, msg, len);
  	break;
      default:
  	break;
      }
      return rv;
  }
  
  int
  fips_hashLen(HASH_HashType type)
  {
      int len = 0;
  
      switch (type) {
      case HASH_AlgSHA1:
  	len = SHA1_LENGTH;
  	break;
      case HASH_AlgSHA224:
  	len = SHA224_LENGTH;
  	break;
      case HASH_AlgSHA256:
  	len = SHA256_LENGTH;
  	break;
      case HASH_AlgSHA384:
  	len = SHA384_LENGTH;
  	break;
      case HASH_AlgSHA512:
  	len = SHA512_LENGTH;
  	break;
      default:
  	break;
      }
      return len;
  }
  
  SECOidTag
  fips_hashOid(HASH_HashType type)
  {
      SECOidTag oid = SEC_OID_UNKNOWN;
  
      switch (type) {
      case HASH_AlgSHA1:
  	oid = SEC_OID_SHA1;
  	break;
      case HASH_AlgSHA224:
  	oid = SEC_OID_SHA224;
  	break;
      case HASH_AlgSHA256:
  	oid = SEC_OID_SHA256;
  	break;
      case HASH_AlgSHA384:
  	oid = SEC_OID_SHA384;
  	break;
      case HASH_AlgSHA512:
  	oid = SEC_OID_SHA512;
  	break;
      default:
  	break;
      }
      return oid;
  }
  
  HASH_HashType
  sha_get_hashType(int hashbits)
  {
      HASH_HashType hashType = HASH_AlgNULL;
  
      switch (hashbits) {
      case 1:
      case (SHA1_LENGTH*PR_BITS_PER_BYTE):
  	hashType = HASH_AlgSHA1;
  	break;
      case (SHA224_LENGTH*PR_BITS_PER_BYTE):
  	hashType = HASH_AlgSHA224;
  	break;
      case (SHA256_LENGTH*PR_BITS_PER_BYTE):
  	hashType = HASH_AlgSHA256;
  	break;
      case (SHA384_LENGTH*PR_BITS_PER_BYTE):
  	hashType = HASH_AlgSHA384;
  	break;
      case (SHA512_LENGTH*PR_BITS_PER_BYTE):
  	hashType = HASH_AlgSHA512;
  	break;
      default:
  	break;
      }
      return hashType;
  }
  
  /*
   * Calculate the SHA Message Digest 
   *
   * MD = Message digest 
   * MDLen = length of Message Digest and SHA_Type
   * msg = message to digest 
   * msgLen = length of message to digest
   */
  SECStatus sha_calcMD(unsigned char *MD, unsigned int MDLen, unsigned char *msg, unsigned int msgLen) 
  {    
      HASH_HashType  hashType = sha_get_hashType(MDLen*PR_BITS_PER_BYTE);
  
      return fips_hashBuf(hashType, MD, msg, msgLen);
  }
  
  /*
   * Perform the SHA Monte Carlo Test
   *
   * MDLen = length of Message Digest and SHA_Type
   * seed = input seed value
   * resp = is the output response file. 
   */
  SECStatus sha_mct_test(unsigned int MDLen, unsigned char *seed, FILE *resp) 
  {
      int i, j;
      unsigned int msgLen = MDLen*3;
      unsigned char MD_i3[HASH_LENGTH_MAX];  /* MD[i-3] */
      unsigned char MD_i2[HASH_LENGTH_MAX];  /* MD[i-2] */
      unsigned char MD_i1[HASH_LENGTH_MAX];  /* MD[i-1] */
      unsigned char MD_i[HASH_LENGTH_MAX];   /* MD[i] */
      unsigned char msg[HASH_LENGTH_MAX*3];
      char buf[HASH_LENGTH_MAX*2 + 1];  /* MAX buf MD_i as a hex string */
  
      for (j=0; j<100; j++) {
          /* MD_0 = MD_1 = MD_2 = seed */
          memcpy(MD_i3, seed, MDLen);
          memcpy(MD_i2, seed, MDLen);
          memcpy(MD_i1, seed, MDLen);
  
          for (i=3; i < 1003; i++) {
              /* Mi = MD[i-3] || MD [i-2] || MD [i-1] */
              memcpy(msg, MD_i3, MDLen);
              memcpy(&msg[MDLen], MD_i2, MDLen);
              memcpy(&msg[MDLen*2], MD_i1,MDLen); 
  
              /* MDi = SHA(Msg) */
              if (sha_calcMD(MD_i, MDLen,   
                             msg, msgLen) != SECSuccess) {
                  return SECFailure;
              }
  
              /* save MD[i-3] MD[i-2]  MD[i-1] */
              memcpy(MD_i3, MD_i2, MDLen);
              memcpy(MD_i2, MD_i1, MDLen);
              memcpy(MD_i1, MD_i, MDLen);
  
          }
  
          /* seed = MD_i */
          memcpy(seed, MD_i, MDLen);
  
          sprintf(buf, "COUNT = %d\n", j);
          fputs(buf, resp);
  
          /* output MD_i */
          fputs("MD = ", resp);
          to_hex_str(buf, MD_i, MDLen);
          fputs(buf, resp);
          fputc('\n', resp);
      }
  
      return SECSuccess;
  }
  
  /*
   * Perform the SHA Tests.
   *
   * reqfn is the pathname of the input REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void sha_test(char *reqfn) 
  {
      unsigned int i, j;
      unsigned int MDlen;   /* the length of the Message Digest in Bytes  */
      unsigned int msgLen;  /* the length of the input Message in Bytes */
      unsigned char *msg = NULL; /* holds the message to digest.*/
      size_t bufSize = 25608; /*MAX buffer size */
      char *buf = NULL;      /* holds one line from the input REQUEST file.*/
      unsigned char seed[HASH_LENGTH_MAX];   /* max size of seed 64 bytes */
      unsigned char MD[HASH_LENGTH_MAX];     /* message digest */
  
      FILE *req = NULL;  /* input stream from the REQUEST file */
      FILE *resp;        /* output stream to the RESPONSE file */
  
      buf = PORT_ZAlloc(bufSize);
      if (buf == NULL) {
          goto loser;
      }      
  
      /* zeroize the variables for the test with this data set */
      memset(seed, 0, sizeof seed);
  
      req = fopen(reqfn, "r");
      resp = stdout;
      while (fgets(buf, bufSize, req) != NULL) {
  
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, resp);
              continue;
          }
          /* [L = Length of the Message Digest and sha_type */
          if (buf[0] == '[') {
              if (strncmp(&buf[1], "L ", 1) == 0) {
                  i = 2;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  MDlen = atoi(&buf[i]);
                  fputs(buf, resp);
                  continue;
              }
          }
          /* Len = Length of the Input Message Length  ... */
          if (strncmp(buf, "Len", 3) == 0) {
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              if (msg) {
                  PORT_ZFree(msg,msgLen);
                  msg = NULL;
              }
              msgLen = atoi(&buf[i]); /* in bits */
              if (msgLen%8 != 0) {
                  fprintf(stderr, "SHA tests are incorrectly configured for "
                      "BIT oriented implementations\n");
                  goto loser;
              }
              msgLen = msgLen/8; /* convert to bytes */
              fputs(buf, resp);
              msg = PORT_ZAlloc(msgLen);
              if (msg == NULL && msgLen != 0) {
                  goto loser;
              } 
              continue;
          }
          /* MSG = ... */
          if (strncmp(buf, "Msg", 3) == 0) {
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< msgLen; i+=2,j++) {
                  hex_to_byteval(&buf[i], &msg[j]);
              }
             fputs(buf, resp);
             /* calculate the Message Digest */ 
             memset(MD, 0, sizeof MD);
             if (sha_calcMD(MD, MDlen,   
                            msg, msgLen) != SECSuccess) {
                 goto loser;
             }
  
             fputs("MD = ", resp);
             to_hex_str(buf, MD, MDlen);
             fputs(buf, resp);
             fputc('\n', resp);
  
             continue;
          }
          /* Seed = ... */
          if (strncmp(buf, "Seed", 4) == 0) {
              i = 4;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j<sizeof seed; i+=2,j++) {
                  hex_to_byteval(&buf[i], &seed[j]);
              }                                     
  
              fputs(buf, resp);
              fputc('\n', resp);
  
              /* do the Monte Carlo test */
              if (sha_mct_test(MDlen, seed, resp) != SECSuccess) {
                  goto loser; 
              }
  
              continue;
          }
      }
  loser:
      if (req) {
          fclose(req);
      }  
      if (buf) {
          PORT_ZFree(buf, bufSize);
      }
      if (msg) {
          PORT_ZFree(msg, msgLen);
      }
  }
  
  /****************************************************/
  /* HMAC SHA-X calc                                  */
  /* hmac_computed - the computed HMAC                */
  /* hmac_length - the length of the computed HMAC    */
  /* secret_key - secret key to HMAC                  */
  /* secret_key_length - length of secret key,        */
  /* message - message to HMAC                        */
  /* message_length - length ofthe message            */
  /****************************************************/
  static SECStatus
  hmac_calc(unsigned char *hmac_computed,
            const unsigned int hmac_length,
            const unsigned char *secret_key,
            const unsigned int secret_key_length,
            const unsigned char *message,
            const unsigned int message_length,
            const HASH_HashType hashAlg )
  {
      SECStatus hmac_status = SECFailure;
      HMACContext *cx = NULL;
      SECHashObject *hashObj = NULL;
      unsigned int bytes_hashed = 0;
  
      hashObj = (SECHashObject *) HASH_GetRawHashObject(hashAlg);
   
      if (!hashObj) 
          return( SECFailure );
  
      cx = HMAC_Create(hashObj, secret_key, 
                       secret_key_length, 
                       PR_TRUE);  /* PR_TRUE for in FIPS mode */
  
      if (cx == NULL) 
          return( SECFailure );
  
      HMAC_Begin(cx);
      HMAC_Update(cx, message, message_length);
      hmac_status = HMAC_Finish(cx, hmac_computed, &bytes_hashed, 
                                hmac_length);
  
      HMAC_Destroy(cx, PR_TRUE);
  
      return( hmac_status );
  }
  
  /*
   * Perform the HMAC Tests.
   *
   * reqfn is the pathname of the input REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void hmac_test(char *reqfn) 
  {
      unsigned int i, j;
      size_t bufSize =      400;    /* MAX buffer size */
      char *buf = NULL;  /* holds one line from the input REQUEST file.*/
      unsigned int keyLen;          /* Key Length */  
      unsigned char key[200];       /* key MAX size = 184 */
      unsigned int msgLen = 128;    /* the length of the input  */
                                    /*  Message is always 128 Bytes */
      unsigned char *msg = NULL;    /* holds the message to digest.*/
      unsigned int HMACLen;         /* the length of the HMAC Bytes  */
      unsigned int TLen;            /* the length of the requested */
                                    /* truncated HMAC Bytes */
      unsigned char HMAC[HASH_LENGTH_MAX];  /* computed HMAC */
      unsigned char expectedHMAC[HASH_LENGTH_MAX]; /* for .fax files that have */ 
                                                   /* supplied known answer */
      HASH_HashType hash_alg;       /* HMAC type */
      
  
      FILE *req = NULL;  /* input stream from the REQUEST file */
      FILE *resp;        /* output stream to the RESPONSE file */
  
      buf = PORT_ZAlloc(bufSize);
      if (buf == NULL) {
          goto loser;
      }      
      msg = PORT_ZAlloc(msgLen);
      if (msg == NULL) {
          goto loser;
      } 
  
      req = fopen(reqfn, "r");
      resp = stdout;
      while (fgets(buf, bufSize, req) != NULL) {
          if (strncmp(buf, "Mac", 3) == 0) {
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              memset(expectedHMAC, 0, HASH_LENGTH_MAX);
              for (j=0; isxdigit(buf[i]); i+=2,j++) { 
                  hex_to_byteval(&buf[i], &expectedHMAC[j]);
              }
              if (memcmp(HMAC, expectedHMAC, TLen) != 0) {
                  fprintf(stderr, "Generate failed:\n");
                  fputs(  "   expected=", stderr);
                  to_hex_str(buf, expectedHMAC, 
                             TLen);
                  fputs(buf, stderr);
                  fputs("\n   generated=", stderr);
                  to_hex_str(buf, HMAC, 
                             TLen);
                  fputs(buf, stderr);
                  fputc('\n', stderr);
              }
          }
  
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, resp);
              continue;
          }
          /* [L = Length of the MAC and HASH_type */
          if (buf[0] == '[') {
              if (strncmp(&buf[1], "L ", 1) == 0) {
                  i = 2;
                  while (isspace(buf[i]) || buf[i] == '=') {
                      i++;
                  }
                  /* HMACLen will get reused for Tlen */
                  HMACLen = atoi(&buf[i]);
  		hash_alg = sha_get_hashType(HMACLen*PR_BITS_PER_BYTE);
  		if (hash_alg == HASH_AlgNULL) {
  		    goto loser;
  		}
                  fputs(buf, resp);
                  continue;
              }
          }
          /* Count = test iteration number*/
          if (strncmp(buf, "Count ", 5) == 0) {    
              /* count can just be put into resp file */
              fputs(buf, resp);
              /* zeroize the variables for the test with this data set */
              keyLen = 0; 
              TLen = 0;
              memset(key, 0, sizeof key);     
              memset(msg, 0, msgLen);
              memset(HMAC, 0, sizeof HMAC);
              continue;
          }
          /* KLen = Length of the Input Secret Key ... */
          if (strncmp(buf, "Klen", 4) == 0) {
              i = 4;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              keyLen = atoi(&buf[i]); /* in bytes */
              fputs(buf, resp);
              continue;
          }
          /* key = the secret key for the key to MAC */
          if (strncmp(buf, "Key", 3) == 0) {
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< keyLen; i+=2,j++) {
                  hex_to_byteval(&buf[i], &key[j]);
              }
             fputs(buf, resp);
          }
          /* TLen = Length of the calculated HMAC */
          if (strncmp(buf, "Tlen", 4) == 0) {
              i = 4;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              TLen = atoi(&buf[i]); /* in bytes */
              fputs(buf, resp);
              continue;
          }
          /* MSG = to HMAC always 128 bytes for these tests */
          if (strncmp(buf, "Msg", 3) == 0) {
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< msgLen; i+=2,j++) {
                  hex_to_byteval(&buf[i], &msg[j]);
              }
             fputs(buf, resp);
             /* calculate the HMAC and output */ 
             if (hmac_calc(HMAC, HMACLen, key, keyLen,   
                           msg, msgLen, hash_alg) != SECSuccess) {
                 goto loser;
             }
             fputs("MAC = ", resp);
             to_hex_str(buf, HMAC, TLen);
             fputs(buf, resp);
             fputc('\n', resp);
             continue;
          }
      }
  loser:
      if (req) {
          fclose(req);
      }
      if (buf) {
          PORT_ZFree(buf, bufSize);
      }
      if (msg) {
          PORT_ZFree(msg, msgLen);
      }
  }
  
  /*
   * Perform the DSA Key Pair Generation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  dsa_keypair_test(char *reqfn)
  {
      char buf[800];       /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * 800 to hold (384 public key (x2 for HEX) + 1'\n'
                           */
      FILE *dsareq;     /* input stream from the REQUEST file */
      FILE *dsaresp;    /* output stream to the RESPONSE file */
      int count;
      int N;
      int L;
      int i;
      PQGParams *pqg = NULL;
      PQGVerify *vfy = NULL;
      PRBool use_dsa1 = PR_FALSE;
      int keySizeIndex;   /* index for valid key sizes */
  
      dsareq = fopen(reqfn, "r");
      dsaresp = stdout;
      while (fgets(buf, sizeof buf, dsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, dsaresp);
              continue;
          }
  
          /* [Mod = x] */
          if (buf[0] == '[') {
              if(pqg!=NULL) {
                  PQG_DestroyParams(pqg);
                  pqg = NULL;
              }
              if(vfy!=NULL) {
                  PQG_DestroyVerify(vfy);
                  vfy = NULL;
              }
  
              if (sscanf(buf, "[mod = L=%d, N=%d]", &L, &N) != 2) {
  		use_dsa1 = PR_TRUE;
                  if (sscanf(buf, "[mod = %d]", &L) != 1) {
                      goto loser;
  		}
              }
              fputs(buf, dsaresp);
              fputc('\n', dsaresp);
  
  	    if (use_dsa1) {
                  /*************************************************************
                   * PQG_ParamGenSeedLen doesn't take a key size, it takes an 
  		 * index that points to a valid key size.
                   */
                  keySizeIndex = PQG_PBITS_TO_INDEX(L);
                  if(keySizeIndex == -1 || L<512 || L>1024) {
                     fprintf(dsaresp,
                          "DSA key size must be a multiple of 64 between 512 "
                          "and 1024, inclusive");
                      goto loser;
                  }
  
                  /* Generate the parameters P, Q, and G */
                  if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
                      &pqg, &vfy) != SECSuccess) {
                      fprintf(dsaresp, 
  				"ERROR: Unable to generate PQG parameters");
                      goto loser;
                  }
  	    } else {
                  if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
                      fprintf(dsaresp, 
  				"ERROR: Unable to generate PQG parameters");
                      goto loser;
                  }
              }
  
              /* output P, Q, and G */
              to_hex_str(buf, pqg->prime.data, pqg->prime.len);
              fprintf(dsaresp, "P = %s\n", buf);
              to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
              fprintf(dsaresp, "Q = %s\n", buf);
              to_hex_str(buf, pqg->base.data, pqg->base.len);
              fprintf(dsaresp, "G = %s\n\n", buf);
              continue;
          }
          /* N = ...*/
          if (buf[0] == 'N') {
  
              if (sscanf(buf, "N = %d", &count) != 1) {
                  goto loser;
              }
              /* Generate a DSA key, and output the key pair for N times */
              for (i = 0; i < count; i++) {
                  DSAPrivateKey *dsakey = NULL;
                  if (DSA_NewKey(pqg, &dsakey) != SECSuccess) {
                      fprintf(dsaresp, "ERROR: Unable to generate DSA key");
                      goto loser;
                  }
                  to_hex_str(buf, dsakey->privateValue.data,
                             dsakey->privateValue.len);
                  fprintf(dsaresp, "X = %s\n", buf);
                  to_hex_str(buf, dsakey->publicValue.data,
                             dsakey->publicValue.len);
                  fprintf(dsaresp, "Y = %s\n\n", buf);
                  PORT_FreeArena(dsakey->params.arena, PR_TRUE);
                  dsakey = NULL;
              }
              continue;
          }
  
      }
  loser:
      fclose(dsareq);
  }
  
  /*
   * pqg generation type
   */
  typedef enum {
      FIPS186_1,/* Generate/Verify P,Q & G  according to FIPS 186-1 */
      A_1_1_2, /* Generate Probable P & Q */
      A_1_1_3, /* Verify Probable P & Q */
      A_1_2_2, /* Verify Provable P & Q */
      A_2_1,   /* Generate Unverifiable G */
      A_2_2,   /* Assure Unverifiable G */
      A_2_3,   /* Generate Verifiable G */
      A_2_4    /* Verify Verifiable G */
  } dsa_pqg_type;
  
  /*
   * Perform the DSA Domain Parameter Validation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  dsa_pqgver_test(char *reqfn)
  {
      char buf[800];      /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * 800 to hold (384 public key (x2 for HEX) + P = ...
                           */
      FILE *dsareq;     /* input stream from the REQUEST file */
      FILE *dsaresp;    /* output stream to the RESPONSE file */
      int N;
      int L;
      unsigned int i, j;
      PQGParams pqg;
      PQGVerify vfy;
      unsigned int pghSize;        /* size for p, g, and h */
      dsa_pqg_type type = FIPS186_1;
  
      dsareq = fopen(reqfn, "r");
      dsaresp = stdout;
      memset(&pqg, 0, sizeof(pqg));
      memset(&vfy, 0, sizeof(vfy));
  
      while (fgets(buf, sizeof buf, dsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, dsaresp);
              continue;
          }
  
          /* [A.xxxxx ] */
          if (buf[0] == '['  && buf[1] == 'A') {
  
  	    if (strncmp(&buf[1],"A.1.1.3",7) == 0) {
  		type = A_1_1_3;
  	    } else if (strncmp(&buf[1],"A.2.2",5) == 0) {
  		type = A_2_2;
  	    } else if (strncmp(&buf[1],"A.2.4",5) == 0) {
  		type = A_2_4;
  	    } else if (strncmp(&buf[1],"A.1.2.2",7) == 0) {
  		type = A_1_2_2;
  	    /* validate our output from PQGGEN */
  	    } else if (strncmp(&buf[1],"A.1.1.2",7) == 0) {
  		type = A_2_4; /* validate PQ and G together */
  	    } else {
  		fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]);
  		exit(1);
  	    }
  		
              fputs(buf, dsaresp);
              continue;
          }
  	
  
          /* [Mod = x] */
          if (buf[0] == '[') {
  
  	    if (type == FIPS186_1) {
                  N=160;
                  if (sscanf(buf, "[mod = %d]", &L) != 1) {
                      goto loser;
  		}
  	    } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) {
  		goto loser;
              }
  
              if (pqg.prime.data) { /* P */
                  SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
              }
              if (pqg.subPrime.data) { /* Q */
                  SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
              }
              if (pqg.base.data) {    /* G */
                  SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
              }
              if (vfy.seed.data) {   /* seed */
                  SECITEM_ZfreeItem(&vfy.seed, PR_FALSE);
              }
              if (vfy.h.data) {     /* H */
                  SECITEM_ZfreeItem(&vfy.h, PR_FALSE);
              }
  
              fputs(buf, dsaresp);
  
              /*calculate the size of p, g, and h then allocate items  */
              pghSize = L/8;
  
  	    pqg.base.data = vfy.h.data = NULL;
  	    vfy.seed.len = pqg.base.len = vfy.h.len = 0;
              SECITEM_AllocItem(NULL, &pqg.prime, pghSize);
              SECITEM_AllocItem(NULL, &vfy.seed, pghSize*3);
  	    if (type == A_2_2) {
  		SECITEM_AllocItem(NULL, &vfy.h, pghSize);
  	    	vfy.h.len = pghSize;
  	    } else if (type == A_2_4) {
  		SECITEM_AllocItem(NULL, &vfy.h, 1);
  	    	vfy.h.len = 1;
  	    }
              pqg.prime.len = pghSize;
              /* q is always N bits */
              SECITEM_AllocItem(NULL, &pqg.subPrime, N/8);
              pqg.subPrime.len = N/8;
              vfy.counter = -1;
  
              continue;
          }
          /* P = ... */
          if (buf[0] == 'P') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< pqg.prime.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pqg.prime.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* Q = ... */
          if (buf[0] == 'Q') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< pqg.subPrime.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* G = ... */
          if (buf[0] == 'G') {
              i = 1;
              if (pqg.base.data) {
                  SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
              }
              SECITEM_AllocItem(NULL, &pqg.base, pghSize);
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< pqg.base.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pqg.base.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* Seed = ...  or domain_parameter_seed = ... */
          if (strncmp(buf, "Seed", 4) == 0) {
              i = 4;
          } else if (strncmp(buf, "domain_parameter_seed", 21) == 0) {
  	    i = 21;
  	} else if (strncmp(buf,"firstseed",9) == 0) {
  	    i = 9;
  	} else {
  	    i = 0;
  	}
  	if (i) {
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &vfy.seed.data[j]);
              }
  	    vfy.seed.len = j;
  
              fputs(buf, dsaresp);
  	    if (type == A_2_4) {
  		SECStatus result;
  
                  /* Verify the Parameters */
                  SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result);
                  if (rv != SECSuccess) {
                      goto loser;
                  }
                  if (result == SECSuccess) {
                      fprintf(dsaresp, "Result = P\n");
                  } else {
                      fprintf(dsaresp, "Result = F\n");
                  }
  	    }
              continue;
          }
  	if ((strncmp(buf,"pseed",5) == 0) ||
  	    (strncmp(buf,"qseed",5) == 0))
  	{
  	    i = 5;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=vfy.seed.len; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &vfy.seed.data[j]);
              }
  	    vfy.seed.len = j;
              fputs(buf, dsaresp);
  
              continue;
  	}
          if (strncmp(buf, "index", 4) == 0) {
  	    i=5;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
  	    hex_to_byteval(&buf[i], &vfy.h.data[0]);
  	    vfy.h.len = 1;
              fputs(buf, dsaresp);
  	}
  
          /* c = ...  or counter=*/
          if (buf[0] == 'c')  {
  	    if (strncmp(buf,"counter", 7) == 0) {
                  if (sscanf(buf, "counter = %u", &vfy.counter) != 1) {
                      goto loser;
  		}
  	    } else {
                  if (sscanf(buf, "c = %u", &vfy.counter) != 1) {
                      goto loser;
  		}
              }
  
              fputs(buf, dsaresp);
              if (type == A_1_1_3) {
  		SECStatus result;
                  /* only verify P and Q, we have everything now. do it */
                  SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result);
                  if (rv != SECSuccess) {
                      goto loser;
                  }
                  if (result == SECSuccess) {
                      fprintf(dsaresp, "Result = P\n");
                  } else {
                      fprintf(dsaresp, "Result = F\n");
                  }
                  fprintf(dsaresp, "\n");
              }
              continue;
          }
  	if (strncmp(buf,"pgen_counter", 12) == 0) {
              if (sscanf(buf, "pgen_counter = %u", &vfy.counter) != 1) {
                  goto loser;
              }	
              fputs(buf, dsaresp);
  	    continue;
  	}
  	if (strncmp(buf,"qgen_counter", 12) == 0) {
              fputs(buf, dsaresp);
              if (type == A_1_2_2) {
  		SECStatus result;
                  /* only verify P and Q, we have everything now. do it */
                  SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result);
                  if (rv != SECSuccess) {
                      goto loser;
                  }
                  if (result == SECSuccess) {
                      fprintf(dsaresp, "Result = P\n");
                  } else {
                      fprintf(dsaresp, "Result = F\n");
                  }
                  fprintf(dsaresp, "\n");
              } 
  	    continue;
  	}
          /* H = ... */
          if (buf[0] == 'H') {
              SECStatus rv, result = SECFailure;
  
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &vfy.h.data[j]);
              }
  	    vfy.h.len = j;
              fputs(buf, dsaresp);
  
  	    /* this should be a byte value. Remove the leading zeros. If
  	     * it doesn't reduce to a byte, PQG_VerifyParams will catch it 
  	    if (type == A_2_2) {
  		data_save = vfy.h.data;
  		while(vfy.h.data[0] && (vfy.h.len > 1)) {
  			vfy.h.data++;
  			vfy.h.len--;
  		}
  	    } */
  
              /* Verify the Parameters */
              rv = PQG_VerifyParams(&pqg, &vfy, &result);
              if (rv != SECSuccess) {
                  goto loser;
              }
              if (result == SECSuccess) {
                  fprintf(dsaresp, "Result = P\n");
              } else {
                  fprintf(dsaresp, "Result = F\n");
              }
              fprintf(dsaresp, "\n");
              continue;
          }
      }
  loser:
      fclose(dsareq);
      if (pqg.prime.data) { /* P */
          SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
      }
      if (pqg.subPrime.data) { /* Q */
          SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
      }
      if (pqg.base.data) {    /* G */
          SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
      }
      if (vfy.seed.data) {   /* seed */
          SECITEM_ZfreeItem(&vfy.seed, PR_FALSE);
      }
      if (vfy.h.data) {     /* H */
          SECITEM_ZfreeItem(&vfy.h, PR_FALSE);
      }
  
  }
  
  /*
   * Perform the DSA Public Key Validation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  dsa_pqggen_test(char *reqfn)
  {
      char buf[800];      /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * 800 to hold seed = (384 public key (x2 for HEX)
                           */
      FILE *dsareq;     /* input stream from the REQUEST file */
      FILE *dsaresp;    /* output stream to the RESPONSE file */
      int count;            /* number of times to generate parameters */
      int N;
      int L;
      int i;
      unsigned int j;
      PQGParams *pqg = NULL;
      PQGVerify *vfy = NULL;
      unsigned int keySizeIndex;
      dsa_pqg_type type = FIPS186_1;
  
      dsareq = fopen(reqfn, "r");
      dsaresp = stdout;
      while (fgets(buf, sizeof buf, dsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, dsaresp);
              continue;
          }
  
          /* [A.xxxxx ] */
          if (buf[0] == '['  && buf[1] == 'A') {
  	    if (strncmp(&buf[1],"A.1.1.2",7) == 0) {
  		type = A_1_1_2;
  	    } else if (strncmp(&buf[1],"A.2.1",5) == 0) {
  		fprintf(stderr, "NSS only Generates G with P&Q\n");
  		exit(1);
  	    } else if (strncmp(&buf[1],"A.2.3",5) == 0) {
  		fprintf(stderr, "NSS only Generates G with P&Q\n");
  		exit(1);
  	    } else if (strncmp(&buf[1],"A.1.2.1",7) == 0) {
  		fprintf(stderr, "NSS does not support Shawe-Taylor Primes\n");
  		exit(1);
  	    } else {
  		fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]);
  		exit(1);
  	    }
              fputs(buf, dsaresp);
              continue;
          }
  
          /* [Mod = ... ] */
          if (buf[0] == '[') {
  
  	    if (type == FIPS186_1) {
                  N=160;
                  if (sscanf(buf, "[mod = %d]", &L) != 1) {
                      goto loser;
  		}
  	    } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) {
  		goto loser;
              }
  
              fputs(buf, dsaresp);
              fputc('\n', dsaresp);
  
  	    if (type == FIPS186_1) {
                  /************************************************************
                   * PQG_ParamGenSeedLen doesn't take a key size, it takes an
                   * index that points to a valid key size.
                   */
                  keySizeIndex = PQG_PBITS_TO_INDEX(L);
                  if(keySizeIndex == -1 || L<512 || L>1024) {
                     fprintf(dsaresp,
                          "DSA key size must be a multiple of 64 between 512 "
                          "and 1024, inclusive");
                      goto loser;
                  }
              }
              continue;
          }
          /* N = ... */
          if (buf[0] == 'N') {
              if (sscanf(buf, "N = %d", &count) != 1) {
                  goto loser;
              }
              for (i = 0; i < count; i++) {
                  SECStatus rv;
  
                  if (type == FIPS186_1) {
                      rv = PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
                           &pqg, &vfy);
                  } else {
                      rv = PQG_ParamGenV2(L, N, N, &pqg, &vfy);
                  }
                  if (rv != SECSuccess) {
                      fprintf(dsaresp,
                              "ERROR: Unable to generate PQG parameters");
                      goto loser;
                  }
                  to_hex_str(buf, pqg->prime.data, pqg->prime.len);
                  fprintf(dsaresp, "P = %s\n", buf);
                  to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
                  fprintf(dsaresp, "Q = %s\n", buf);
                  to_hex_str(buf, pqg->base.data, pqg->base.len);
                  fprintf(dsaresp, "G = %s\n", buf);
  		if (type == FIPS186_1) {
                      to_hex_str(buf, vfy->seed.data, vfy->seed.len);
                      fprintf(dsaresp, "Seed = %s\n", buf);
                      fprintf(dsaresp, "c = %d\n", vfy->counter);
                      to_hex_str(buf, vfy->h.data, vfy->h.len);
                      fputs("H = ", dsaresp);
                      for (j=vfy->h.len; j< pqg->prime.len; j++) {
                  	fprintf(dsaresp, "00");
                      }
                      fprintf(dsaresp, "%s\n", buf);
  		} else {
                      fprintf(dsaresp, "counter = %d\n", vfy->counter);
  		    fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]);
                      to_hex_str(buf, vfy->seed.data, vfy->seed.len);
                      fprintf(dsaresp, "domain_parameter_seed = %s\n", buf);
  		}
                  fputc('\n', dsaresp);
                  if(pqg!=NULL) {
                      PQG_DestroyParams(pqg);
                      pqg = NULL;
                  }
                  if(vfy!=NULL) {
                      PQG_DestroyVerify(vfy);
                      vfy = NULL;
                  }
              }
  
              continue;
          }
  
      }
  loser:
      fclose(dsareq);
      if(pqg!=NULL) {
          PQG_DestroyParams(pqg);
      }
      if(vfy!=NULL) {
          PQG_DestroyVerify(vfy);
      }
  }
  
  
  /*
   * Perform the DSA Signature Generation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  dsa_siggen_test(char *reqfn)
  {
      char buf[800];      /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * max for Msg = ....
                           */
      FILE *dsareq;     /* input stream from the REQUEST file */
      FILE *dsaresp;    /* output stream to the RESPONSE file */
      int modulus;
      int L;
      int N;
      int i, j;
      PRBool use_dsa1 = PR_FALSE;
      PQGParams *pqg = NULL;
      PQGVerify *vfy = NULL;
      DSAPrivateKey *dsakey = NULL;
      int keySizeIndex;     /* index for valid key sizes */
      unsigned char hashBuf[HASH_LENGTH_MAX];  /* SHA-x hash (160-512 bits) */
      unsigned char sig[DSA_MAX_SIGNATURE_LEN];
      SECItem digest, signature;
      HASH_HashType hashType = HASH_AlgNULL;
      int hashNum = 0;
  
      dsareq = fopen(reqfn, "r");
      dsaresp = stdout;
  
      while (fgets(buf, sizeof buf, dsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, dsaresp);
              continue;
          }
  
          /* [Mod = x] */
          if (buf[0] == '[') {
              if(pqg!=NULL) {
                  PQG_DestroyParams(pqg);
                  pqg = NULL;
              }
              if(vfy!=NULL) {
                  PQG_DestroyVerify(vfy);
                  vfy = NULL;
              }
              if (dsakey != NULL) {
                      PORT_FreeArena(dsakey->params.arena, PR_TRUE);
                      dsakey = NULL;
              }
  
              if (sscanf(buf, "[mod = L=%d,  N=%d, SHA-%d]", &L, & N,
                  &hashNum) != 3) {
                  use_dsa1 = PR_TRUE;
  		hashNum = 1;
                  if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
                      goto loser;
                  }
              }
              fputs(buf, dsaresp);
              fputc('\n', dsaresp);
  
              /****************************************************************
              * PQG_ParamGenSeedLen doesn't take a key size, it takes an index
              * that points to a valid key size.
              */
              if (use_dsa1) {
                  keySizeIndex = PQG_PBITS_TO_INDEX(modulus);
                  if(keySizeIndex == -1 || modulus<512 || modulus>1024) {
                      fprintf(dsaresp,
                          "DSA key size must be a multiple of 64 between 512 "
                          "and 1024, inclusive");
                      goto loser;
                  }
                  /* Generate PQG and output PQG */
                  if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
                      &pqg, &vfy) != SECSuccess) {
                      fprintf(dsaresp, 
                              "ERROR: Unable to generate PQG parameters");
                      goto loser;
                  }
              } else {
                  if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
                      fprintf(dsaresp, 
                              "ERROR: Unable to generate PQG parameters");
                      goto loser;
                  }
              }
              to_hex_str(buf, pqg->prime.data, pqg->prime.len);
              fprintf(dsaresp, "P = %s\n", buf);
              to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
              fprintf(dsaresp, "Q = %s\n", buf);
              to_hex_str(buf, pqg->base.data, pqg->base.len);
              fprintf(dsaresp, "G = %s\n", buf);
  
              /* create DSA Key */
              if (DSA_NewKey(pqg, &dsakey) != SECSuccess) {
                  fprintf(dsaresp, "ERROR: Unable to generate DSA key");
                  goto loser;
              }
   
  	    hashType = sha_get_hashType(hashNum);
  	    if (hashType == HASH_AlgNULL) {
  		fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum);
  		goto loser;
  	    }
              continue;
          }
  
          /* Msg = ... */
          if (strncmp(buf, "Msg", 3) == 0) {
              unsigned char msg[128]; /* MAX msg 128 */
              unsigned int len = 0;
  
  	    if (hashType == HASH_AlgNULL) {
  		fprintf(dsaresp, "ERROR: Hash Alg not set");
  		goto loser;
  	    }
  
              memset(hashBuf, 0, sizeof hashBuf);
              memset(sig,  0, sizeof sig);
  
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &msg[j]);
              }
              if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) {
                   fprintf(dsaresp, "ERROR: Unable to generate SHA% digest", 
  			 hashNum);
                   goto loser;
              }
  
  
              digest.type = siBuffer;
              digest.data = hashBuf;
              digest.len = fips_hashLen(hashType);
              signature.type = siBuffer;
              signature.data = sig;
              signature.len = sizeof sig;
  
              if (DSA_SignDigest(dsakey, &signature, &digest) != SECSuccess) {
                  fprintf(dsaresp, "ERROR: Unable to generate DSA signature");
                  goto loser;
              }
              len = signature.len;
              if (len%2 != 0) {
                  goto loser;
              }
              len = len/2;
  
              /* output the orginal Msg, and generated Y, R, and S */
              fputs(buf, dsaresp);
              to_hex_str(buf, dsakey->publicValue.data,
                         dsakey->publicValue.len);
              fprintf(dsaresp, "Y = %s\n", buf);
              to_hex_str(buf, &signature.data[0], len);
              fprintf(dsaresp, "R = %s\n", buf);
              to_hex_str(buf, &signature.data[len], len);
              fprintf(dsaresp, "S = %s\n", buf);
              fputc('\n', dsaresp);
              continue;
          }
  
      }
  loser:
      fclose(dsareq);
      if(pqg != NULL) {
          PQG_DestroyParams(pqg);
          pqg = NULL;
      }
      if(vfy != NULL) {
          PQG_DestroyVerify(vfy);
          vfy = NULL;
      }
      if (dsakey) {
          PORT_FreeArena(dsakey->params.arena, PR_TRUE);
          dsakey = NULL;
      }
  }
  
   /*
   * Perform the DSA Signature Verification Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  dsa_sigver_test(char *reqfn)
  {
      char buf[800];       /* holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * max for Msg = ....
                           */
      FILE *dsareq;     /* input stream from the REQUEST file */
      FILE *dsaresp;    /* output stream to the RESPONSE file */
      int L;
      int N;
      unsigned int i, j;
      SECItem digest, signature;
      DSAPublicKey pubkey;
      unsigned int pgySize;        /* size for p, g, and y */
      unsigned char hashBuf[HASH_LENGTH_MAX];  /* SHA-x hash (160-512 bits) */
      unsigned char sig[DSA_MAX_SIGNATURE_LEN];
      HASH_HashType hashType = HASH_AlgNULL;
      int hashNum = 0;
  
      dsareq = fopen(reqfn, "r");
      dsaresp = stdout;
      memset(&pubkey, 0, sizeof(pubkey));
  
      while (fgets(buf, sizeof buf, dsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, dsaresp);
              continue;
          }
  
          /* [Mod = x] */
          if (buf[0] == '[') {
  
              if (sscanf(buf, "[mod = L=%d,  N=%d, SHA-%d]", &L, & N,
                  &hashNum) != 3) {
  		N=160;
  		hashNum = 1;
                  if (sscanf(buf, "[mod = %d]", &L) != 1) {
                      goto loser;
                  }
              }
  
              if (pubkey.params.prime.data) { /* P */
                  SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE);
              }
              if (pubkey.params.subPrime.data) { /* Q */
                  SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE);
              }
              if (pubkey.params.base.data) {    /* G */
                  SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE);
              }
              if (pubkey.publicValue.data) {    /* Y */
                  SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE);
              }
              fputs(buf, dsaresp);
  
              /* calculate the size of p, g, and y then allocate items */
              pgySize = L/8;
              SECITEM_AllocItem(NULL, &pubkey.params.prime, pgySize);
              SECITEM_AllocItem(NULL, &pubkey.params.base, pgySize);
              SECITEM_AllocItem(NULL, &pubkey.publicValue, pgySize);
              pubkey.params.prime.len = pubkey.params.base.len = pgySize;
              pubkey.publicValue.len = pgySize;
  
              /* q always N/8 bytes */
              SECITEM_AllocItem(NULL, &pubkey.params.subPrime, N/8);
              pubkey.params.subPrime.len = N/8;
  
  	    hashType = sha_get_hashType(hashNum);
  	    if (hashType == HASH_AlgNULL) {
  		fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum);
  		goto loser;
  	    }
  
              continue;
          }
          /* P = ... */
          if (buf[0] == 'P') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              memset(pubkey.params.prime.data, 0, pubkey.params.prime.len);
              for (j=0; j< pubkey.params.prime.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pubkey.params.prime.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* Q = ... */
          if (buf[0] == 'Q') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              memset(pubkey.params.subPrime.data, 0, pubkey.params.subPrime.len);
              for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pubkey.params.subPrime.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* G = ... */
          if (buf[0] == 'G') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              memset(pubkey.params.base.data, 0, pubkey.params.base.len);
              for (j=0; j< pubkey.params.base.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pubkey.params.base.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* Msg = ... */
          if (strncmp(buf, "Msg", 3) == 0) {
              unsigned char msg[128]; /* MAX msg 128 */
              memset(hashBuf, 0, sizeof hashBuf);
  
  	    if (hashType == HASH_AlgNULL) {
  		fprintf(dsaresp, "ERROR: Hash Alg not set");
  		goto loser;
  	    }
  
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]); i+=2,j++) {
                  hex_to_byteval(&buf[i], &msg[j]);
              }
              if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) {
                  fprintf(dsaresp, "ERROR: Unable to generate SHA-%d digest",
  								hashNum);
                  goto loser;
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* Y = ... */
          if (buf[0] == 'Y') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              memset(pubkey.publicValue.data, 0, pubkey.params.subPrime.len);
              for (j=0; j< pubkey.publicValue.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &pubkey.publicValue.data[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* R = ... */
          if (buf[0] == 'R') {
              memset(sig,  0, sizeof sig);
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) {
                  hex_to_byteval(&buf[i], &sig[j]);
              }
  
              fputs(buf, dsaresp);
              continue;
          }
  
          /* S = ... */
          if (buf[0] == 'S') {
  	    if (hashType == HASH_AlgNULL) {
  		fprintf(dsaresp, "ERROR: Hash Alg not set");
  		goto loser;
  	    }
  
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=pubkey.params.subPrime.len; 
  				j< pubkey.params.subPrime.len*2; i+=2,j++) {
                  hex_to_byteval(&buf[i], &sig[j]);
              }
              fputs(buf, dsaresp);
  
              digest.type = siBuffer;
              digest.data = hashBuf;
              digest.len = fips_hashLen(hashType);
              signature.type = siBuffer;
              signature.data = sig;
              signature.len = pubkey.params.subPrime.len*2;
  
              if (DSA_VerifyDigest(&pubkey, &signature, &digest) == SECSuccess) {
                  fprintf(dsaresp, "Result = P\n");
              } else {
                  fprintf(dsaresp, "Result = F\n");
              }
  	    fprintf(dsaresp, "\n");
              continue;
          }
      }
  loser:
      fclose(dsareq);
      if (pubkey.params.prime.data) { /* P */
          SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE);
      }
      if (pubkey.params.subPrime.data) { /* Q */
          SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE);
      }
      if (pubkey.params.base.data) {    /* G */
          SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE);
      }
      if (pubkey.publicValue.data) {    /* Y */
          SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE);
      }
  }
  
  /*
   * Perform the RSA Signature Generation Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  rsa_siggen_test(char *reqfn)
  {
      char buf[2*RSA_MAX_TEST_MODULUS_BYTES+1];
                          /* buf holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * 2x for HEX output + 1 for \n
                           */
      FILE *rsareq;     /* input stream from the REQUEST file */
      FILE *rsaresp;    /* output stream to the RESPONSE file */
      int i, j;
      unsigned char  sha[HASH_LENGTH_MAX];    /* SHA digest */
      unsigned int   shaLength = 0;           /* length of SHA */
      HASH_HashType  shaAlg = HASH_AlgNULL;   /* type of SHA Alg */
      SECOidTag      shaOid = SEC_OID_UNKNOWN;
      int modulus;                                /* the Modulus size */
      int  publicExponent  = DEFAULT_RSA_PUBLIC_EXPONENT;
      SECItem pe = {0, 0, 0 };
      unsigned char pubEx[4];
      int peCount = 0;
  
      RSAPrivateKey  *rsaBlapiPrivKey = NULL;   /* holds RSA private and
                                                * public keys */
      RSAPublicKey   *rsaBlapiPublicKey = NULL; /* hold RSA public key */
  
      rsareq = fopen(reqfn, "r");
      rsaresp = stdout;
  
      /* calculate the exponent */
      for (i=0; i < 4; i++) {
          if (peCount || (publicExponent &
                  ((unsigned long)0xff000000L >> (i*8)))) {
              pubEx[peCount] =
                  (unsigned char)((publicExponent >> (3-i)*8) & 0xff);
              peCount++;
          }
      }
      pe.len = peCount;
      pe.data = &pubEx[0];
      pe.type = siBuffer;
  
      while (fgets(buf, sizeof buf, rsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, rsaresp);
              continue;
          }
  
          /* [mod = ...] */
          if (buf[0] == '[') {
  
              if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
                  goto loser;
              }
              if (modulus > RSA_MAX_TEST_MODULUS_BITS) {
                  fprintf(rsaresp,"ERROR: modulus greater than test maximum\n");
                  goto loser;
              }
  
              fputs(buf, rsaresp);
  
              if (rsaBlapiPrivKey != NULL) {
                  PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE);
                  rsaBlapiPrivKey = NULL;
                  rsaBlapiPublicKey = NULL;
              }
  
              rsaBlapiPrivKey = RSA_NewKey(modulus, &pe);
              if (rsaBlapiPrivKey == NULL) {
                  fprintf(rsaresp, "Error unable to create RSA key\n");
                  goto loser;
              }
  
              to_hex_str(buf, rsaBlapiPrivKey->modulus.data,
                         rsaBlapiPrivKey->modulus.len);
              fprintf(rsaresp, "\nn = %s\n\n", buf);
              to_hex_str(buf, rsaBlapiPrivKey->publicExponent.data,
                         rsaBlapiPrivKey->publicExponent.len);
              fprintf(rsaresp, "e = %s\n", buf);
              /* convert private key to public key.  Memory
               * is freed with private key's arena  */
              rsaBlapiPublicKey = (RSAPublicKey *)PORT_ArenaAlloc(
                                                    rsaBlapiPrivKey->arena,
                                                    sizeof(RSAPublicKey));
  
              rsaBlapiPublicKey->modulus.len = rsaBlapiPrivKey->modulus.len;
              rsaBlapiPublicKey->modulus.data = rsaBlapiPrivKey->modulus.data;
              rsaBlapiPublicKey->publicExponent.len =
                  rsaBlapiPrivKey->publicExponent.len;
              rsaBlapiPublicKey->publicExponent.data =
                  rsaBlapiPrivKey->publicExponent.data;
              continue;
          }
  
          /* SHAAlg = ... */
          if (strncmp(buf, "SHAAlg", 6) == 0) {
             i = 6;
             while (isspace(buf[i]) || buf[i] == '=') {
                 i++;
             }
             /* set the SHA Algorithm */
             if (strncmp(&buf[i], "SHA1", 4) == 0) {
                  shaAlg = HASH_AlgSHA1;
             } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
                  shaAlg = HASH_AlgSHA224;
             } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
                  shaAlg = HASH_AlgSHA256;
             } else if (strncmp(&buf[i], "SHA384", 6)== 0) {
                 shaAlg = HASH_AlgSHA384;
             } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
                 shaAlg = HASH_AlgSHA512;
             } else {
                 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
                 goto loser;
             }
             fputs(buf, rsaresp);
             continue;
  
          }
          /* Msg = ... */
          if (strncmp(buf, "Msg", 3) == 0) {
  
              unsigned char msg[128]; /* MAX msg 128 */
              unsigned int rsa_bytes_signed;
              unsigned char rsa_computed_signature[RSA_MAX_TEST_MODULUS_BYTES];
              SECStatus       rv = SECFailure;
              NSSLOWKEYPublicKey  * rsa_public_key;
              NSSLOWKEYPrivateKey * rsa_private_key;
              NSSLOWKEYPrivateKey   low_RSA_private_key = { NULL,
                                                  NSSLOWKEYRSAKey, };
              NSSLOWKEYPublicKey    low_RSA_public_key = { NULL,
                                                  NSSLOWKEYRSAKey, };
  
              low_RSA_private_key.u.rsa = *rsaBlapiPrivKey;
              low_RSA_public_key.u.rsa = *rsaBlapiPublicKey;
  
              rsa_private_key = &low_RSA_private_key;
              rsa_public_key = &low_RSA_public_key;
  
              memset(sha, 0, sizeof sha);
              memset(msg, 0, sizeof msg);
              rsa_bytes_signed = 0;
              memset(rsa_computed_signature, 0, sizeof rsa_computed_signature);
  
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              for (j=0; isxdigit(buf[i]) && j < sizeof(msg); i+=2,j++) {
                  hex_to_byteval(&buf[i], &msg[j]);
              }
  	    shaLength = fips_hashLen(shaAlg);
  	    if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) {
  		if (shaLength == 0) {
              	    fprintf(rsaresp, "ERROR: SHAAlg not defined.");
  		}
                  fprintf(rsaresp, "ERROR: Unable to generate SHA%x",
  			shaLength == 160 ? 1 : shaLength);
                  goto loser;
              }
  	    shaOid = fips_hashOid(shaAlg);
  
              /* Perform RSA signature with the RSA private key. */
              rv = RSA_HashSign( shaOid,
                                 rsa_private_key,
                                 rsa_computed_signature,
                                 &rsa_bytes_signed,
                                 nsslowkey_PrivateModulusLen(rsa_private_key),
                                 sha,
                                 shaLength);
  
              if( rv != SECSuccess ) {
                   fprintf(rsaresp, "ERROR: RSA_HashSign failed");
                   goto loser;
              }
  
              /* Output the signature */
              fputs(buf, rsaresp);
              to_hex_str(buf, rsa_computed_signature, rsa_bytes_signed);
              fprintf(rsaresp, "S = %s\n", buf);
  
              /* Perform RSA verification with the RSA public key. */
              rv = RSA_HashCheckSign( shaOid,
                                      rsa_public_key,
                                      rsa_computed_signature,
                                      rsa_bytes_signed,
                                      sha,
                                      shaLength);
              if( rv != SECSuccess ) {
                   fprintf(rsaresp, "ERROR: RSA_HashCheckSign failed");
                   goto loser;
              }
              continue;
          }
      }
  loser:
      fclose(rsareq);
  
      if (rsaBlapiPrivKey != NULL) {
          /* frees private and public key */
          PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE);
          rsaBlapiPrivKey = NULL;
          rsaBlapiPublicKey = NULL;
      }
  
  }
  /*
   * Perform the RSA Signature Verification Test.
   *
   * reqfn is the pathname of the REQUEST file.
   *
   * The output RESPONSE file is written to stdout.
   */
  void
  rsa_sigver_test(char *reqfn)
  {
      char buf[2*RSA_MAX_TEST_MODULUS_BYTES+7];
                          /* buf holds one line from the input REQUEST file
                           * or to the output RESPONSE file.
                           * s = 2x for HEX output + 1 for \n
                           */
      FILE *rsareq;     /* input stream from the REQUEST file */
      FILE *rsaresp;    /* output stream to the RESPONSE file */
      int i, j;
      unsigned char   sha[HASH_LENGTH_MAX];   /* SHA digest */
      unsigned int    shaLength = 0;              /* actual length of the digest */
      HASH_HashType   shaAlg = HASH_AlgNULL;
      SECOidTag       shaOid = SEC_OID_UNKNOWN;
      int modulus = 0;                            /* the Modulus size */
      unsigned char   signature[513];    /* largest signature size + '\n' */
      unsigned int    signatureLength = 0;   /* actual length of the signature */
      PRBool keyvalid = PR_TRUE;
  
      RSAPublicKey   rsaBlapiPublicKey; /* hold RSA public key */
  
      rsareq = fopen(reqfn, "r");
      rsaresp = stdout;
      memset(&rsaBlapiPublicKey, 0, sizeof(RSAPublicKey));
  
      while (fgets(buf, sizeof buf, rsareq) != NULL) {
          /* a comment or blank line */
          if (buf[0] == '#' || buf[0] == '\n') {
              fputs(buf, rsaresp);
              continue;
          }
  
          /* [Mod = ...] */
          if (buf[0] == '[') {
              unsigned int flen;  /* length in bytes of the field size */
  
              if (rsaBlapiPublicKey.modulus.data) { /* n */
                  SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE);
              }
              if (sscanf(buf, "[mod = %d]", &modulus) != 1) {
                  goto loser;
              }
  
              if (modulus > RSA_MAX_TEST_MODULUS_BITS) {
                  fprintf(rsaresp,"ERROR: modulus greater than test maximum\n");
                  goto loser;
              }
  
              fputs(buf, rsaresp);
  
              signatureLength = flen = modulus/8;
  
              SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.modulus, flen);
              if (rsaBlapiPublicKey.modulus.data == NULL) {
                  goto loser;
              }
              continue;
          }
  
          /* n = ... modulus */
          if (buf[0] == 'n') {
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              keyvalid = from_hex_str(&rsaBlapiPublicKey.modulus.data[0],
                                      rsaBlapiPublicKey.modulus.len,
                                      &buf[i]);
  
              if (!keyvalid) {
                  fprintf(rsaresp, "ERROR: rsa_sigver n not valid.\n");
                                   goto loser;
              }
              fputs(buf, rsaresp);
              continue;
          }
  
          /* SHAAlg = ... */
          if (strncmp(buf, "SHAAlg", 6) == 0) {
             i = 6;
             while (isspace(buf[i]) || buf[i] == '=') {
                 i++;
             }
             /* set the SHA Algorithm */
             if (strncmp(&buf[i], "SHA1", 4) == 0) {
                  shaAlg = HASH_AlgSHA1;
             } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
                  shaAlg = HASH_AlgSHA224;
             } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
                  shaAlg = HASH_AlgSHA256;
             } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
                 shaAlg = HASH_AlgSHA384;
             } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
                 shaAlg = HASH_AlgSHA512;
             } else {
                 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
                 goto loser;
             }
             fputs(buf, rsaresp);
             continue;
          }
  
          /* e = ... public Key */
          if (buf[0] == 'e') {
              unsigned char data[RSA_MAX_TEST_EXPONENT_BYTES];
              unsigned char t;
  
              memset(data, 0, sizeof data);
  
              if (rsaBlapiPublicKey.publicExponent.data) { /* e */
                  SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE);
              }
  
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
              /* skip leading zero's */
              while (isxdigit(buf[i])) {
                  hex_to_byteval(&buf[i], &t);
                  if (t == 0) {
                      i+=2;
                  } else break;
              }
          
              /* get the exponent */
              for (j=0; isxdigit(buf[i]) && j < sizeof data; i+=2,j++) {
                  hex_to_byteval(&buf[i], &data[j]);
              }
  
              if (j == 0) { j = 1; }  /* to handle 1 byte length exponents */
  
              SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.publicExponent,  j);
              if (rsaBlapiPublicKey.publicExponent.data == NULL) {
                  goto loser;
              }
  
              for (i=0; i < j; i++) {
                  rsaBlapiPublicKey.publicExponent.data[i] = data[i];
              }
  
              fputs(buf, rsaresp);
              continue;
          }
  
          /* Msg = ... */
          if (strncmp(buf, "Msg", 3) == 0) {
              unsigned char msg[128]; /* MAX msg 128 */
  
              memset(sha, 0, sizeof sha);
              memset(msg, 0, sizeof msg);
  
              i = 3;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
  
              for (j=0; isxdigit(buf[i]) && j < sizeof msg; i+=2,j++) {
                  hex_to_byteval(&buf[i], &msg[j]);
              }
  
  	    shaLength = fips_hashLen(shaAlg);
  	    if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) {
  		if (shaLength == 0) {
              	    fprintf(rsaresp, "ERROR: SHAAlg not defined.");
  		}
                  fprintf(rsaresp, "ERROR: Unable to generate SHA%x",
  			shaLength == 160 ? 1 : shaLength);
                  goto loser;
              }
  
              fputs(buf, rsaresp);
              continue;
  
          }
  
          /* S = ... */
          if (buf[0] == 'S') {
              SECStatus rv = SECFailure;
              NSSLOWKEYPublicKey  * rsa_public_key;
              NSSLOWKEYPublicKey    low_RSA_public_key = { NULL,
                                                    NSSLOWKEYRSAKey, };
  
              /* convert to a low RSA public key */
              low_RSA_public_key.u.rsa = rsaBlapiPublicKey;
              rsa_public_key = &low_RSA_public_key;
  
              memset(signature, 0, sizeof(signature));
              i = 1;
              while (isspace(buf[i]) || buf[i] == '=') {
                  i++;
              }
  
              for (j=0; isxdigit(buf[i]) && j < sizeof signature; i+=2,j++) {
                  hex_to_byteval(&buf[i], &signature[j]);
              }
  
              signatureLength = j;
              fputs(buf, rsaresp);
  
              /* Perform RSA verification with the RSA public key. */
              rv = RSA_HashCheckSign( shaOid,
                                      rsa_public_key,
                                      signature,
                                      signatureLength,
                                      sha,
                                      shaLength);
              if( rv == SECSuccess ) {
                  fputs("Result = P\n", rsaresp);
              } else {
                  fputs("Result = F\n", rsaresp);
              }
              continue;
          }
      }
  loser:
      fclose(rsareq);
      if (rsaBlapiPublicKey.modulus.data) { /* n */
          SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE);
      }
      if (rsaBlapiPublicKey.publicExponent.data) { /* e */
          SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE);
      }
  }
  
  int main(int argc, char **argv)
  {
      if (argc < 2) exit (-1);
  
      RNG_RNGInit();
      SECOID_Init();
  
      /*************/
      /*   TDEA    */
      /*************/
      if (strcmp(argv[1], "tdea") == 0) {
          /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
          if (strcmp(argv[2], "kat") == 0) {
              /* Known Answer Test (KAT) */
              tdea_kat_mmt(argv[4]);     
          } else if (strcmp(argv[2], "mmt") == 0) {
              /* Multi-block Message Test (MMT) */
                  tdea_kat_mmt(argv[4]);
          } else if (strcmp(argv[2], "mct") == 0) {
                  /* Monte Carlo Test (MCT) */
                  if (strcmp(argv[3], "ecb") == 0) {
                      /* ECB mode */
                      tdea_mct(NSS_DES_EDE3, argv[4]); 
                  } else if (strcmp(argv[3], "cbc") == 0) {
                      /* CBC mode */
                      tdea_mct(NSS_DES_EDE3_CBC, argv[4]);
                  }
          }
      /*************/
      /*   AES     */
      /*************/
      } else if (strcmp(argv[1], "aes") == 0) {
  	/* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
  	if (       strcmp(argv[2], "kat") == 0) {
  	    /* Known Answer Test (KAT) */
  	    aes_kat_mmt(argv[4]);
  	} else if (strcmp(argv[2], "mmt") == 0) {
  	    /* Multi-block Message Test (MMT) */
  	    aes_kat_mmt(argv[4]);
  	} else if (strcmp(argv[2], "mct") == 0) {
  	    /* Monte Carlo Test (MCT) */
  	    if (       strcmp(argv[3], "ecb") == 0) {
  		/* ECB mode */
  		aes_ecb_mct(argv[4]);
  	    } else if (strcmp(argv[3], "cbc") == 0) {
  		/* CBC mode */
  		aes_cbc_mct(argv[4]);
  	    }
  	}
      /*************/
      /*   SHA     */
      /*************/
      } else if (strcmp(argv[1], "sha") == 0) {
          sha_test(argv[2]);
      /*************/
      /*   RSA     */
      /*************/
      } else if (strcmp(argv[1], "rsa") == 0) {
          /* argv[2]=siggen|sigver */
          /* argv[3]=<test name>.req */
          if (strcmp(argv[2], "siggen") == 0) {
              /* Signature Generation Test */
              rsa_siggen_test(argv[3]);
          } else if (strcmp(argv[2], "sigver") == 0) {
              /* Signature Verification Test */
              rsa_sigver_test(argv[3]);
          }
      /*************/
      /*   HMAC    */
      /*************/
      } else if (strcmp(argv[1], "hmac") == 0) {
          hmac_test(argv[2]);
      /*************/
      /*   DSA     */
      /*************/
      } else if (strcmp(argv[1], "dsa") == 0) {
          /* argv[2]=keypair|pqggen|pqgver|siggen|sigver */
          /* argv[3]=<test name>.req */
          if (strcmp(argv[2], "keypair") == 0) {
              /* Key Pair Generation Test */
              dsa_keypair_test(argv[3]);
          } else if (strcmp(argv[2], "pqggen") == 0) {
          /* Domain Parameter Generation Test */
              dsa_pqggen_test(argv[3]);
          } else if (strcmp(argv[2], "pqgver") == 0) {
                  /* Domain Parameter Validation Test */
              dsa_pqgver_test(argv[3]);
          } else if (strcmp(argv[2], "siggen") == 0) {
              /* Signature Generation Test */
              dsa_siggen_test(argv[3]);
          } else if (strcmp(argv[2], "sigver") == 0) {
              /* Signature Verification Test */
              dsa_sigver_test(argv[3]);
          }
  #ifndef NSS_DISABLE_ECC
      /*************/
      /*   ECDSA   */
      /*************/
      } else if (strcmp(argv[1], "ecdsa") == 0) {
  	/* argv[2]=keypair|pkv|siggen|sigver argv[3]=<test name>.req */
  	if (       strcmp(argv[2], "keypair") == 0) {
  	    /* Key Pair Generation Test */
  	    ecdsa_keypair_test(argv[3]);
  	} else if (strcmp(argv[2], "pkv") == 0) {
  	    /* Public Key Validation Test */
  	    ecdsa_pkv_test(argv[3]);
  	} else if (strcmp(argv[2], "siggen") == 0) {
  	    /* Signature Generation Test */
  	    ecdsa_siggen_test(argv[3]);
  	} else if (strcmp(argv[2], "sigver") == 0) {
  	    /* Signature Verification Test */
  	    ecdsa_sigver_test(argv[3]);
  	}
  #endif /* NSS_DISABLE_ECC */
      /*************/
      /*   RNG     */
      /*************/
      } else if (strcmp(argv[1], "rng") == 0) {
  	/* argv[2]=vst|mct argv[3]=<test name>.req */
  	if (       strcmp(argv[2], "vst") == 0) {
  	    /* Variable Seed Test */
  	    rng_vst(argv[3]);
  	} else if (strcmp(argv[2], "mct") == 0) {
  	    /* Monte Carlo Test */
  	    rng_mct(argv[3]);
  	}
      } else if (strcmp(argv[1], "drbg") == 0) {
  	/* Variable Seed Test */
  	drbg(argv[2]);
      } else if (strcmp(argv[1], "ddrbg") == 0) {
  	debug = 1;
  	drbg(argv[2]);
      }
      return 0;
  }
  