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