michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "secitem.h" michael@0: #include "blapi.h" michael@0: #include "nssutil.h" michael@0: #include "secerr.h" michael@0: #include "secder.h" michael@0: #include "secdig.h" michael@0: #include "secoid.h" michael@0: #include "ec.h" michael@0: #include "hasht.h" michael@0: #include "lowkeyi.h" michael@0: #include "softoken.h" michael@0: michael@0: #if 0 michael@0: #include "../../lib/freebl/mpi/mpi.h" michael@0: #endif michael@0: michael@0: #ifndef NSS_DISABLE_ECC michael@0: extern SECStatus michael@0: EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); michael@0: extern SECStatus michael@0: EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, michael@0: const ECParams *srcParams); michael@0: #endif michael@0: michael@0: #define ENCRYPT 1 michael@0: #define DECRYPT 0 michael@0: #define BYTE unsigned char michael@0: #define DEFAULT_RSA_PUBLIC_EXPONENT 0x10001 michael@0: #define RSA_MAX_TEST_MODULUS_BITS 4096 michael@0: #define RSA_MAX_TEST_MODULUS_BYTES RSA_MAX_TEST_MODULUS_BITS/8 michael@0: #define RSA_MAX_TEST_EXPONENT_BYTES 8 michael@0: #define PQG_TEST_SEED_BYTES 20 michael@0: michael@0: SECStatus michael@0: hex_to_byteval(const char *c2, unsigned char *byteval) michael@0: { michael@0: int i; michael@0: unsigned char offset; michael@0: *byteval = 0; michael@0: for (i=0; i<2; i++) { michael@0: if (c2[i] >= '0' && c2[i] <= '9') { michael@0: offset = c2[i] - '0'; michael@0: *byteval |= offset << 4*(1-i); michael@0: } else if (c2[i] >= 'a' && c2[i] <= 'f') { michael@0: offset = c2[i] - 'a'; michael@0: *byteval |= (offset + 10) << 4*(1-i); michael@0: } else if (c2[i] >= 'A' && c2[i] <= 'F') { michael@0: offset = c2[i] - 'A'; michael@0: *byteval |= (offset + 10) << 4*(1-i); michael@0: } else { michael@0: return SECFailure; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: byteval_to_hex(unsigned char byteval, char *c2, char a) michael@0: { michael@0: int i; michael@0: unsigned char offset; michael@0: for (i=0; i<2; i++) { michael@0: offset = (byteval >> 4*(1-i)) & 0x0f; michael@0: if (offset < 10) { michael@0: c2[i] = '0' + offset; michael@0: } else { michael@0: c2[i] = a + offset - 10; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: void michael@0: to_hex_str(char *str, const unsigned char *buf, unsigned int len) michael@0: { michael@0: unsigned int i; michael@0: for (i=0; i 2*len) { michael@0: /* michael@0: * The input hex string is too long, but we allow it if the michael@0: * extra digits are leading 0's. michael@0: */ michael@0: for (j = 0; j < nxdigit-2*len; j++) { michael@0: if (str[j] != '0') { michael@0: return PR_FALSE; michael@0: } michael@0: } michael@0: /* skip leading 0's */ michael@0: str += nxdigit-2*len; michael@0: nxdigit = 2*len; michael@0: } michael@0: for (i=0, j=0; i< len; i++) { michael@0: if (2*i < 2*len-nxdigit) { michael@0: /* Handle a short input as if we padded it with leading 0's. */ michael@0: if (2*i+1 < 2*len-nxdigit) { michael@0: buf[i] = 0; michael@0: } else { michael@0: char tmp[2]; michael@0: tmp[0] = '0'; michael@0: tmp[1] = str[j]; michael@0: hex_to_byteval(tmp, &buf[i]); michael@0: j++; michael@0: } michael@0: } else { michael@0: hex_to_byteval(&str[j], &buf[i]); michael@0: j += 2; michael@0: } michael@0: } michael@0: return PR_TRUE; michael@0: } michael@0: michael@0: SECStatus michael@0: tdea_encrypt_buf( michael@0: int mode, michael@0: const unsigned char *key, michael@0: const unsigned char *iv, michael@0: unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, michael@0: const unsigned char *input, unsigned int inputlen) michael@0: { michael@0: SECStatus rv = SECFailure; michael@0: DESContext *cx; michael@0: unsigned char doublecheck[8*20]; /* 1 to 20 blocks */ michael@0: unsigned int doublechecklen = 0; michael@0: michael@0: cx = DES_CreateContext(key, iv, mode, PR_TRUE); michael@0: if (cx == NULL) { michael@0: goto loser; michael@0: } michael@0: rv = DES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (*outputlen != inputlen) { michael@0: goto loser; michael@0: } michael@0: DES_DestroyContext(cx, PR_TRUE); michael@0: cx = NULL; michael@0: michael@0: /* michael@0: * Doublecheck our result by decrypting the ciphertext and michael@0: * compare the output with the input plaintext. michael@0: */ michael@0: cx = DES_CreateContext(key, iv, mode, PR_FALSE); michael@0: if (cx == NULL) { michael@0: goto loser; michael@0: } michael@0: rv = DES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck, michael@0: output, *outputlen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (doublechecklen != *outputlen) { michael@0: goto loser; michael@0: } michael@0: DES_DestroyContext(cx, PR_TRUE); michael@0: cx = NULL; michael@0: if (memcmp(doublecheck, input, inputlen) != 0) { michael@0: goto loser; michael@0: } michael@0: rv = SECSuccess; michael@0: michael@0: loser: michael@0: if (cx != NULL) { michael@0: DES_DestroyContext(cx, PR_TRUE); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: tdea_decrypt_buf( michael@0: int mode, michael@0: const unsigned char *key, michael@0: const unsigned char *iv, michael@0: unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, michael@0: const unsigned char *input, unsigned int inputlen) michael@0: { michael@0: SECStatus rv = SECFailure; michael@0: DESContext *cx; michael@0: unsigned char doublecheck[8*20]; /* 1 to 20 blocks */ michael@0: unsigned int doublechecklen = 0; michael@0: michael@0: cx = DES_CreateContext(key, iv, mode, PR_FALSE); michael@0: if (cx == NULL) { michael@0: goto loser; michael@0: } michael@0: rv = DES_Decrypt(cx, output, outputlen, maxoutputlen, michael@0: input, inputlen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (*outputlen != inputlen) { michael@0: goto loser; michael@0: } michael@0: DES_DestroyContext(cx, PR_TRUE); michael@0: cx = NULL; michael@0: michael@0: /* michael@0: * Doublecheck our result by encrypting the plaintext and michael@0: * compare the output with the input ciphertext. michael@0: */ michael@0: cx = DES_CreateContext(key, iv, mode, PR_TRUE); michael@0: if (cx == NULL) { michael@0: goto loser; michael@0: } michael@0: rv = DES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck, michael@0: output, *outputlen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (doublechecklen != *outputlen) { michael@0: goto loser; michael@0: } michael@0: DES_DestroyContext(cx, PR_TRUE); michael@0: cx = NULL; michael@0: if (memcmp(doublecheck, input, inputlen) != 0) { michael@0: goto loser; michael@0: } michael@0: rv = SECSuccess; michael@0: michael@0: loser: michael@0: if (cx != NULL) { michael@0: DES_DestroyContext(cx, PR_TRUE); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: * Perform the TDEA Known Answer Test (KAT) or Multi-block Message michael@0: * Test (MMT) in ECB or CBC mode. The KAT (there are five types) michael@0: * and MMT have the same structure: given the key and IV (CBC mode michael@0: * only), encrypt the given plaintext or decrypt the given ciphertext. michael@0: * So we can handle them the same way. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: tdea_kat_mmt(char *reqfn) michael@0: { michael@0: char buf[180]; /* holds one line from the input REQUEST file. michael@0: * needs to be large enough to hold the longest michael@0: * line "CIPHERTEXT = <180 hex digits>\n". michael@0: */ michael@0: FILE *req; /* input stream from the REQUEST file */ michael@0: FILE *resp; /* output stream to the RESPONSE file */ michael@0: int i, j; michael@0: int mode; /* NSS_DES_EDE3 (ECB) or NSS_DES_EDE3_CBC */ michael@0: int crypt = DECRYPT; /* 1 means encrypt, 0 means decrypt */ michael@0: unsigned char key[24]; /* TDEA 3 key bundle */ michael@0: unsigned int numKeys = 0; michael@0: unsigned char iv[8]; /* for all modes except ECB */ michael@0: unsigned char plaintext[8*20]; /* 1 to 20 blocks */ michael@0: unsigned int plaintextlen; michael@0: unsigned char ciphertext[8*20]; /* 1 to 20 blocks */ michael@0: unsigned int ciphertextlen; michael@0: SECStatus rv; michael@0: michael@0: req = fopen(reqfn, "r"); michael@0: resp = stdout; michael@0: while (fgets(buf, sizeof buf, req) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* [ENCRYPT] or [DECRYPT] */ michael@0: if (buf[0] == '[') { michael@0: if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { michael@0: crypt = ENCRYPT; michael@0: } else { michael@0: crypt = DECRYPT; michael@0: } michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* NumKeys */ michael@0: if (strncmp(&buf[0], "NumKeys", 7) == 0) { michael@0: i = 7; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: numKeys = buf[i]; michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* "COUNT = x" begins a new data set */ michael@0: if (strncmp(buf, "COUNT", 5) == 0) { michael@0: /* mode defaults to ECB, if dataset has IV mode will be set CBC */ michael@0: mode = NSS_DES_EDE3; michael@0: /* zeroize the variables for the test with this data set */ michael@0: memset(key, 0, sizeof key); michael@0: memset(iv, 0, sizeof iv); michael@0: memset(plaintext, 0, sizeof plaintext); michael@0: plaintextlen = 0; michael@0: memset(ciphertext, 0, sizeof ciphertext); michael@0: ciphertextlen = 0; michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: if (numKeys == 0) { michael@0: if (strncmp(buf, "KEYs", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: key[j+8] = key[j]; michael@0: key[j+16] = key[j]; michael@0: } michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: } else { michael@0: /* KEY1 = ... */ michael@0: if (strncmp(buf, "KEY1", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* KEY2 = ... */ michael@0: if (strncmp(buf, "KEY2", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=8; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* KEY3 = ... */ michael@0: if (strncmp(buf, "KEY3", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=16; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: /* IV = ... */ michael@0: if (strncmp(buf, "IV", 2) == 0) { michael@0: mode = NSS_DES_EDE3_CBC; michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j> 4; michael@0: in ^= in >> 2; michael@0: in ^= in >> 1; michael@0: return (BYTE)(out ^ !(in & 1)); michael@0: } michael@0: michael@0: /* michael@0: * Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j] michael@0: * for TDEA Monte Carlo Test (MCT) in ECB and CBC modes. michael@0: */ michael@0: void michael@0: tdea_mct_next_keys(unsigned char *key, michael@0: const unsigned char *text_2, const unsigned char *text_1, michael@0: const unsigned char *text, unsigned int numKeys) michael@0: { michael@0: int k; michael@0: michael@0: /* key1[i+1] = key1[i] xor PT/CT[j] */ michael@0: for (k=0; k<8; k++) { michael@0: key[k] ^= text[k]; michael@0: } michael@0: /* key2 */ michael@0: if (numKeys == 2 || numKeys == 3) { michael@0: /* key2 independent */ michael@0: for (k=8; k<16; k++) { michael@0: /* key2[i+1] = KEY2[i] xor PT/CT[j-1] */ michael@0: key[k] ^= text_1[k-8]; michael@0: } michael@0: } else { michael@0: /* key2 == key 1 */ michael@0: for (k=8; k<16; k++) { michael@0: /* key2[i+1] = KEY2[i] xor PT/CT[j] */ michael@0: key[k] = key[k-8]; michael@0: } michael@0: } michael@0: /* key3 */ michael@0: if (numKeys == 1 || numKeys == 2) { michael@0: /* key3 == key 1 */ michael@0: for (k=16; k<24; k++) { michael@0: /* key3[i+1] = KEY3[i] xor PT/CT[j] */ michael@0: key[k] = key[k-16]; michael@0: } michael@0: } else { michael@0: /* key3 independent */ michael@0: for (k=16; k<24; k++) { michael@0: /* key3[i+1] = KEY3[i] xor PT/CT[j-2] */ michael@0: key[k] ^= text_2[k-16]; michael@0: } michael@0: } michael@0: /* set the parity bits */ michael@0: for (k=0; k<24; k++) { michael@0: key[k] = odd_parity(key[k]); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Perform the Monte Carlo Test michael@0: * michael@0: * mode = NSS_DES_EDE3 or NSS_DES_EDE3_CBC michael@0: * crypt = ENCRYPT || DECRYPT michael@0: * inputtext = plaintext or Cyphertext depending on the value of crypt michael@0: * inputlength is expected to be size 8 bytes michael@0: * iv = needs to be set for NSS_DES_EDE3_CBC mode michael@0: * resp = is the output response file. michael@0: */ michael@0: void michael@0: tdea_mct_test(int mode, unsigned char* key, unsigned int numKeys, michael@0: unsigned int crypt, unsigned char* inputtext, michael@0: unsigned int inputlength, unsigned char* iv, FILE *resp) { michael@0: michael@0: int i, j; michael@0: unsigned char outputtext_1[8]; /* PT/CT[j-1] */ michael@0: unsigned char outputtext_2[8]; /* PT/CT[j-2] */ michael@0: char buf[80]; /* holds one line from the input REQUEST file. */ michael@0: unsigned int outputlen; michael@0: unsigned char outputtext[8]; michael@0: michael@0: michael@0: SECStatus rv; michael@0: michael@0: if (mode == NSS_DES_EDE3 && iv != NULL) { michael@0: printf("IV must be NULL for NSS_DES_EDE3 mode"); michael@0: goto loser; michael@0: } else if (mode == NSS_DES_EDE3_CBC && iv == NULL) { michael@0: printf("IV must not be NULL for NSS_DES_EDE3_CBC mode"); michael@0: goto loser; michael@0: } michael@0: michael@0: /* loop 400 times */ michael@0: for (i=0; i<400; i++) { michael@0: /* if i == 0 CV[0] = IV not necessary */ michael@0: /* record the count and key values and plainText */ michael@0: sprintf(buf, "COUNT = %d\n", i); michael@0: fputs(buf, resp); michael@0: /* Output KEY1[i] */ michael@0: fputs("KEY1 = ", resp); michael@0: to_hex_str(buf, key, 8); michael@0: fputs(buf, resp); michael@0: fputc('\n', resp); michael@0: /* Output KEY2[i] */ michael@0: fputs("KEY2 = ", resp); michael@0: to_hex_str(buf, &key[8], 8); michael@0: fputs(buf, resp); michael@0: fputc('\n', resp); michael@0: /* Output KEY3[i] */ michael@0: fputs("KEY3 = ", resp); michael@0: to_hex_str(buf, &key[16], 8); michael@0: fputs(buf, resp); michael@0: fputc('\n', resp); michael@0: if (mode == NSS_DES_EDE3_CBC) { michael@0: /* Output CV[i] */ michael@0: fputs("IV = ", resp); michael@0: to_hex_str(buf, iv, 8); michael@0: fputs(buf, resp); michael@0: fputc('\n', resp); michael@0: } michael@0: if (crypt == ENCRYPT) { michael@0: /* Output PT[0] */ michael@0: fputs("PLAINTEXT = ", resp); michael@0: } else { michael@0: /* Output CT[0] */ michael@0: fputs("CIPHERTEXT = ", resp); michael@0: } michael@0: michael@0: to_hex_str(buf, inputtext, inputlength); michael@0: fputs(buf, resp); michael@0: fputc('\n', resp); michael@0: michael@0: /* loop 10,000 times */ michael@0: for (j=0; j<10000; j++) { michael@0: michael@0: outputlen = 0; michael@0: if (crypt == ENCRYPT) { michael@0: /* inputtext == ciphertext outputtext == plaintext*/ michael@0: rv = tdea_encrypt_buf(mode, key, michael@0: (mode == NSS_DES_EDE3) ? NULL : iv, michael@0: outputtext, &outputlen, 8, michael@0: inputtext, 8); michael@0: } else { michael@0: /* inputtext == plaintext outputtext == ciphertext */ michael@0: rv = tdea_decrypt_buf(mode, key, michael@0: (mode == NSS_DES_EDE3) ? NULL : iv, michael@0: outputtext, &outputlen, 8, michael@0: inputtext, 8); michael@0: } michael@0: michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (outputlen != inputlength) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (mode == NSS_DES_EDE3_CBC) { michael@0: if (crypt == ENCRYPT) { michael@0: if (j == 0) { michael@0: /*P[j+1] = CV[0] */ michael@0: memcpy(inputtext, iv, 8); michael@0: } else { michael@0: /* p[j+1] = C[j-1] */ michael@0: memcpy(inputtext, outputtext_1, 8); michael@0: } michael@0: /* CV[j+1] = C[j] */ michael@0: memcpy(iv, outputtext, 8); michael@0: if (j != 9999) { michael@0: /* save C[j-1] */ michael@0: memcpy(outputtext_1, outputtext, 8); michael@0: } michael@0: } else { /* DECRYPT */ michael@0: /* CV[j+1] = C[j] */ michael@0: memcpy(iv, inputtext, 8); michael@0: /* C[j+1] = P[j] */ michael@0: memcpy(inputtext, outputtext, 8); michael@0: } michael@0: } else { michael@0: /* ECB mode PT/CT[j+1] = CT/PT[j] */ michael@0: memcpy(inputtext, outputtext, 8); michael@0: } michael@0: michael@0: /* Save PT/CT[j-2] and PT/CT[j-1] */ michael@0: if (j==9997) memcpy(outputtext_2, outputtext, 8); michael@0: if (j==9998) memcpy(outputtext_1, outputtext, 8); michael@0: /* done at the end of the for(j) loop */ michael@0: } michael@0: michael@0: michael@0: if (crypt == ENCRYPT) { michael@0: /* Output CT[j] */ michael@0: fputs("CIPHERTEXT = ", resp); michael@0: } else { michael@0: /* Output PT[j] */ michael@0: fputs("PLAINTEXT = ", resp); michael@0: } michael@0: to_hex_str(buf, outputtext, 8); michael@0: fputs(buf, resp); michael@0: fputc('\n', resp); michael@0: michael@0: /* Key[i+1] = Key[i] xor ... outputtext_2 == PT/CT[j-2] michael@0: * outputtext_1 == PT/CT[j-1] outputtext == PT/CT[j] michael@0: */ michael@0: tdea_mct_next_keys(key, outputtext_2, michael@0: outputtext_1, outputtext, numKeys); michael@0: michael@0: if (mode == NSS_DES_EDE3_CBC) { michael@0: /* taken care of in the j=9999 iteration */ michael@0: if (crypt == ENCRYPT) { michael@0: /* P[i] = C[j-1] */ michael@0: /* CV[i] = C[j] */ michael@0: } else { michael@0: /* taken care of in the j=9999 iteration */ michael@0: /* CV[i] = C[j] */ michael@0: /* C[i] = P[j] */ michael@0: } michael@0: } else { michael@0: /* ECB PT/CT[i] = PT/CT[j] */ michael@0: memcpy(inputtext, outputtext, 8); michael@0: } michael@0: /* done at the end of the for(i) loop */ michael@0: fputc('\n', resp); michael@0: } michael@0: michael@0: loser: michael@0: return; michael@0: } michael@0: michael@0: /* michael@0: * Perform the TDEA Monte Carlo Test (MCT) in ECB/CBC modes. michael@0: * by gathering the input from the request file, and then michael@0: * calling tdea_mct_test. michael@0: * michael@0: * reqfn is the pathname of the input REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: tdea_mct(int mode, char *reqfn) michael@0: { michael@0: int i, j; michael@0: char buf[80]; /* holds one line from the input REQUEST file. */ michael@0: FILE *req; /* input stream from the REQUEST file */ michael@0: FILE *resp; /* output stream to the RESPONSE file */ michael@0: unsigned int crypt = 0; /* 1 means encrypt, 0 means decrypt */ michael@0: unsigned char key[24]; /* TDEA 3 key bundle */ michael@0: unsigned int numKeys = 0; michael@0: unsigned char plaintext[8]; /* PT[j] */ michael@0: unsigned char ciphertext[8]; /* CT[j] */ michael@0: unsigned char iv[8]; michael@0: michael@0: /* zeroize the variables for the test with this data set */ michael@0: memset(key, 0, sizeof key); michael@0: memset(plaintext, 0, sizeof plaintext); michael@0: memset(ciphertext, 0, sizeof ciphertext); michael@0: memset(iv, 0, sizeof iv); michael@0: michael@0: req = fopen(reqfn, "r"); michael@0: resp = stdout; michael@0: while (fgets(buf, sizeof buf, req) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* [ENCRYPT] or [DECRYPT] */ michael@0: if (buf[0] == '[') { michael@0: if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { michael@0: crypt = ENCRYPT; michael@0: } else { michael@0: crypt = DECRYPT; michael@0: } michael@0: fputs(buf, resp); michael@0: continue; michael@0: } michael@0: /* NumKeys */ michael@0: if (strncmp(&buf[0], "NumKeys", 7) == 0) { michael@0: i = 7; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: numKeys = atoi(&buf[i]); michael@0: continue; michael@0: } michael@0: /* KEY1 = ... */ michael@0: if (strncmp(buf, "KEY1", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: continue; michael@0: } michael@0: /* KEY2 = ... */ michael@0: if (strncmp(buf, "KEY2", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=8; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: continue; michael@0: } michael@0: /* KEY3 = ... */ michael@0: if (strncmp(buf, "KEY3", 4) == 0) { michael@0: i = 4; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=16; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: continue; michael@0: } michael@0: michael@0: /* IV = ... */ michael@0: if (strncmp(buf, "IV", 2) == 0) { michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j\n". michael@0: */ michael@0: FILE *aesreq; /* input stream from the REQUEST file */ michael@0: FILE *aesresp; /* output stream to the RESPONSE file */ michael@0: int i, j; michael@0: int mode; /* NSS_AES (ECB) or NSS_AES_CBC */ michael@0: int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ michael@0: unsigned char key[32]; /* 128, 192, or 256 bits */ michael@0: unsigned int keysize; michael@0: unsigned char iv[16]; /* for all modes except ECB */ michael@0: unsigned char plaintext[10*16]; /* 1 to 10 blocks */ michael@0: unsigned int plaintextlen; michael@0: unsigned char ciphertext[10*16]; /* 1 to 10 blocks */ michael@0: unsigned int ciphertextlen; michael@0: SECStatus rv; michael@0: michael@0: aesreq = fopen(reqfn, "r"); michael@0: aesresp = stdout; michael@0: while (fgets(buf, sizeof buf, aesreq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* [ENCRYPT] or [DECRYPT] */ michael@0: if (buf[0] == '[') { michael@0: if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { michael@0: encrypt = 1; michael@0: } else { michael@0: encrypt = 0; michael@0: } michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* "COUNT = x" begins a new data set */ michael@0: if (strncmp(buf, "COUNT", 5) == 0) { michael@0: mode = NSS_AES; michael@0: /* zeroize the variables for the test with this data set */ michael@0: memset(key, 0, sizeof key); michael@0: keysize = 0; michael@0: memset(iv, 0, sizeof iv); michael@0: memset(plaintext, 0, sizeof plaintext); michael@0: plaintextlen = 0; michael@0: memset(ciphertext, 0, sizeof ciphertext); michael@0: ciphertextlen = 0; michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* KEY = ... */ michael@0: if (strncmp(buf, "KEY", 3) == 0) { michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: keysize = j; michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* IV = ... */ michael@0: if (strncmp(buf, "IV", 2) == 0) { michael@0: mode = NSS_AES_CBC; michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j\n". michael@0: */ michael@0: FILE *aesreq; /* input stream from the REQUEST file */ michael@0: FILE *aesresp; /* output stream to the RESPONSE file */ michael@0: int i, j; michael@0: int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ michael@0: unsigned char key[32]; /* 128, 192, or 256 bits */ michael@0: unsigned int keysize; michael@0: unsigned char plaintext[16]; /* PT[j] */ michael@0: unsigned char plaintext_1[16]; /* PT[j-1] */ michael@0: unsigned char ciphertext[16]; /* CT[j] */ michael@0: unsigned char ciphertext_1[16]; /* CT[j-1] */ michael@0: unsigned char doublecheck[16]; michael@0: unsigned int outputlen; michael@0: AESContext *cx = NULL; /* the operation being tested */ michael@0: AESContext *cx2 = NULL; /* the inverse operation done in parallel michael@0: * to doublecheck our result. michael@0: */ michael@0: SECStatus rv; michael@0: michael@0: aesreq = fopen(reqfn, "r"); michael@0: aesresp = stdout; michael@0: while (fgets(buf, sizeof buf, aesreq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* [ENCRYPT] or [DECRYPT] */ michael@0: if (buf[0] == '[') { michael@0: if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { michael@0: encrypt = 1; michael@0: } else { michael@0: encrypt = 0; michael@0: } michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* "COUNT = x" begins a new data set */ michael@0: if (strncmp(buf, "COUNT", 5) == 0) { michael@0: /* zeroize the variables for the test with this data set */ michael@0: memset(key, 0, sizeof key); michael@0: keysize = 0; michael@0: memset(plaintext, 0, sizeof plaintext); michael@0: memset(ciphertext, 0, sizeof ciphertext); michael@0: continue; michael@0: } michael@0: /* KEY = ... */ michael@0: if (strncmp(buf, "KEY", 3) == 0) { michael@0: /* Key[0] = Key */ michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: keysize = j; michael@0: continue; michael@0: } michael@0: /* PLAINTEXT = ... */ michael@0: if (strncmp(buf, "PLAINTEXT", 9) == 0) { michael@0: /* sanity check */ michael@0: if (!encrypt) { michael@0: goto loser; michael@0: } michael@0: /* PT[0] = PT */ michael@0: i = 9; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j\n". michael@0: */ michael@0: FILE *aesreq; /* input stream from the REQUEST file */ michael@0: FILE *aesresp; /* output stream to the RESPONSE file */ michael@0: int i, j; michael@0: int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ michael@0: unsigned char key[32]; /* 128, 192, or 256 bits */ michael@0: unsigned int keysize; michael@0: unsigned char iv[16]; michael@0: unsigned char plaintext[16]; /* PT[j] */ michael@0: unsigned char plaintext_1[16]; /* PT[j-1] */ michael@0: unsigned char ciphertext[16]; /* CT[j] */ michael@0: unsigned char ciphertext_1[16]; /* CT[j-1] */ michael@0: unsigned char doublecheck[16]; michael@0: unsigned int outputlen; michael@0: AESContext *cx = NULL; /* the operation being tested */ michael@0: AESContext *cx2 = NULL; /* the inverse operation done in parallel michael@0: * to doublecheck our result. michael@0: */ michael@0: SECStatus rv; michael@0: michael@0: aesreq = fopen(reqfn, "r"); michael@0: aesresp = stdout; michael@0: while (fgets(buf, sizeof buf, aesreq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* [ENCRYPT] or [DECRYPT] */ michael@0: if (buf[0] == '[') { michael@0: if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { michael@0: encrypt = 1; michael@0: } else { michael@0: encrypt = 0; michael@0: } michael@0: fputs(buf, aesresp); michael@0: continue; michael@0: } michael@0: /* "COUNT = x" begins a new data set */ michael@0: if (strncmp(buf, "COUNT", 5) == 0) { michael@0: /* zeroize the variables for the test with this data set */ michael@0: memset(key, 0, sizeof key); michael@0: keysize = 0; michael@0: memset(iv, 0, sizeof iv); michael@0: memset(plaintext, 0, sizeof plaintext); michael@0: memset(ciphertext, 0, sizeof ciphertext); michael@0: continue; michael@0: } michael@0: /* KEY = ... */ michael@0: if (strncmp(buf, "KEY", 3) == 0) { michael@0: /* Key[0] = Key */ michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &key[j]); michael@0: } michael@0: keysize = j; michael@0: continue; michael@0: } michael@0: /* IV = ... */ michael@0: if (strncmp(buf, "IV", 2) == 0) { michael@0: /* IV[0] = IV */ michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; joid.len)); michael@0: michael@0: /* michael@0: * ecparams->data needs to contain the ASN encoding of an object ID (OID) michael@0: * representing the named curve. The actual OID is in michael@0: * oidData->oid.data so we simply prepend 0x06 and OID length michael@0: */ michael@0: ecparams->data[0] = SEC_ASN1_OBJECT_ID; michael@0: ecparams->data[1] = oidData->oid.len; michael@0: memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len); michael@0: michael@0: return ecparams; michael@0: } michael@0: michael@0: /* michael@0: * Perform the ECDSA Key Pair Generation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: ecdsa_keypair_test(char *reqfn) michael@0: { michael@0: char buf[256]; /* holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * needs to be large enough to hold the longest michael@0: * line "Qx = <144 hex digits>\n". michael@0: */ michael@0: FILE *ecdsareq; /* input stream from the REQUEST file */ michael@0: FILE *ecdsaresp; /* output stream to the RESPONSE file */ michael@0: char curve[16]; /* "nistxddd" */ michael@0: ECParams *ecparams; michael@0: int N; michael@0: int i; michael@0: unsigned int len; michael@0: michael@0: ecdsareq = fopen(reqfn, "r"); michael@0: ecdsaresp = stdout; michael@0: strcpy(curve, "nist"); michael@0: while (fgets(buf, sizeof buf, ecdsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* [X-ddd] */ michael@0: if (buf[0] == '[') { michael@0: const char *src; michael@0: char *dst; michael@0: SECItem *encodedparams; michael@0: michael@0: src = &buf[1]; michael@0: dst = &curve[4]; michael@0: *dst++ = tolower(*src); michael@0: src += 2; /* skip the hyphen */ michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst = '\0'; michael@0: encodedparams = getECParams(curve); michael@0: if (encodedparams == NULL) { michael@0: goto loser; michael@0: } michael@0: if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: SECITEM_FreeItem(encodedparams, PR_TRUE); michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* N = x */ michael@0: if (buf[0] == 'N') { michael@0: if (sscanf(buf, "N = %d", &N) != 1) { michael@0: goto loser; michael@0: } michael@0: for (i = 0; i < N; i++) { michael@0: ECPrivateKey *ecpriv; michael@0: michael@0: if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: fputs("d = ", ecdsaresp); michael@0: to_hex_str(buf, ecpriv->privateValue.data, michael@0: ecpriv->privateValue.len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue) michael@0: != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: len = ecpriv->publicValue.len; michael@0: if (len%2 == 0) { michael@0: goto loser; michael@0: } michael@0: len = (len-1)/2; michael@0: if (ecpriv->publicValue.data[0] michael@0: != EC_POINT_FORM_UNCOMPRESSED) { michael@0: goto loser; michael@0: } michael@0: fputs("Qx = ", ecdsaresp); michael@0: to_hex_str(buf, &ecpriv->publicValue.data[1], len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: fputs("Qy = ", ecdsaresp); michael@0: to_hex_str(buf, &ecpriv->publicValue.data[1+len], len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE); michael@0: } michael@0: PORT_FreeArena(ecparams->arena, PR_FALSE); michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: fclose(ecdsareq); michael@0: } michael@0: michael@0: /* michael@0: * Perform the ECDSA Public Key Validation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: ecdsa_pkv_test(char *reqfn) michael@0: { michael@0: char buf[256]; /* holds one line from the input REQUEST file. michael@0: * needs to be large enough to hold the longest michael@0: * line "Qx = <144 hex digits>\n". michael@0: */ michael@0: FILE *ecdsareq; /* input stream from the REQUEST file */ michael@0: FILE *ecdsaresp; /* output stream to the RESPONSE file */ michael@0: char curve[16]; /* "nistxddd" */ michael@0: ECParams *ecparams = NULL; michael@0: SECItem pubkey; michael@0: unsigned int i; michael@0: unsigned int len; michael@0: PRBool keyvalid = PR_TRUE; michael@0: michael@0: ecdsareq = fopen(reqfn, "r"); michael@0: ecdsaresp = stdout; michael@0: strcpy(curve, "nist"); michael@0: pubkey.data = NULL; michael@0: while (fgets(buf, sizeof buf, ecdsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* [X-ddd] */ michael@0: if (buf[0] == '[') { michael@0: const char *src; michael@0: char *dst; michael@0: SECItem *encodedparams; michael@0: michael@0: src = &buf[1]; michael@0: dst = &curve[4]; michael@0: *dst++ = tolower(*src); michael@0: src += 2; /* skip the hyphen */ michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst = '\0'; michael@0: if (ecparams != NULL) { michael@0: PORT_FreeArena(ecparams->arena, PR_FALSE); michael@0: ecparams = NULL; michael@0: } michael@0: encodedparams = getECParams(curve); michael@0: if (encodedparams == NULL) { michael@0: goto loser; michael@0: } michael@0: if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: SECITEM_FreeItem(encodedparams, PR_TRUE); michael@0: len = (ecparams->fieldID.size + 7) >> 3; michael@0: if (pubkey.data != NULL) { michael@0: PORT_Free(pubkey.data); michael@0: pubkey.data = NULL; michael@0: } michael@0: SECITEM_AllocItem(NULL, &pubkey, 2*len+1); michael@0: if (pubkey.data == NULL) { michael@0: goto loser; michael@0: } michael@0: pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED; michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* Qx = ... */ michael@0: if (strncmp(buf, "Qx", 2) == 0) { michael@0: fputs(buf, ecdsaresp); michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: keyvalid = from_hex_str(&pubkey.data[1], len, &buf[i]); michael@0: continue; michael@0: } michael@0: /* Qy = ... */ michael@0: if (strncmp(buf, "Qy", 2) == 0) { michael@0: fputs(buf, ecdsaresp); michael@0: if (!keyvalid) { michael@0: fputs("Result = F\n", ecdsaresp); michael@0: continue; michael@0: } michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: keyvalid = from_hex_str(&pubkey.data[1+len], len, &buf[i]); michael@0: if (!keyvalid) { michael@0: fputs("Result = F\n", ecdsaresp); michael@0: continue; michael@0: } michael@0: if (EC_ValidatePublicKey(ecparams, &pubkey) == SECSuccess) { michael@0: fputs("Result = P\n", ecdsaresp); michael@0: } else if (PORT_GetError() == SEC_ERROR_BAD_KEY) { michael@0: fputs("Result = F\n", ecdsaresp); michael@0: } else { michael@0: goto loser; michael@0: } michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: if (ecparams != NULL) { michael@0: PORT_FreeArena(ecparams->arena, PR_FALSE); michael@0: } michael@0: if (pubkey.data != NULL) { michael@0: PORT_Free(pubkey.data); michael@0: } michael@0: fclose(ecdsareq); michael@0: } michael@0: michael@0: /* michael@0: * Perform the ECDSA Signature Generation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: ecdsa_siggen_test(char *reqfn) michael@0: { michael@0: char buf[1024]; /* holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * needs to be large enough to hold the longest michael@0: * line "Msg = <256 hex digits>\n". michael@0: */ michael@0: FILE *ecdsareq; /* input stream from the REQUEST file */ michael@0: FILE *ecdsaresp; /* output stream to the RESPONSE file */ michael@0: char curve[16]; /* "nistxddd" */ michael@0: ECParams *ecparams = NULL; michael@0: int i, j; michael@0: unsigned int len; michael@0: unsigned char msg[512]; /* message to be signed (<= 128 bytes) */ michael@0: unsigned int msglen; michael@0: unsigned char sha1[20]; /* SHA-1 hash (160 bits) */ michael@0: unsigned char sig[2*MAX_ECKEY_LEN]; michael@0: SECItem signature, digest; michael@0: michael@0: ecdsareq = fopen(reqfn, "r"); michael@0: ecdsaresp = stdout; michael@0: strcpy(curve, "nist"); michael@0: while (fgets(buf, sizeof buf, ecdsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* [X-ddd] */ michael@0: if (buf[0] == '[') { michael@0: const char *src; michael@0: char *dst; michael@0: SECItem *encodedparams; michael@0: michael@0: src = &buf[1]; michael@0: dst = &curve[4]; michael@0: *dst++ = tolower(*src); michael@0: src += 2; /* skip the hyphen */ michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst = '\0'; michael@0: if (ecparams != NULL) { michael@0: PORT_FreeArena(ecparams->arena, PR_FALSE); michael@0: ecparams = NULL; michael@0: } michael@0: encodedparams = getECParams(curve); michael@0: if (encodedparams == NULL) { michael@0: goto loser; michael@0: } michael@0: if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: SECITEM_FreeItem(encodedparams, PR_TRUE); michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* Msg = ... */ michael@0: if (strncmp(buf, "Msg", 3) == 0) { michael@0: ECPrivateKey *ecpriv; michael@0: michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &msg[j]); michael@0: } michael@0: msglen = j; michael@0: if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: fputs(buf, ecdsaresp); michael@0: michael@0: if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue) michael@0: != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: len = ecpriv->publicValue.len; michael@0: if (len%2 == 0) { michael@0: goto loser; michael@0: } michael@0: len = (len-1)/2; michael@0: if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { michael@0: goto loser; michael@0: } michael@0: fputs("Qx = ", ecdsaresp); michael@0: to_hex_str(buf, &ecpriv->publicValue.data[1], len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: fputs("Qy = ", ecdsaresp); michael@0: to_hex_str(buf, &ecpriv->publicValue.data[1+len], len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: michael@0: digest.type = siBuffer; michael@0: digest.data = sha1; michael@0: digest.len = sizeof sha1; michael@0: signature.type = siBuffer; michael@0: signature.data = sig; michael@0: signature.len = sizeof sig; michael@0: if (ECDSA_SignDigest(ecpriv, &signature, &digest) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: len = signature.len; michael@0: if (len%2 != 0) { michael@0: goto loser; michael@0: } michael@0: len = len/2; michael@0: fputs("R = ", ecdsaresp); michael@0: to_hex_str(buf, &signature.data[0], len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: fputs("S = ", ecdsaresp); michael@0: to_hex_str(buf, &signature.data[len], len); michael@0: fputs(buf, ecdsaresp); michael@0: fputc('\n', ecdsaresp); michael@0: michael@0: PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE); michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: if (ecparams != NULL) { michael@0: PORT_FreeArena(ecparams->arena, PR_FALSE); michael@0: } michael@0: fclose(ecdsareq); michael@0: } michael@0: michael@0: /* michael@0: * Perform the ECDSA Signature Verification Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: ecdsa_sigver_test(char *reqfn) michael@0: { michael@0: char buf[1024]; /* holds one line from the input REQUEST file. michael@0: * needs to be large enough to hold the longest michael@0: * line "Msg = <256 hex digits>\n". michael@0: */ michael@0: FILE *ecdsareq; /* input stream from the REQUEST file */ michael@0: FILE *ecdsaresp; /* output stream to the RESPONSE file */ michael@0: char curve[16]; /* "nistxddd" */ michael@0: ECPublicKey ecpub; michael@0: unsigned int i, j; michael@0: unsigned int flen; /* length in bytes of the field size */ michael@0: unsigned int olen; /* length in bytes of the base point order */ michael@0: unsigned char msg[512]; /* message that was signed (<= 128 bytes) */ michael@0: unsigned int msglen; michael@0: unsigned char sha1[20]; /* SHA-1 hash (160 bits) */ michael@0: unsigned char sig[2*MAX_ECKEY_LEN]; michael@0: SECItem signature, digest; michael@0: PRBool keyvalid = PR_TRUE; michael@0: PRBool sigvalid = PR_TRUE; michael@0: michael@0: ecdsareq = fopen(reqfn, "r"); michael@0: ecdsaresp = stdout; michael@0: ecpub.ecParams.arena = NULL; michael@0: strcpy(curve, "nist"); michael@0: while (fgets(buf, sizeof buf, ecdsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* [X-ddd] */ michael@0: if (buf[0] == '[') { michael@0: const char *src; michael@0: char *dst; michael@0: SECItem *encodedparams; michael@0: ECParams *ecparams; michael@0: michael@0: src = &buf[1]; michael@0: dst = &curve[4]; michael@0: *dst++ = tolower(*src); michael@0: src += 2; /* skip the hyphen */ michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst++ = *src++; michael@0: *dst = '\0'; michael@0: encodedparams = getECParams(curve); michael@0: if (encodedparams == NULL) { michael@0: goto loser; michael@0: } michael@0: if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: SECITEM_FreeItem(encodedparams, PR_TRUE); michael@0: if (ecpub.ecParams.arena != NULL) { michael@0: PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE); michael@0: } michael@0: ecpub.ecParams.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (ecpub.ecParams.arena == NULL) { michael@0: goto loser; michael@0: } michael@0: if (EC_CopyParams(ecpub.ecParams.arena, &ecpub.ecParams, ecparams) michael@0: != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: PORT_FreeArena(ecparams->arena, PR_FALSE); michael@0: flen = (ecpub.ecParams.fieldID.size + 7) >> 3; michael@0: olen = ecpub.ecParams.order.len; michael@0: if (2*olen > sizeof sig) { michael@0: goto loser; michael@0: } michael@0: ecpub.publicValue.type = siBuffer; michael@0: ecpub.publicValue.data = NULL; michael@0: ecpub.publicValue.len = 0; michael@0: SECITEM_AllocItem(ecpub.ecParams.arena, michael@0: &ecpub.publicValue, 2*flen+1); michael@0: if (ecpub.publicValue.data == NULL) { michael@0: goto loser; michael@0: } michael@0: ecpub.publicValue.data[0] = EC_POINT_FORM_UNCOMPRESSED; michael@0: fputs(buf, ecdsaresp); michael@0: continue; michael@0: } michael@0: /* Msg = ... */ michael@0: if (strncmp(buf, "Msg", 3) == 0) { michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &msg[j]); michael@0: } michael@0: msglen = j; michael@0: if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: fputs(buf, ecdsaresp); michael@0: michael@0: digest.type = siBuffer; michael@0: digest.data = sha1; michael@0: digest.len = sizeof sha1; michael@0: michael@0: continue; michael@0: } michael@0: /* Qx = ... */ michael@0: if (strncmp(buf, "Qx", 2) == 0) { michael@0: fputs(buf, ecdsaresp); michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: keyvalid = from_hex_str(&ecpub.publicValue.data[1], flen, michael@0: &buf[i]); michael@0: continue; michael@0: } michael@0: /* Qy = ... */ michael@0: if (strncmp(buf, "Qy", 2) == 0) { michael@0: fputs(buf, ecdsaresp); michael@0: if (!keyvalid) { michael@0: continue; michael@0: } michael@0: i = 2; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: keyvalid = from_hex_str(&ecpub.publicValue.data[1+flen], flen, michael@0: &buf[i]); michael@0: if (!keyvalid) { michael@0: continue; michael@0: } michael@0: if (EC_ValidatePublicKey(&ecpub.ecParams, &ecpub.publicValue) michael@0: != SECSuccess) { michael@0: if (PORT_GetError() == SEC_ERROR_BAD_KEY) { michael@0: keyvalid = PR_FALSE; michael@0: } else { michael@0: goto loser; michael@0: } michael@0: } michael@0: continue; michael@0: } michael@0: /* R = ... */ michael@0: if (buf[0] == 'R') { michael@0: fputs(buf, ecdsaresp); michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: sigvalid = from_hex_str(sig, olen, &buf[i]); michael@0: continue; michael@0: } michael@0: /* S = ... */ michael@0: if (buf[0] == 'S') { michael@0: fputs(buf, ecdsaresp); michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: if (sigvalid) { michael@0: sigvalid = from_hex_str(&sig[olen], olen, &buf[i]); michael@0: } michael@0: signature.type = siBuffer; michael@0: signature.data = sig; michael@0: signature.len = 2*olen; michael@0: michael@0: if (!keyvalid || !sigvalid) { michael@0: fputs("Result = F\n", ecdsaresp); michael@0: } else if (ECDSA_VerifyDigest(&ecpub, &signature, &digest) michael@0: == SECSuccess) { michael@0: fputs("Result = P\n", ecdsaresp); michael@0: } else { michael@0: fputs("Result = F\n", ecdsaresp); michael@0: } michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: if (ecpub.ecParams.arena != NULL) { michael@0: PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE); michael@0: } michael@0: fclose(ecdsareq); michael@0: } michael@0: #endif /* NSS_DISABLE_ECC */ michael@0: michael@0: michael@0: /* michael@0: * Read a value from the test and allocate the result. michael@0: */ michael@0: static unsigned char * michael@0: alloc_value(char *buf, int *len) michael@0: { michael@0: unsigned char * value; michael@0: int i, count; michael@0: michael@0: if (strncmp(buf, "", 6) == 0) { michael@0: *len = 0; michael@0: return NULL; michael@0: } michael@0: michael@0: /* find the length of the number */ michael@0: for (count = 0; isxdigit(buf[count]); count++); michael@0: *len = count/2; michael@0: michael@0: if (*len == 0) { michael@0: return NULL; michael@0: } michael@0: michael@0: value = PORT_Alloc(*len); michael@0: if (!value) { michael@0: *len = 0; michael@0: return NULL; michael@0: } michael@0: michael@0: for (i=0; i<*len; buf+=2 , i++) { michael@0: hex_to_byteval(buf, &value[i]); michael@0: } michael@0: michael@0: michael@0: return value; michael@0: } michael@0: michael@0: PRBool michael@0: isblankline(char *b) michael@0: { michael@0: while (isspace(*b)) b++; michael@0: if ((*b == '\n') || (*b == 0)) { michael@0: return PR_TRUE; michael@0: } michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: static int debug = 0; michael@0: michael@0: /* michael@0: * Perform the Hash_DRBG (CAVS) for the RNG algorithm michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: drbg(char *reqfn) michael@0: { michael@0: char buf[2000]; /* test case has some very long lines, returned bits michael@0: * as high as 800 bytes (6400 bits). That 1600 byte michael@0: * plus a tag */ michael@0: char buf2[2000]; michael@0: FILE *rngreq; /* input stream from the REQUEST file */ michael@0: FILE *rngresp; /* output stream to the RESPONSE file */ michael@0: michael@0: unsigned int i, j; michael@0: PRBool predictionResistance = PR_FALSE; michael@0: unsigned char *nonce = NULL; michael@0: int nonceLen = 0; michael@0: unsigned char *personalizationString = NULL; michael@0: int personalizationStringLen = 0; michael@0: unsigned char *additionalInput = NULL; michael@0: int additionalInputLen = 0; michael@0: unsigned char *entropyInput = NULL; michael@0: int entropyInputLen = 0; michael@0: unsigned char predictedreturn_bytes[SHA256_LENGTH]; michael@0: unsigned char return_bytes[SHA256_LENGTH]; michael@0: int return_bytes_len = SHA256_LENGTH; michael@0: enum { NONE, INSTANTIATE, GENERATE, RESEED, RESULT } command = michael@0: NONE; michael@0: PRBool genResult = PR_FALSE; michael@0: SECStatus rv; michael@0: michael@0: rngreq = fopen(reqfn, "r"); michael@0: rngresp = stdout; michael@0: while (fgets(buf, sizeof buf, rngreq) != NULL) { michael@0: switch (command) { michael@0: case INSTANTIATE: michael@0: if (debug) { michael@0: fputs("# PRNGTEST_Instantiate(",rngresp); michael@0: to_hex_str(buf2,entropyInput, entropyInputLen); michael@0: fputs(buf2,rngresp); michael@0: fprintf(rngresp,",%d,",entropyInputLen); michael@0: to_hex_str(buf2,nonce, nonceLen); michael@0: fputs(buf2,rngresp); michael@0: fprintf(rngresp,",%d,",nonceLen); michael@0: to_hex_str(buf2,personalizationString, michael@0: personalizationStringLen); michael@0: fputs(buf2,rngresp); michael@0: fprintf(rngresp,",%d)\n", personalizationStringLen); michael@0: } michael@0: rv = PRNGTEST_Instantiate(entropyInput, entropyInputLen, michael@0: nonce, nonceLen, michael@0: personalizationString, michael@0: personalizationStringLen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: break; michael@0: michael@0: case GENERATE: michael@0: case RESULT: michael@0: memset(return_bytes, 0, return_bytes_len); michael@0: if (debug) { michael@0: fputs("# PRNGTEST_Generate(returnbytes",rngresp); michael@0: fprintf(rngresp,",%d,", return_bytes_len); michael@0: to_hex_str(buf2,additionalInput, additionalInputLen); michael@0: fputs(buf2,rngresp); michael@0: fprintf(rngresp,",%d)\n",additionalInputLen); michael@0: } michael@0: rv = PRNGTEST_Generate((PRUint8 *) return_bytes, michael@0: return_bytes_len, michael@0: (PRUint8 *) additionalInput, michael@0: additionalInputLen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (command == RESULT) { michael@0: fputs("ReturnedBits = ", rngresp); michael@0: to_hex_str(buf2, return_bytes, return_bytes_len); michael@0: fputs(buf2, rngresp); michael@0: fputc('\n', rngresp); michael@0: if (debug) { michael@0: fputs("# PRNGTEST_Uninstantiate()\n",rngresp); michael@0: } michael@0: rv = PRNGTEST_Uninstantiate(); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: } else if (debug) { michael@0: fputs("#ReturnedBits = ", rngresp); michael@0: to_hex_str(buf2, return_bytes, return_bytes_len); michael@0: fputs(buf2, rngresp); michael@0: fputc('\n', rngresp); michael@0: } michael@0: michael@0: memset(additionalInput, 0, additionalInputLen); michael@0: break; michael@0: michael@0: case RESEED: michael@0: if (entropyInput || additionalInput) { michael@0: if (debug) { michael@0: fputs("# PRNGTEST_Reseed(",rngresp); michael@0: fprintf(rngresp,",%d,", return_bytes_len); michael@0: to_hex_str(buf2,entropyInput, entropyInputLen); michael@0: fputs(buf2,rngresp); michael@0: fprintf(rngresp,",%d,", entropyInputLen); michael@0: to_hex_str(buf2,additionalInput, additionalInputLen); michael@0: fputs(buf2,rngresp); michael@0: fprintf(rngresp,",%d)\n",additionalInputLen); michael@0: } michael@0: rv = PRNGTEST_Reseed(entropyInput, entropyInputLen, michael@0: additionalInput, additionalInputLen); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: } michael@0: memset(entropyInput, 0, entropyInputLen); michael@0: memset(additionalInput, 0, additionalInputLen); michael@0: break; michael@0: case NONE: michael@0: break; michael@0: michael@0: } michael@0: command = NONE; michael@0: michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r' ) { michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [Hash - SHA256] */ michael@0: if (strncmp(buf, "[SHA-256]", 9) == 0) { michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: if (strncmp(buf, "[PredictionResistance", 21) == 0) { michael@0: i = 21; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: if (strncmp(buf, "False", 5) == 0) { michael@0: predictionResistance = PR_FALSE; michael@0: } else { michael@0: predictionResistance = PR_TRUE; michael@0: } michael@0: michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: if (strncmp(buf, "[EntropyInputLen", 16) == 0) { michael@0: if (entropyInput) { michael@0: PORT_ZFree(entropyInput, entropyInputLen); michael@0: entropyInput = NULL; michael@0: entropyInputLen = 0; michael@0: } michael@0: if (sscanf(buf, "[EntropyInputLen = %d]", &entropyInputLen) != 1) { michael@0: goto loser; michael@0: } michael@0: entropyInputLen = entropyInputLen/8; michael@0: if (entropyInputLen > 0) { michael@0: entropyInput = PORT_Alloc(entropyInputLen); michael@0: } michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: if (strncmp(buf, "[NonceLen", 9) == 0) { michael@0: if (nonce) { michael@0: PORT_ZFree(nonce, nonceLen); michael@0: nonce = NULL; michael@0: nonceLen = 0; michael@0: } michael@0: michael@0: if (sscanf(buf, "[NonceLen = %d]", &nonceLen) != 1) { michael@0: goto loser; michael@0: } michael@0: nonceLen = nonceLen/8; michael@0: if (nonceLen > 0) { michael@0: nonce = PORT_Alloc(nonceLen); michael@0: } michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: if (strncmp(buf, "[PersonalizationStringLen", 16) == 0) { michael@0: if (personalizationString) { michael@0: PORT_ZFree(personalizationString, personalizationStringLen); michael@0: personalizationString = NULL; michael@0: personalizationStringLen = 0; michael@0: } michael@0: michael@0: if (sscanf(buf, "[PersonalizationStringLen = %d]", &personalizationStringLen) != 1) { michael@0: goto loser; michael@0: } michael@0: personalizationStringLen = personalizationStringLen / 8; michael@0: if (personalizationStringLen > 0) { michael@0: personalizationString = PORT_Alloc(personalizationStringLen); michael@0: } michael@0: fputs(buf, rngresp); michael@0: michael@0: continue; michael@0: } michael@0: michael@0: if (strncmp(buf, "[AdditionalInputLen", 16) == 0) { michael@0: if (additionalInput) { michael@0: PORT_ZFree(additionalInput, additionalInputLen); michael@0: additionalInput = NULL; michael@0: additionalInputLen = 0; michael@0: } michael@0: michael@0: if (sscanf(buf, "[AdditionalInputLen = %d]", &additionalInputLen) != 1) { michael@0: goto loser; michael@0: } michael@0: additionalInputLen = additionalInputLen/8; michael@0: if (additionalInputLen > 0) { michael@0: additionalInput = PORT_Alloc(additionalInputLen); michael@0: } michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: if (strncmp(buf, "COUNT", 5) == 0) { michael@0: /* zeroize the variables for the test with this data set */ michael@0: if (entropyInput) { michael@0: memset(entropyInput, 0, entropyInputLen); michael@0: } michael@0: if (nonce) { michael@0: memset(nonce, 0, nonceLen); michael@0: } michael@0: if (personalizationString) { michael@0: memset(personalizationString, 0, personalizationStringLen); michael@0: } michael@0: if (additionalInput) { michael@0: memset(additionalInput, 0, additionalInputLen); michael@0: } michael@0: genResult = PR_FALSE; michael@0: michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: michael@0: /* EntropyInputReseed = ... */ michael@0: if (strncmp(buf, "EntropyInputReseed", 18) == 0) { michael@0: if (entropyInput) { michael@0: memset(entropyInput, 0, entropyInputLen); michael@0: i = 18; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j\n". michael@0: */ michael@0: FILE *rngreq; /* input stream from the REQUEST file */ michael@0: FILE *rngresp; /* output stream to the RESPONSE file */ michael@0: unsigned int i, j; michael@0: unsigned char Q[DSA1_SUBPRIME_LEN]; michael@0: PRBool hasQ = PR_FALSE; michael@0: unsigned int b; /* 160 <= b <= 512, b is a multiple of 8 */ michael@0: unsigned char XKey[512/8]; michael@0: unsigned char XSeed[512/8]; michael@0: unsigned char GENX[DSA1_SIGNATURE_LEN]; michael@0: unsigned char DSAX[DSA1_SUBPRIME_LEN]; michael@0: SECStatus rv; michael@0: michael@0: rngreq = fopen(reqfn, "r"); michael@0: rngresp = stdout; michael@0: while (fgets(buf, sizeof buf, rngreq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: /* [Xchange - SHA1] */ michael@0: if (buf[0] == '[') { michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: /* Q = ... */ michael@0: if (buf[0] == 'Q') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j\n". michael@0: */ michael@0: FILE *rngreq; /* input stream from the REQUEST file */ michael@0: FILE *rngresp; /* output stream to the RESPONSE file */ michael@0: unsigned int i, j; michael@0: unsigned char Q[DSA1_SUBPRIME_LEN]; michael@0: PRBool hasQ = PR_FALSE; michael@0: unsigned int b; /* 160 <= b <= 512, b is a multiple of 8 */ michael@0: unsigned char XKey[512/8]; michael@0: unsigned char XSeed[512/8]; michael@0: unsigned char GENX[2*SHA1_LENGTH]; michael@0: unsigned char DSAX[DSA1_SUBPRIME_LEN]; michael@0: SECStatus rv; michael@0: michael@0: rngreq = fopen(reqfn, "r"); michael@0: rngresp = stdout; michael@0: while (fgets(buf, sizeof buf, rngreq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: /* [Xchange - SHA1] */ michael@0: if (buf[0] == '[') { michael@0: fputs(buf, rngresp); michael@0: continue; michael@0: } michael@0: /* Q = ... */ michael@0: if (buf[0] == 'Q') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j1024) { michael@0: fprintf(dsaresp, michael@0: "DSA key size must be a multiple of 64 between 512 " michael@0: "and 1024, inclusive"); michael@0: goto loser; michael@0: } michael@0: michael@0: /* Generate the parameters P, Q, and G */ michael@0: if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, michael@0: &pqg, &vfy) != SECSuccess) { michael@0: fprintf(dsaresp, michael@0: "ERROR: Unable to generate PQG parameters"); michael@0: goto loser; michael@0: } michael@0: } else { michael@0: if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) { michael@0: fprintf(dsaresp, michael@0: "ERROR: Unable to generate PQG parameters"); michael@0: goto loser; michael@0: } michael@0: } michael@0: michael@0: /* output P, Q, and G */ michael@0: to_hex_str(buf, pqg->prime.data, pqg->prime.len); michael@0: fprintf(dsaresp, "P = %s\n", buf); michael@0: to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); michael@0: fprintf(dsaresp, "Q = %s\n", buf); michael@0: to_hex_str(buf, pqg->base.data, pqg->base.len); michael@0: fprintf(dsaresp, "G = %s\n\n", buf); michael@0: continue; michael@0: } michael@0: /* N = ...*/ michael@0: if (buf[0] == 'N') { michael@0: michael@0: if (sscanf(buf, "N = %d", &count) != 1) { michael@0: goto loser; michael@0: } michael@0: /* Generate a DSA key, and output the key pair for N times */ michael@0: for (i = 0; i < count; i++) { michael@0: DSAPrivateKey *dsakey = NULL; michael@0: if (DSA_NewKey(pqg, &dsakey) != SECSuccess) { michael@0: fprintf(dsaresp, "ERROR: Unable to generate DSA key"); michael@0: goto loser; michael@0: } michael@0: to_hex_str(buf, dsakey->privateValue.data, michael@0: dsakey->privateValue.len); michael@0: fprintf(dsaresp, "X = %s\n", buf); michael@0: to_hex_str(buf, dsakey->publicValue.data, michael@0: dsakey->publicValue.len); michael@0: fprintf(dsaresp, "Y = %s\n\n", buf); michael@0: PORT_FreeArena(dsakey->params.arena, PR_TRUE); michael@0: dsakey = NULL; michael@0: } michael@0: continue; michael@0: } michael@0: michael@0: } michael@0: loser: michael@0: fclose(dsareq); michael@0: } michael@0: michael@0: /* michael@0: * pqg generation type michael@0: */ michael@0: typedef enum { michael@0: FIPS186_1,/* Generate/Verify P,Q & G according to FIPS 186-1 */ michael@0: A_1_1_2, /* Generate Probable P & Q */ michael@0: A_1_1_3, /* Verify Probable P & Q */ michael@0: A_1_2_2, /* Verify Provable P & Q */ michael@0: A_2_1, /* Generate Unverifiable G */ michael@0: A_2_2, /* Assure Unverifiable G */ michael@0: A_2_3, /* Generate Verifiable G */ michael@0: A_2_4 /* Verify Verifiable G */ michael@0: } dsa_pqg_type; michael@0: michael@0: /* michael@0: * Perform the DSA Domain Parameter Validation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: dsa_pqgver_test(char *reqfn) michael@0: { michael@0: char buf[800]; /* holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * 800 to hold (384 public key (x2 for HEX) + P = ... michael@0: */ michael@0: FILE *dsareq; /* input stream from the REQUEST file */ michael@0: FILE *dsaresp; /* output stream to the RESPONSE file */ michael@0: int N; michael@0: int L; michael@0: unsigned int i, j; michael@0: PQGParams pqg; michael@0: PQGVerify vfy; michael@0: unsigned int pghSize; /* size for p, g, and h */ michael@0: dsa_pqg_type type = FIPS186_1; michael@0: michael@0: dsareq = fopen(reqfn, "r"); michael@0: dsaresp = stdout; michael@0: memset(&pqg, 0, sizeof(pqg)); michael@0: memset(&vfy, 0, sizeof(vfy)); michael@0: michael@0: while (fgets(buf, sizeof buf, dsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [A.xxxxx ] */ michael@0: if (buf[0] == '[' && buf[1] == 'A') { michael@0: michael@0: if (strncmp(&buf[1],"A.1.1.3",7) == 0) { michael@0: type = A_1_1_3; michael@0: } else if (strncmp(&buf[1],"A.2.2",5) == 0) { michael@0: type = A_2_2; michael@0: } else if (strncmp(&buf[1],"A.2.4",5) == 0) { michael@0: type = A_2_4; michael@0: } else if (strncmp(&buf[1],"A.1.2.2",7) == 0) { michael@0: type = A_1_2_2; michael@0: /* validate our output from PQGGEN */ michael@0: } else if (strncmp(&buf[1],"A.1.1.2",7) == 0) { michael@0: type = A_2_4; /* validate PQ and G together */ michael@0: } else { michael@0: fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]); michael@0: exit(1); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: michael@0: /* [Mod = x] */ michael@0: if (buf[0] == '[') { michael@0: michael@0: if (type == FIPS186_1) { michael@0: N=160; michael@0: if (sscanf(buf, "[mod = %d]", &L) != 1) { michael@0: goto loser; michael@0: } michael@0: } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (pqg.prime.data) { /* P */ michael@0: SECITEM_ZfreeItem(&pqg.prime, PR_FALSE); michael@0: } michael@0: if (pqg.subPrime.data) { /* Q */ michael@0: SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE); michael@0: } michael@0: if (pqg.base.data) { /* G */ michael@0: SECITEM_ZfreeItem(&pqg.base, PR_FALSE); michael@0: } michael@0: if (vfy.seed.data) { /* seed */ michael@0: SECITEM_ZfreeItem(&vfy.seed, PR_FALSE); michael@0: } michael@0: if (vfy.h.data) { /* H */ michael@0: SECITEM_ZfreeItem(&vfy.h, PR_FALSE); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: michael@0: /*calculate the size of p, g, and h then allocate items */ michael@0: pghSize = L/8; michael@0: michael@0: pqg.base.data = vfy.h.data = NULL; michael@0: vfy.seed.len = pqg.base.len = vfy.h.len = 0; michael@0: SECITEM_AllocItem(NULL, &pqg.prime, pghSize); michael@0: SECITEM_AllocItem(NULL, &vfy.seed, pghSize*3); michael@0: if (type == A_2_2) { michael@0: SECITEM_AllocItem(NULL, &vfy.h, pghSize); michael@0: vfy.h.len = pghSize; michael@0: } else if (type == A_2_4) { michael@0: SECITEM_AllocItem(NULL, &vfy.h, 1); michael@0: vfy.h.len = 1; michael@0: } michael@0: pqg.prime.len = pghSize; michael@0: /* q is always N bits */ michael@0: SECITEM_AllocItem(NULL, &pqg.subPrime, N/8); michael@0: pqg.subPrime.len = N/8; michael@0: vfy.counter = -1; michael@0: michael@0: continue; michael@0: } michael@0: /* P = ... */ michael@0: if (buf[0] == 'P') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j< pqg.prime.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pqg.prime.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* Q = ... */ michael@0: if (buf[0] == 'Q') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j< pqg.subPrime.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pqg.subPrime.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* G = ... */ michael@0: if (buf[0] == 'G') { michael@0: i = 1; michael@0: if (pqg.base.data) { michael@0: SECITEM_ZfreeItem(&pqg.base, PR_FALSE); michael@0: } michael@0: SECITEM_AllocItem(NULL, &pqg.base, pghSize); michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j< pqg.base.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pqg.base.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* Seed = ... or domain_parameter_seed = ... */ michael@0: if (strncmp(buf, "Seed", 4) == 0) { michael@0: i = 4; michael@0: } else if (strncmp(buf, "domain_parameter_seed", 21) == 0) { michael@0: i = 21; michael@0: } else if (strncmp(buf,"firstseed",9) == 0) { michael@0: i = 9; michael@0: } else { michael@0: i = 0; michael@0: } michael@0: if (i) { michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &vfy.seed.data[j]); michael@0: } michael@0: vfy.seed.len = j; michael@0: michael@0: fputs(buf, dsaresp); michael@0: if (type == A_2_4) { michael@0: SECStatus result; michael@0: michael@0: /* Verify the Parameters */ michael@0: SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (result == SECSuccess) { michael@0: fprintf(dsaresp, "Result = P\n"); michael@0: } else { michael@0: fprintf(dsaresp, "Result = F\n"); michael@0: } michael@0: } michael@0: continue; michael@0: } michael@0: if ((strncmp(buf,"pseed",5) == 0) || michael@0: (strncmp(buf,"qseed",5) == 0)) michael@0: { michael@0: i = 5; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=vfy.seed.len; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &vfy.seed.data[j]); michael@0: } michael@0: vfy.seed.len = j; michael@0: fputs(buf, dsaresp); michael@0: michael@0: continue; michael@0: } michael@0: if (strncmp(buf, "index", 4) == 0) { michael@0: i=5; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: hex_to_byteval(&buf[i], &vfy.h.data[0]); michael@0: vfy.h.len = 1; michael@0: fputs(buf, dsaresp); michael@0: } michael@0: michael@0: /* c = ... or counter=*/ michael@0: if (buf[0] == 'c') { michael@0: if (strncmp(buf,"counter", 7) == 0) { michael@0: if (sscanf(buf, "counter = %u", &vfy.counter) != 1) { michael@0: goto loser; michael@0: } michael@0: } else { michael@0: if (sscanf(buf, "c = %u", &vfy.counter) != 1) { michael@0: goto loser; michael@0: } michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: if (type == A_1_1_3) { michael@0: SECStatus result; michael@0: /* only verify P and Q, we have everything now. do it */ michael@0: SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (result == SECSuccess) { michael@0: fprintf(dsaresp, "Result = P\n"); michael@0: } else { michael@0: fprintf(dsaresp, "Result = F\n"); michael@0: } michael@0: fprintf(dsaresp, "\n"); michael@0: } michael@0: continue; michael@0: } michael@0: if (strncmp(buf,"pgen_counter", 12) == 0) { michael@0: if (sscanf(buf, "pgen_counter = %u", &vfy.counter) != 1) { michael@0: goto loser; michael@0: } michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: if (strncmp(buf,"qgen_counter", 12) == 0) { michael@0: fputs(buf, dsaresp); michael@0: if (type == A_1_2_2) { michael@0: SECStatus result; michael@0: /* only verify P and Q, we have everything now. do it */ michael@0: SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (result == SECSuccess) { michael@0: fprintf(dsaresp, "Result = P\n"); michael@0: } else { michael@0: fprintf(dsaresp, "Result = F\n"); michael@0: } michael@0: fprintf(dsaresp, "\n"); michael@0: } michael@0: continue; michael@0: } michael@0: /* H = ... */ michael@0: if (buf[0] == 'H') { michael@0: SECStatus rv, result = SECFailure; michael@0: michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &vfy.h.data[j]); michael@0: } michael@0: vfy.h.len = j; michael@0: fputs(buf, dsaresp); michael@0: michael@0: /* this should be a byte value. Remove the leading zeros. If michael@0: * it doesn't reduce to a byte, PQG_VerifyParams will catch it michael@0: if (type == A_2_2) { michael@0: data_save = vfy.h.data; michael@0: while(vfy.h.data[0] && (vfy.h.len > 1)) { michael@0: vfy.h.data++; michael@0: vfy.h.len--; michael@0: } michael@0: } */ michael@0: michael@0: /* Verify the Parameters */ michael@0: rv = PQG_VerifyParams(&pqg, &vfy, &result); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (result == SECSuccess) { michael@0: fprintf(dsaresp, "Result = P\n"); michael@0: } else { michael@0: fprintf(dsaresp, "Result = F\n"); michael@0: } michael@0: fprintf(dsaresp, "\n"); michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: fclose(dsareq); michael@0: if (pqg.prime.data) { /* P */ michael@0: SECITEM_ZfreeItem(&pqg.prime, PR_FALSE); michael@0: } michael@0: if (pqg.subPrime.data) { /* Q */ michael@0: SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE); michael@0: } michael@0: if (pqg.base.data) { /* G */ michael@0: SECITEM_ZfreeItem(&pqg.base, PR_FALSE); michael@0: } michael@0: if (vfy.seed.data) { /* seed */ michael@0: SECITEM_ZfreeItem(&vfy.seed, PR_FALSE); michael@0: } michael@0: if (vfy.h.data) { /* H */ michael@0: SECITEM_ZfreeItem(&vfy.h, PR_FALSE); michael@0: } michael@0: michael@0: } michael@0: michael@0: /* michael@0: * Perform the DSA Public Key Validation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: dsa_pqggen_test(char *reqfn) michael@0: { michael@0: char buf[800]; /* holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * 800 to hold seed = (384 public key (x2 for HEX) michael@0: */ michael@0: FILE *dsareq; /* input stream from the REQUEST file */ michael@0: FILE *dsaresp; /* output stream to the RESPONSE file */ michael@0: int count; /* number of times to generate parameters */ michael@0: int N; michael@0: int L; michael@0: int i; michael@0: unsigned int j; michael@0: PQGParams *pqg = NULL; michael@0: PQGVerify *vfy = NULL; michael@0: unsigned int keySizeIndex; michael@0: dsa_pqg_type type = FIPS186_1; michael@0: michael@0: dsareq = fopen(reqfn, "r"); michael@0: dsaresp = stdout; michael@0: while (fgets(buf, sizeof buf, dsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [A.xxxxx ] */ michael@0: if (buf[0] == '[' && buf[1] == 'A') { michael@0: if (strncmp(&buf[1],"A.1.1.2",7) == 0) { michael@0: type = A_1_1_2; michael@0: } else if (strncmp(&buf[1],"A.2.1",5) == 0) { michael@0: fprintf(stderr, "NSS only Generates G with P&Q\n"); michael@0: exit(1); michael@0: } else if (strncmp(&buf[1],"A.2.3",5) == 0) { michael@0: fprintf(stderr, "NSS only Generates G with P&Q\n"); michael@0: exit(1); michael@0: } else if (strncmp(&buf[1],"A.1.2.1",7) == 0) { michael@0: fprintf(stderr, "NSS does not support Shawe-Taylor Primes\n"); michael@0: exit(1); michael@0: } else { michael@0: fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]); michael@0: exit(1); michael@0: } michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [Mod = ... ] */ michael@0: if (buf[0] == '[') { michael@0: michael@0: if (type == FIPS186_1) { michael@0: N=160; michael@0: if (sscanf(buf, "[mod = %d]", &L) != 1) { michael@0: goto loser; michael@0: } michael@0: } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) { michael@0: goto loser; michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: fputc('\n', dsaresp); michael@0: michael@0: if (type == FIPS186_1) { michael@0: /************************************************************ michael@0: * PQG_ParamGenSeedLen doesn't take a key size, it takes an michael@0: * index that points to a valid key size. michael@0: */ michael@0: keySizeIndex = PQG_PBITS_TO_INDEX(L); michael@0: if(keySizeIndex == -1 || L<512 || L>1024) { michael@0: fprintf(dsaresp, michael@0: "DSA key size must be a multiple of 64 between 512 " michael@0: "and 1024, inclusive"); michael@0: goto loser; michael@0: } michael@0: } michael@0: continue; michael@0: } michael@0: /* N = ... */ michael@0: if (buf[0] == 'N') { michael@0: if (sscanf(buf, "N = %d", &count) != 1) { michael@0: goto loser; michael@0: } michael@0: for (i = 0; i < count; i++) { michael@0: SECStatus rv; michael@0: michael@0: if (type == FIPS186_1) { michael@0: rv = PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, michael@0: &pqg, &vfy); michael@0: } else { michael@0: rv = PQG_ParamGenV2(L, N, N, &pqg, &vfy); michael@0: } michael@0: if (rv != SECSuccess) { michael@0: fprintf(dsaresp, michael@0: "ERROR: Unable to generate PQG parameters"); michael@0: goto loser; michael@0: } michael@0: to_hex_str(buf, pqg->prime.data, pqg->prime.len); michael@0: fprintf(dsaresp, "P = %s\n", buf); michael@0: to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); michael@0: fprintf(dsaresp, "Q = %s\n", buf); michael@0: to_hex_str(buf, pqg->base.data, pqg->base.len); michael@0: fprintf(dsaresp, "G = %s\n", buf); michael@0: if (type == FIPS186_1) { michael@0: to_hex_str(buf, vfy->seed.data, vfy->seed.len); michael@0: fprintf(dsaresp, "Seed = %s\n", buf); michael@0: fprintf(dsaresp, "c = %d\n", vfy->counter); michael@0: to_hex_str(buf, vfy->h.data, vfy->h.len); michael@0: fputs("H = ", dsaresp); michael@0: for (j=vfy->h.len; j< pqg->prime.len; j++) { michael@0: fprintf(dsaresp, "00"); michael@0: } michael@0: fprintf(dsaresp, "%s\n", buf); michael@0: } else { michael@0: fprintf(dsaresp, "counter = %d\n", vfy->counter); michael@0: fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]); michael@0: to_hex_str(buf, vfy->seed.data, vfy->seed.len); michael@0: fprintf(dsaresp, "domain_parameter_seed = %s\n", buf); michael@0: } michael@0: fputc('\n', dsaresp); michael@0: if(pqg!=NULL) { michael@0: PQG_DestroyParams(pqg); michael@0: pqg = NULL; michael@0: } michael@0: if(vfy!=NULL) { michael@0: PQG_DestroyVerify(vfy); michael@0: vfy = NULL; michael@0: } michael@0: } michael@0: michael@0: continue; michael@0: } michael@0: michael@0: } michael@0: loser: michael@0: fclose(dsareq); michael@0: if(pqg!=NULL) { michael@0: PQG_DestroyParams(pqg); michael@0: } michael@0: if(vfy!=NULL) { michael@0: PQG_DestroyVerify(vfy); michael@0: } michael@0: } michael@0: michael@0: michael@0: /* michael@0: * Perform the DSA Signature Generation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: dsa_siggen_test(char *reqfn) michael@0: { michael@0: char buf[800]; /* holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * max for Msg = .... michael@0: */ michael@0: FILE *dsareq; /* input stream from the REQUEST file */ michael@0: FILE *dsaresp; /* output stream to the RESPONSE file */ michael@0: int modulus; michael@0: int L; michael@0: int N; michael@0: int i, j; michael@0: PRBool use_dsa1 = PR_FALSE; michael@0: PQGParams *pqg = NULL; michael@0: PQGVerify *vfy = NULL; michael@0: DSAPrivateKey *dsakey = NULL; michael@0: int keySizeIndex; /* index for valid key sizes */ michael@0: unsigned char hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */ michael@0: unsigned char sig[DSA_MAX_SIGNATURE_LEN]; michael@0: SECItem digest, signature; michael@0: HASH_HashType hashType = HASH_AlgNULL; michael@0: int hashNum = 0; michael@0: michael@0: dsareq = fopen(reqfn, "r"); michael@0: dsaresp = stdout; michael@0: michael@0: while (fgets(buf, sizeof buf, dsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [Mod = x] */ michael@0: if (buf[0] == '[') { michael@0: if(pqg!=NULL) { michael@0: PQG_DestroyParams(pqg); michael@0: pqg = NULL; michael@0: } michael@0: if(vfy!=NULL) { michael@0: PQG_DestroyVerify(vfy); michael@0: vfy = NULL; michael@0: } michael@0: if (dsakey != NULL) { michael@0: PORT_FreeArena(dsakey->params.arena, PR_TRUE); michael@0: dsakey = NULL; michael@0: } michael@0: michael@0: if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d]", &L, & N, michael@0: &hashNum) != 3) { michael@0: use_dsa1 = PR_TRUE; michael@0: hashNum = 1; michael@0: if (sscanf(buf, "[mod = %d]", &modulus) != 1) { michael@0: goto loser; michael@0: } michael@0: } michael@0: fputs(buf, dsaresp); michael@0: fputc('\n', dsaresp); michael@0: michael@0: /**************************************************************** michael@0: * PQG_ParamGenSeedLen doesn't take a key size, it takes an index michael@0: * that points to a valid key size. michael@0: */ michael@0: if (use_dsa1) { michael@0: keySizeIndex = PQG_PBITS_TO_INDEX(modulus); michael@0: if(keySizeIndex == -1 || modulus<512 || modulus>1024) { michael@0: fprintf(dsaresp, michael@0: "DSA key size must be a multiple of 64 between 512 " michael@0: "and 1024, inclusive"); michael@0: goto loser; michael@0: } michael@0: /* Generate PQG and output PQG */ michael@0: if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, michael@0: &pqg, &vfy) != SECSuccess) { michael@0: fprintf(dsaresp, michael@0: "ERROR: Unable to generate PQG parameters"); michael@0: goto loser; michael@0: } michael@0: } else { michael@0: if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) { michael@0: fprintf(dsaresp, michael@0: "ERROR: Unable to generate PQG parameters"); michael@0: goto loser; michael@0: } michael@0: } michael@0: to_hex_str(buf, pqg->prime.data, pqg->prime.len); michael@0: fprintf(dsaresp, "P = %s\n", buf); michael@0: to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); michael@0: fprintf(dsaresp, "Q = %s\n", buf); michael@0: to_hex_str(buf, pqg->base.data, pqg->base.len); michael@0: fprintf(dsaresp, "G = %s\n", buf); michael@0: michael@0: /* create DSA Key */ michael@0: if (DSA_NewKey(pqg, &dsakey) != SECSuccess) { michael@0: fprintf(dsaresp, "ERROR: Unable to generate DSA key"); michael@0: goto loser; michael@0: } michael@0: michael@0: hashType = sha_get_hashType(hashNum); michael@0: if (hashType == HASH_AlgNULL) { michael@0: fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum); michael@0: goto loser; michael@0: } michael@0: continue; michael@0: } michael@0: michael@0: /* Msg = ... */ michael@0: if (strncmp(buf, "Msg", 3) == 0) { michael@0: unsigned char msg[128]; /* MAX msg 128 */ michael@0: unsigned int len = 0; michael@0: michael@0: if (hashType == HASH_AlgNULL) { michael@0: fprintf(dsaresp, "ERROR: Hash Alg not set"); michael@0: goto loser; michael@0: } michael@0: michael@0: memset(hashBuf, 0, sizeof hashBuf); michael@0: memset(sig, 0, sizeof sig); michael@0: michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &msg[j]); michael@0: } michael@0: if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) { michael@0: fprintf(dsaresp, "ERROR: Unable to generate SHA% digest", michael@0: hashNum); michael@0: goto loser; michael@0: } michael@0: michael@0: michael@0: digest.type = siBuffer; michael@0: digest.data = hashBuf; michael@0: digest.len = fips_hashLen(hashType); michael@0: signature.type = siBuffer; michael@0: signature.data = sig; michael@0: signature.len = sizeof sig; michael@0: michael@0: if (DSA_SignDigest(dsakey, &signature, &digest) != SECSuccess) { michael@0: fprintf(dsaresp, "ERROR: Unable to generate DSA signature"); michael@0: goto loser; michael@0: } michael@0: len = signature.len; michael@0: if (len%2 != 0) { michael@0: goto loser; michael@0: } michael@0: len = len/2; michael@0: michael@0: /* output the orginal Msg, and generated Y, R, and S */ michael@0: fputs(buf, dsaresp); michael@0: to_hex_str(buf, dsakey->publicValue.data, michael@0: dsakey->publicValue.len); michael@0: fprintf(dsaresp, "Y = %s\n", buf); michael@0: to_hex_str(buf, &signature.data[0], len); michael@0: fprintf(dsaresp, "R = %s\n", buf); michael@0: to_hex_str(buf, &signature.data[len], len); michael@0: fprintf(dsaresp, "S = %s\n", buf); michael@0: fputc('\n', dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: } michael@0: loser: michael@0: fclose(dsareq); michael@0: if(pqg != NULL) { michael@0: PQG_DestroyParams(pqg); michael@0: pqg = NULL; michael@0: } michael@0: if(vfy != NULL) { michael@0: PQG_DestroyVerify(vfy); michael@0: vfy = NULL; michael@0: } michael@0: if (dsakey) { michael@0: PORT_FreeArena(dsakey->params.arena, PR_TRUE); michael@0: dsakey = NULL; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Perform the DSA Signature Verification Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: dsa_sigver_test(char *reqfn) michael@0: { michael@0: char buf[800]; /* holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * max for Msg = .... michael@0: */ michael@0: FILE *dsareq; /* input stream from the REQUEST file */ michael@0: FILE *dsaresp; /* output stream to the RESPONSE file */ michael@0: int L; michael@0: int N; michael@0: unsigned int i, j; michael@0: SECItem digest, signature; michael@0: DSAPublicKey pubkey; michael@0: unsigned int pgySize; /* size for p, g, and y */ michael@0: unsigned char hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */ michael@0: unsigned char sig[DSA_MAX_SIGNATURE_LEN]; michael@0: HASH_HashType hashType = HASH_AlgNULL; michael@0: int hashNum = 0; michael@0: michael@0: dsareq = fopen(reqfn, "r"); michael@0: dsaresp = stdout; michael@0: memset(&pubkey, 0, sizeof(pubkey)); michael@0: michael@0: while (fgets(buf, sizeof buf, dsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [Mod = x] */ michael@0: if (buf[0] == '[') { michael@0: michael@0: if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d]", &L, & N, michael@0: &hashNum) != 3) { michael@0: N=160; michael@0: hashNum = 1; michael@0: if (sscanf(buf, "[mod = %d]", &L) != 1) { michael@0: goto loser; michael@0: } michael@0: } michael@0: michael@0: if (pubkey.params.prime.data) { /* P */ michael@0: SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE); michael@0: } michael@0: if (pubkey.params.subPrime.data) { /* Q */ michael@0: SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE); michael@0: } michael@0: if (pubkey.params.base.data) { /* G */ michael@0: SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE); michael@0: } michael@0: if (pubkey.publicValue.data) { /* Y */ michael@0: SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE); michael@0: } michael@0: fputs(buf, dsaresp); michael@0: michael@0: /* calculate the size of p, g, and y then allocate items */ michael@0: pgySize = L/8; michael@0: SECITEM_AllocItem(NULL, &pubkey.params.prime, pgySize); michael@0: SECITEM_AllocItem(NULL, &pubkey.params.base, pgySize); michael@0: SECITEM_AllocItem(NULL, &pubkey.publicValue, pgySize); michael@0: pubkey.params.prime.len = pubkey.params.base.len = pgySize; michael@0: pubkey.publicValue.len = pgySize; michael@0: michael@0: /* q always N/8 bytes */ michael@0: SECITEM_AllocItem(NULL, &pubkey.params.subPrime, N/8); michael@0: pubkey.params.subPrime.len = N/8; michael@0: michael@0: hashType = sha_get_hashType(hashNum); michael@0: if (hashType == HASH_AlgNULL) { michael@0: fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum); michael@0: goto loser; michael@0: } michael@0: michael@0: continue; michael@0: } michael@0: /* P = ... */ michael@0: if (buf[0] == 'P') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: memset(pubkey.params.prime.data, 0, pubkey.params.prime.len); michael@0: for (j=0; j< pubkey.params.prime.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pubkey.params.prime.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* Q = ... */ michael@0: if (buf[0] == 'Q') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: memset(pubkey.params.subPrime.data, 0, pubkey.params.subPrime.len); michael@0: for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pubkey.params.subPrime.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* G = ... */ michael@0: if (buf[0] == 'G') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: memset(pubkey.params.base.data, 0, pubkey.params.base.len); michael@0: for (j=0; j< pubkey.params.base.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pubkey.params.base.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* Msg = ... */ michael@0: if (strncmp(buf, "Msg", 3) == 0) { michael@0: unsigned char msg[128]; /* MAX msg 128 */ michael@0: memset(hashBuf, 0, sizeof hashBuf); michael@0: michael@0: if (hashType == HASH_AlgNULL) { michael@0: fprintf(dsaresp, "ERROR: Hash Alg not set"); michael@0: goto loser; michael@0: } michael@0: michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &msg[j]); michael@0: } michael@0: if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) { michael@0: fprintf(dsaresp, "ERROR: Unable to generate SHA-%d digest", michael@0: hashNum); michael@0: goto loser; michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* Y = ... */ michael@0: if (buf[0] == 'Y') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: memset(pubkey.publicValue.data, 0, pubkey.params.subPrime.len); michael@0: for (j=0; j< pubkey.publicValue.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &pubkey.publicValue.data[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* R = ... */ michael@0: if (buf[0] == 'R') { michael@0: memset(sig, 0, sizeof sig); michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &sig[j]); michael@0: } michael@0: michael@0: fputs(buf, dsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* S = ... */ michael@0: if (buf[0] == 'S') { michael@0: if (hashType == HASH_AlgNULL) { michael@0: fprintf(dsaresp, "ERROR: Hash Alg not set"); michael@0: goto loser; michael@0: } michael@0: michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=pubkey.params.subPrime.len; michael@0: j< pubkey.params.subPrime.len*2; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &sig[j]); michael@0: } michael@0: fputs(buf, dsaresp); michael@0: michael@0: digest.type = siBuffer; michael@0: digest.data = hashBuf; michael@0: digest.len = fips_hashLen(hashType); michael@0: signature.type = siBuffer; michael@0: signature.data = sig; michael@0: signature.len = pubkey.params.subPrime.len*2; michael@0: michael@0: if (DSA_VerifyDigest(&pubkey, &signature, &digest) == SECSuccess) { michael@0: fprintf(dsaresp, "Result = P\n"); michael@0: } else { michael@0: fprintf(dsaresp, "Result = F\n"); michael@0: } michael@0: fprintf(dsaresp, "\n"); michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: fclose(dsareq); michael@0: if (pubkey.params.prime.data) { /* P */ michael@0: SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE); michael@0: } michael@0: if (pubkey.params.subPrime.data) { /* Q */ michael@0: SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE); michael@0: } michael@0: if (pubkey.params.base.data) { /* G */ michael@0: SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE); michael@0: } michael@0: if (pubkey.publicValue.data) { /* Y */ michael@0: SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Perform the RSA Signature Generation Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: rsa_siggen_test(char *reqfn) michael@0: { michael@0: char buf[2*RSA_MAX_TEST_MODULUS_BYTES+1]; michael@0: /* buf holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * 2x for HEX output + 1 for \n michael@0: */ michael@0: FILE *rsareq; /* input stream from the REQUEST file */ michael@0: FILE *rsaresp; /* output stream to the RESPONSE file */ michael@0: int i, j; michael@0: unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */ michael@0: unsigned int shaLength = 0; /* length of SHA */ michael@0: HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */ michael@0: SECOidTag shaOid = SEC_OID_UNKNOWN; michael@0: int modulus; /* the Modulus size */ michael@0: int publicExponent = DEFAULT_RSA_PUBLIC_EXPONENT; michael@0: SECItem pe = {0, 0, 0 }; michael@0: unsigned char pubEx[4]; michael@0: int peCount = 0; michael@0: michael@0: RSAPrivateKey *rsaBlapiPrivKey = NULL; /* holds RSA private and michael@0: * public keys */ michael@0: RSAPublicKey *rsaBlapiPublicKey = NULL; /* hold RSA public key */ michael@0: michael@0: rsareq = fopen(reqfn, "r"); michael@0: rsaresp = stdout; michael@0: michael@0: /* calculate the exponent */ michael@0: for (i=0; i < 4; i++) { michael@0: if (peCount || (publicExponent & michael@0: ((unsigned long)0xff000000L >> (i*8)))) { michael@0: pubEx[peCount] = michael@0: (unsigned char)((publicExponent >> (3-i)*8) & 0xff); michael@0: peCount++; michael@0: } michael@0: } michael@0: pe.len = peCount; michael@0: pe.data = &pubEx[0]; michael@0: pe.type = siBuffer; michael@0: michael@0: while (fgets(buf, sizeof buf, rsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [mod = ...] */ michael@0: if (buf[0] == '[') { michael@0: michael@0: if (sscanf(buf, "[mod = %d]", &modulus) != 1) { michael@0: goto loser; michael@0: } michael@0: if (modulus > RSA_MAX_TEST_MODULUS_BITS) { michael@0: fprintf(rsaresp,"ERROR: modulus greater than test maximum\n"); michael@0: goto loser; michael@0: } michael@0: michael@0: fputs(buf, rsaresp); michael@0: michael@0: if (rsaBlapiPrivKey != NULL) { michael@0: PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE); michael@0: rsaBlapiPrivKey = NULL; michael@0: rsaBlapiPublicKey = NULL; michael@0: } michael@0: michael@0: rsaBlapiPrivKey = RSA_NewKey(modulus, &pe); michael@0: if (rsaBlapiPrivKey == NULL) { michael@0: fprintf(rsaresp, "Error unable to create RSA key\n"); michael@0: goto loser; michael@0: } michael@0: michael@0: to_hex_str(buf, rsaBlapiPrivKey->modulus.data, michael@0: rsaBlapiPrivKey->modulus.len); michael@0: fprintf(rsaresp, "\nn = %s\n\n", buf); michael@0: to_hex_str(buf, rsaBlapiPrivKey->publicExponent.data, michael@0: rsaBlapiPrivKey->publicExponent.len); michael@0: fprintf(rsaresp, "e = %s\n", buf); michael@0: /* convert private key to public key. Memory michael@0: * is freed with private key's arena */ michael@0: rsaBlapiPublicKey = (RSAPublicKey *)PORT_ArenaAlloc( michael@0: rsaBlapiPrivKey->arena, michael@0: sizeof(RSAPublicKey)); michael@0: michael@0: rsaBlapiPublicKey->modulus.len = rsaBlapiPrivKey->modulus.len; michael@0: rsaBlapiPublicKey->modulus.data = rsaBlapiPrivKey->modulus.data; michael@0: rsaBlapiPublicKey->publicExponent.len = michael@0: rsaBlapiPrivKey->publicExponent.len; michael@0: rsaBlapiPublicKey->publicExponent.data = michael@0: rsaBlapiPrivKey->publicExponent.data; michael@0: continue; michael@0: } michael@0: michael@0: /* SHAAlg = ... */ michael@0: if (strncmp(buf, "SHAAlg", 6) == 0) { michael@0: i = 6; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: /* set the SHA Algorithm */ michael@0: if (strncmp(&buf[i], "SHA1", 4) == 0) { michael@0: shaAlg = HASH_AlgSHA1; michael@0: } else if (strncmp(&buf[i], "SHA224", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA224; michael@0: } else if (strncmp(&buf[i], "SHA256", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA256; michael@0: } else if (strncmp(&buf[i], "SHA384", 6)== 0) { michael@0: shaAlg = HASH_AlgSHA384; michael@0: } else if (strncmp(&buf[i], "SHA512", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA512; michael@0: } else { michael@0: fprintf(rsaresp, "ERROR: Unable to find SHAAlg type"); michael@0: goto loser; michael@0: } michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: michael@0: } michael@0: /* Msg = ... */ michael@0: if (strncmp(buf, "Msg", 3) == 0) { michael@0: michael@0: unsigned char msg[128]; /* MAX msg 128 */ michael@0: unsigned int rsa_bytes_signed; michael@0: unsigned char rsa_computed_signature[RSA_MAX_TEST_MODULUS_BYTES]; michael@0: SECStatus rv = SECFailure; michael@0: NSSLOWKEYPublicKey * rsa_public_key; michael@0: NSSLOWKEYPrivateKey * rsa_private_key; michael@0: NSSLOWKEYPrivateKey low_RSA_private_key = { NULL, michael@0: NSSLOWKEYRSAKey, }; michael@0: NSSLOWKEYPublicKey low_RSA_public_key = { NULL, michael@0: NSSLOWKEYRSAKey, }; michael@0: michael@0: low_RSA_private_key.u.rsa = *rsaBlapiPrivKey; michael@0: low_RSA_public_key.u.rsa = *rsaBlapiPublicKey; michael@0: michael@0: rsa_private_key = &low_RSA_private_key; michael@0: rsa_public_key = &low_RSA_public_key; michael@0: michael@0: memset(sha, 0, sizeof sha); michael@0: memset(msg, 0, sizeof msg); michael@0: rsa_bytes_signed = 0; michael@0: memset(rsa_computed_signature, 0, sizeof rsa_computed_signature); michael@0: michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: for (j=0; isxdigit(buf[i]) && j < sizeof(msg); i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &msg[j]); michael@0: } michael@0: shaLength = fips_hashLen(shaAlg); michael@0: if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) { michael@0: if (shaLength == 0) { michael@0: fprintf(rsaresp, "ERROR: SHAAlg not defined."); michael@0: } michael@0: fprintf(rsaresp, "ERROR: Unable to generate SHA%x", michael@0: shaLength == 160 ? 1 : shaLength); michael@0: goto loser; michael@0: } michael@0: shaOid = fips_hashOid(shaAlg); michael@0: michael@0: /* Perform RSA signature with the RSA private key. */ michael@0: rv = RSA_HashSign( shaOid, michael@0: rsa_private_key, michael@0: rsa_computed_signature, michael@0: &rsa_bytes_signed, michael@0: nsslowkey_PrivateModulusLen(rsa_private_key), michael@0: sha, michael@0: shaLength); michael@0: michael@0: if( rv != SECSuccess ) { michael@0: fprintf(rsaresp, "ERROR: RSA_HashSign failed"); michael@0: goto loser; michael@0: } michael@0: michael@0: /* Output the signature */ michael@0: fputs(buf, rsaresp); michael@0: to_hex_str(buf, rsa_computed_signature, rsa_bytes_signed); michael@0: fprintf(rsaresp, "S = %s\n", buf); michael@0: michael@0: /* Perform RSA verification with the RSA public key. */ michael@0: rv = RSA_HashCheckSign( shaOid, michael@0: rsa_public_key, michael@0: rsa_computed_signature, michael@0: rsa_bytes_signed, michael@0: sha, michael@0: shaLength); michael@0: if( rv != SECSuccess ) { michael@0: fprintf(rsaresp, "ERROR: RSA_HashCheckSign failed"); michael@0: goto loser; michael@0: } michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: fclose(rsareq); michael@0: michael@0: if (rsaBlapiPrivKey != NULL) { michael@0: /* frees private and public key */ michael@0: PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE); michael@0: rsaBlapiPrivKey = NULL; michael@0: rsaBlapiPublicKey = NULL; michael@0: } michael@0: michael@0: } michael@0: /* michael@0: * Perform the RSA Signature Verification Test. michael@0: * michael@0: * reqfn is the pathname of the REQUEST file. michael@0: * michael@0: * The output RESPONSE file is written to stdout. michael@0: */ michael@0: void michael@0: rsa_sigver_test(char *reqfn) michael@0: { michael@0: char buf[2*RSA_MAX_TEST_MODULUS_BYTES+7]; michael@0: /* buf holds one line from the input REQUEST file michael@0: * or to the output RESPONSE file. michael@0: * s = 2x for HEX output + 1 for \n michael@0: */ michael@0: FILE *rsareq; /* input stream from the REQUEST file */ michael@0: FILE *rsaresp; /* output stream to the RESPONSE file */ michael@0: int i, j; michael@0: unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */ michael@0: unsigned int shaLength = 0; /* actual length of the digest */ michael@0: HASH_HashType shaAlg = HASH_AlgNULL; michael@0: SECOidTag shaOid = SEC_OID_UNKNOWN; michael@0: int modulus = 0; /* the Modulus size */ michael@0: unsigned char signature[513]; /* largest signature size + '\n' */ michael@0: unsigned int signatureLength = 0; /* actual length of the signature */ michael@0: PRBool keyvalid = PR_TRUE; michael@0: michael@0: RSAPublicKey rsaBlapiPublicKey; /* hold RSA public key */ michael@0: michael@0: rsareq = fopen(reqfn, "r"); michael@0: rsaresp = stdout; michael@0: memset(&rsaBlapiPublicKey, 0, sizeof(RSAPublicKey)); michael@0: michael@0: while (fgets(buf, sizeof buf, rsareq) != NULL) { michael@0: /* a comment or blank line */ michael@0: if (buf[0] == '#' || buf[0] == '\n') { michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* [Mod = ...] */ michael@0: if (buf[0] == '[') { michael@0: unsigned int flen; /* length in bytes of the field size */ michael@0: michael@0: if (rsaBlapiPublicKey.modulus.data) { /* n */ michael@0: SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE); michael@0: } michael@0: if (sscanf(buf, "[mod = %d]", &modulus) != 1) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (modulus > RSA_MAX_TEST_MODULUS_BITS) { michael@0: fprintf(rsaresp,"ERROR: modulus greater than test maximum\n"); michael@0: goto loser; michael@0: } michael@0: michael@0: fputs(buf, rsaresp); michael@0: michael@0: signatureLength = flen = modulus/8; michael@0: michael@0: SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.modulus, flen); michael@0: if (rsaBlapiPublicKey.modulus.data == NULL) { michael@0: goto loser; michael@0: } michael@0: continue; michael@0: } michael@0: michael@0: /* n = ... modulus */ michael@0: if (buf[0] == 'n') { michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: keyvalid = from_hex_str(&rsaBlapiPublicKey.modulus.data[0], michael@0: rsaBlapiPublicKey.modulus.len, michael@0: &buf[i]); michael@0: michael@0: if (!keyvalid) { michael@0: fprintf(rsaresp, "ERROR: rsa_sigver n not valid.\n"); michael@0: goto loser; michael@0: } michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* SHAAlg = ... */ michael@0: if (strncmp(buf, "SHAAlg", 6) == 0) { michael@0: i = 6; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: /* set the SHA Algorithm */ michael@0: if (strncmp(&buf[i], "SHA1", 4) == 0) { michael@0: shaAlg = HASH_AlgSHA1; michael@0: } else if (strncmp(&buf[i], "SHA224", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA224; michael@0: } else if (strncmp(&buf[i], "SHA256", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA256; michael@0: } else if (strncmp(&buf[i], "SHA384", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA384; michael@0: } else if (strncmp(&buf[i], "SHA512", 6) == 0) { michael@0: shaAlg = HASH_AlgSHA512; michael@0: } else { michael@0: fprintf(rsaresp, "ERROR: Unable to find SHAAlg type"); michael@0: goto loser; michael@0: } michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* e = ... public Key */ michael@0: if (buf[0] == 'e') { michael@0: unsigned char data[RSA_MAX_TEST_EXPONENT_BYTES]; michael@0: unsigned char t; michael@0: michael@0: memset(data, 0, sizeof data); michael@0: michael@0: if (rsaBlapiPublicKey.publicExponent.data) { /* e */ michael@0: SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE); michael@0: } michael@0: michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: /* skip leading zero's */ michael@0: while (isxdigit(buf[i])) { michael@0: hex_to_byteval(&buf[i], &t); michael@0: if (t == 0) { michael@0: i+=2; michael@0: } else break; michael@0: } michael@0: michael@0: /* get the exponent */ michael@0: for (j=0; isxdigit(buf[i]) && j < sizeof data; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &data[j]); michael@0: } michael@0: michael@0: if (j == 0) { j = 1; } /* to handle 1 byte length exponents */ michael@0: michael@0: SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.publicExponent, j); michael@0: if (rsaBlapiPublicKey.publicExponent.data == NULL) { michael@0: goto loser; michael@0: } michael@0: michael@0: for (i=0; i < j; i++) { michael@0: rsaBlapiPublicKey.publicExponent.data[i] = data[i]; michael@0: } michael@0: michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: } michael@0: michael@0: /* Msg = ... */ michael@0: if (strncmp(buf, "Msg", 3) == 0) { michael@0: unsigned char msg[128]; /* MAX msg 128 */ michael@0: michael@0: memset(sha, 0, sizeof sha); michael@0: memset(msg, 0, sizeof msg); michael@0: michael@0: i = 3; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: michael@0: for (j=0; isxdigit(buf[i]) && j < sizeof msg; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &msg[j]); michael@0: } michael@0: michael@0: shaLength = fips_hashLen(shaAlg); michael@0: if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) { michael@0: if (shaLength == 0) { michael@0: fprintf(rsaresp, "ERROR: SHAAlg not defined."); michael@0: } michael@0: fprintf(rsaresp, "ERROR: Unable to generate SHA%x", michael@0: shaLength == 160 ? 1 : shaLength); michael@0: goto loser; michael@0: } michael@0: michael@0: fputs(buf, rsaresp); michael@0: continue; michael@0: michael@0: } michael@0: michael@0: /* S = ... */ michael@0: if (buf[0] == 'S') { michael@0: SECStatus rv = SECFailure; michael@0: NSSLOWKEYPublicKey * rsa_public_key; michael@0: NSSLOWKEYPublicKey low_RSA_public_key = { NULL, michael@0: NSSLOWKEYRSAKey, }; michael@0: michael@0: /* convert to a low RSA public key */ michael@0: low_RSA_public_key.u.rsa = rsaBlapiPublicKey; michael@0: rsa_public_key = &low_RSA_public_key; michael@0: michael@0: memset(signature, 0, sizeof(signature)); michael@0: i = 1; michael@0: while (isspace(buf[i]) || buf[i] == '=') { michael@0: i++; michael@0: } michael@0: michael@0: for (j=0; isxdigit(buf[i]) && j < sizeof signature; i+=2,j++) { michael@0: hex_to_byteval(&buf[i], &signature[j]); michael@0: } michael@0: michael@0: signatureLength = j; michael@0: fputs(buf, rsaresp); michael@0: michael@0: /* Perform RSA verification with the RSA public key. */ michael@0: rv = RSA_HashCheckSign( shaOid, michael@0: rsa_public_key, michael@0: signature, michael@0: signatureLength, michael@0: sha, michael@0: shaLength); michael@0: if( rv == SECSuccess ) { michael@0: fputs("Result = P\n", rsaresp); michael@0: } else { michael@0: fputs("Result = F\n", rsaresp); michael@0: } michael@0: continue; michael@0: } michael@0: } michael@0: loser: michael@0: fclose(rsareq); michael@0: if (rsaBlapiPublicKey.modulus.data) { /* n */ michael@0: SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE); michael@0: } michael@0: if (rsaBlapiPublicKey.publicExponent.data) { /* e */ michael@0: SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE); michael@0: } michael@0: } michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: if (argc < 2) exit (-1); michael@0: michael@0: RNG_RNGInit(); michael@0: SECOID_Init(); michael@0: michael@0: /*************/ michael@0: /* TDEA */ michael@0: /*************/ michael@0: if (strcmp(argv[1], "tdea") == 0) { michael@0: /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=.req */ michael@0: if (strcmp(argv[2], "kat") == 0) { michael@0: /* Known Answer Test (KAT) */ michael@0: tdea_kat_mmt(argv[4]); michael@0: } else if (strcmp(argv[2], "mmt") == 0) { michael@0: /* Multi-block Message Test (MMT) */ michael@0: tdea_kat_mmt(argv[4]); michael@0: } else if (strcmp(argv[2], "mct") == 0) { michael@0: /* Monte Carlo Test (MCT) */ michael@0: if (strcmp(argv[3], "ecb") == 0) { michael@0: /* ECB mode */ michael@0: tdea_mct(NSS_DES_EDE3, argv[4]); michael@0: } else if (strcmp(argv[3], "cbc") == 0) { michael@0: /* CBC mode */ michael@0: tdea_mct(NSS_DES_EDE3_CBC, argv[4]); michael@0: } michael@0: } michael@0: /*************/ michael@0: /* AES */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "aes") == 0) { michael@0: /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=.req */ michael@0: if ( strcmp(argv[2], "kat") == 0) { michael@0: /* Known Answer Test (KAT) */ michael@0: aes_kat_mmt(argv[4]); michael@0: } else if (strcmp(argv[2], "mmt") == 0) { michael@0: /* Multi-block Message Test (MMT) */ michael@0: aes_kat_mmt(argv[4]); michael@0: } else if (strcmp(argv[2], "mct") == 0) { michael@0: /* Monte Carlo Test (MCT) */ michael@0: if ( strcmp(argv[3], "ecb") == 0) { michael@0: /* ECB mode */ michael@0: aes_ecb_mct(argv[4]); michael@0: } else if (strcmp(argv[3], "cbc") == 0) { michael@0: /* CBC mode */ michael@0: aes_cbc_mct(argv[4]); michael@0: } michael@0: } michael@0: /*************/ michael@0: /* SHA */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "sha") == 0) { michael@0: sha_test(argv[2]); michael@0: /*************/ michael@0: /* RSA */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "rsa") == 0) { michael@0: /* argv[2]=siggen|sigver */ michael@0: /* argv[3]=.req */ michael@0: if (strcmp(argv[2], "siggen") == 0) { michael@0: /* Signature Generation Test */ michael@0: rsa_siggen_test(argv[3]); michael@0: } else if (strcmp(argv[2], "sigver") == 0) { michael@0: /* Signature Verification Test */ michael@0: rsa_sigver_test(argv[3]); michael@0: } michael@0: /*************/ michael@0: /* HMAC */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "hmac") == 0) { michael@0: hmac_test(argv[2]); michael@0: /*************/ michael@0: /* DSA */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "dsa") == 0) { michael@0: /* argv[2]=keypair|pqggen|pqgver|siggen|sigver */ michael@0: /* argv[3]=.req */ michael@0: if (strcmp(argv[2], "keypair") == 0) { michael@0: /* Key Pair Generation Test */ michael@0: dsa_keypair_test(argv[3]); michael@0: } else if (strcmp(argv[2], "pqggen") == 0) { michael@0: /* Domain Parameter Generation Test */ michael@0: dsa_pqggen_test(argv[3]); michael@0: } else if (strcmp(argv[2], "pqgver") == 0) { michael@0: /* Domain Parameter Validation Test */ michael@0: dsa_pqgver_test(argv[3]); michael@0: } else if (strcmp(argv[2], "siggen") == 0) { michael@0: /* Signature Generation Test */ michael@0: dsa_siggen_test(argv[3]); michael@0: } else if (strcmp(argv[2], "sigver") == 0) { michael@0: /* Signature Verification Test */ michael@0: dsa_sigver_test(argv[3]); michael@0: } michael@0: #ifndef NSS_DISABLE_ECC michael@0: /*************/ michael@0: /* ECDSA */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "ecdsa") == 0) { michael@0: /* argv[2]=keypair|pkv|siggen|sigver argv[3]=.req */ michael@0: if ( strcmp(argv[2], "keypair") == 0) { michael@0: /* Key Pair Generation Test */ michael@0: ecdsa_keypair_test(argv[3]); michael@0: } else if (strcmp(argv[2], "pkv") == 0) { michael@0: /* Public Key Validation Test */ michael@0: ecdsa_pkv_test(argv[3]); michael@0: } else if (strcmp(argv[2], "siggen") == 0) { michael@0: /* Signature Generation Test */ michael@0: ecdsa_siggen_test(argv[3]); michael@0: } else if (strcmp(argv[2], "sigver") == 0) { michael@0: /* Signature Verification Test */ michael@0: ecdsa_sigver_test(argv[3]); michael@0: } michael@0: #endif /* NSS_DISABLE_ECC */ michael@0: /*************/ michael@0: /* RNG */ michael@0: /*************/ michael@0: } else if (strcmp(argv[1], "rng") == 0) { michael@0: /* argv[2]=vst|mct argv[3]=.req */ michael@0: if ( strcmp(argv[2], "vst") == 0) { michael@0: /* Variable Seed Test */ michael@0: rng_vst(argv[3]); michael@0: } else if (strcmp(argv[2], "mct") == 0) { michael@0: /* Monte Carlo Test */ michael@0: rng_mct(argv[3]); michael@0: } michael@0: } else if (strcmp(argv[1], "drbg") == 0) { michael@0: /* Variable Seed Test */ michael@0: drbg(argv[2]); michael@0: } else if (strcmp(argv[1], "ddrbg") == 0) { michael@0: debug = 1; michael@0: drbg(argv[2]); michael@0: } michael@0: return 0; michael@0: }