diff -r 000000000000 -r 6474c204b198 security/nss/cmd/fipstest/fipstest.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/security/nss/cmd/fipstest/fipstest.c Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,5370 @@ +/* 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 +#include +#include + +#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 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> 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\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\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\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; joid.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, "", 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\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\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; j1024) { + 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]=.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]=.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]=.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]=.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]=.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]=.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; +}