/* 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/. */
/* * Convert a string of hex digits (str) to an array (buf) of len bytes. * Return PR_TRUE if the hex string can fit in the byte array. Return * PR_FALSE if the hex string is empty or is too long.
*/
PRBool
from_hex_str(unsignedchar *buf, unsignedint len, constchar *str)
{ unsignedint nxdigit; /* number of hex digits in str */ unsignedint i; /* index into buf */ unsignedint j; /* index into str */
/* count the hex digits */
nxdigit = 0; for (nxdigit = 0; isxdigit((unsignedchar)str[nxdigit]); nxdigit++) { /* empty body */
} if (nxdigit == 0) { return PR_FALSE;
} if (nxdigit > 2 * len) { /* * The input hex string is too long, but we allow it if the * extra digits are leading 0's.
*/ for (j = 0; j < nxdigit - 2 * len; j++) { if (str[j] != '0') { return PR_FALSE;
}
} /* skip leading 0's */
str += nxdigit - 2 * len;
nxdigit = 2 * len;
} for (i = 0, j = 0; i < len; i++) { if (2 * i < 2 * len - nxdigit) { /* Handle a short input as if we padded it with leading 0's. */ if (2 * i + 1 < 2 * len - nxdigit) {
buf[i] = 0;
} else { char tmp[2];
tmp[0] = '0';
tmp[1] = str[j];
hex_to_byteval(tmp, &buf[i]);
j++;
}
} else {
hex_to_byteval(&str[j], &buf[i]);
j += 2;
}
} return PR_TRUE;
}
/* * 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 */ unsignedchar key[24]; /* TDEA 3 key bundle */ unsignedint numKeys = 0; unsignedchar iv[8]; /* for all modes except ECB */ unsignedchar plaintext[8 * 20]; /* 1 to 20 blocks */ unsignedint plaintextlen; unsignedchar ciphertext[8 * 20]; /* 1 to 20 blocks */ unsignedint 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((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 8; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 16; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
}
fputs(buf, resp); continue;
}
/* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (crypt != ENCRYPT) { goto loser;
}
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
plaintextlen = j;
rv = tdea_encrypt_buf(mode, key,
(mode == NSS_DES_EDE3) ? NULL : iv,
ciphertext, &ciphertextlen, sizeof ciphertext,
plaintext, plaintextlen); if (rv != SECSuccess) { goto loser;
}
/* * Set the parity bit for the given byte
*/
BYTE
odd_parity(BYTE in)
{
BYTE out = in;
in ^= in >> 4;
in ^= in >> 2;
in ^= in >> 1; return (BYTE)(out ^ !(in & 1));
}
/* * Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j] * for TDEA Monte Carlo Test (MCT) in ECB and CBC modes.
*/ void
tdea_mct_next_keys(unsignedchar *key, constunsignedchar *text_2, constunsignedchar *text_1, constunsignedchar *text, unsignedint numKeys)
{ int 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, unsignedchar *key, unsignedint numKeys, unsignedint crypt, unsignedchar *inputtext, unsignedint inputlength, unsignedchar *iv, FILE *resp)
{
int i, j; unsignedchar outputtext_1[8]; /* PT/CT[j-1] */ unsignedchar outputtext_2[8]; /* PT/CT[j-2] */ char buf[80]; /* holds one line from the input REQUEST file. */ unsignedint outputlen; unsignedchar outputtext[8];
SECStatus rv;
if (mode == NSS_DES_EDE3 && iv != NULL) {
printf("IV must be NULL for NSS_DES_EDE3 mode"); goto loser;
} elseif (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 */
snprintf(buf, sizeof(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);
}
/* 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 (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 */ unsignedint crypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[24]; /* TDEA 3 key bundle */ unsignedint numKeys = 0; unsignedchar plaintext[8]; /* PT[j] */ unsignedchar ciphertext[8]; /* CT[j] */ unsignedchar 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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
numKeys = atoi(&buf[i]); continue;
} /* KEY1 = ... */ if (strncmp(buf, "KEY1", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
} continue;
} /* KEY2 = ... */ if (strncmp(buf, "KEY2", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 8; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
} continue;
} /* KEY3 = ... */ if (strncmp(buf, "KEY3", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 16; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
} continue;
}
/* IV = ... */ if (strncmp(buf, "IV", 2) == 0) {
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
} continue;
}
/* * Doublecheck our result by encrypting the plaintext and * compare the output with the input ciphertext.
*/
cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16); if (cx == NULL) { goto loser;
}
rv = AES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
output, *outputlen); if (rv != SECSuccess) { goto loser;
} if (doublechecklen != *outputlen) { goto loser;
}
AES_DestroyContext(cx, PR_TRUE);
cx = NULL; if (memcmp(doublecheck, input, inputlen) != 0) { goto loser;
}
rv = SECSuccess;
loser: if (cx != NULL) {
AES_DestroyContext(cx, PR_TRUE);
} return rv;
} /* * Perform the AES GCM tests. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_gcm(char *reqfn, int encrypt)
{ char buf[512]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "CIPHERTEXT = <320 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar iv[128]; /* handle large gcm IV's */ unsignedchar plaintext[10 * 16]; /* 1 to 10 blocks */ unsignedint plaintextlen; unsignedchar ciphertext[11 * 16]; /* 1 to 10 blocks + tag */ unsignedint ciphertextlen; unsignedchar aad[11 * 16]; /* 1 to 10 blocks + tag */ unsignedint aadlen = 0; unsignedint tagbits; unsignedint taglen = 0; unsignedint ivlen;
CK_NSS_GCM_PARAMS params;
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, "[Taglen", 7) == 0) { if (sscanf(buf, "[Taglen = %d]", &tagbits) != 1) { goto loser;
}
taglen = tagbits / 8;
} if (strncmp(buf, "[IVlen", 6) == 0) { if (sscanf(buf, "[IVlen = %d]", &ivlen) != 1) { goto loser;
}
ivlen = ivlen / 8;
}
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);
plaintextlen = 0;
memset(ciphertext, 0, sizeof ciphertext);
ciphertextlen = 0;
fputs(buf, aesresp); continue;
} /* KEY = ... */ if (strncmp(buf, "Key", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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) {
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
}
fputs(buf, aesresp); continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PT", 2) == 0) { /* sanity check */ if (!encrypt) { goto loser;
}
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
plaintextlen = j;
fputs(buf, aesresp); continue;
} /* CIPHERTEXT = ... */ if (strncmp(buf, "CT", 2) == 0) { /* sanity check */ if (encrypt) { goto loser;
}
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &ciphertext[j]);
}
ciphertextlen = j;
fputs(buf, aesresp); continue;
} if (strncmp(buf, "AAD", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &aad[j]);
}
aadlen = j;
fputs(buf, aesresp); if (encrypt) { if (encrypt == 2) {
rv = RNG_GenerateGlobalRandomBytes(iv, ivlen); if (rv != SECSuccess) { goto loser;
}
}
params.pIv = iv;
params.ulIvLen = ivlen;
params.pAAD = aad;
params.ulAADLen = aadlen;
params.ulTagBits = tagbits;
rv = aes_encrypt_buf(NSS_AES_GCM, key, keysize,
(unsignedchar *)¶ms,
ciphertext, &ciphertextlen, sizeof ciphertext,
plaintext, plaintextlen); if (rv != SECSuccess) { goto loser;
}
/* * Perform the AES Known Answer Test (KAT) or Multi-block Message * Test (MMT) in ECB or CBC mode. The KAT (there are four types) * and MMT have the same structure: given the key and IV (CBC mode * only), encrypt the given plaintext or decrypt the given ciphertext. * So we can handle them the same way. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_kat_mmt(char *reqfn)
{ char buf[512]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "CIPHERTEXT = <320 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; int mode = NSS_AES; /* NSS_AES (ECB) or NSS_AES_CBC */ int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar iv[16]; /* for all modes except ECB */ unsignedchar plaintext[10 * 16]; /* 1 to 10 blocks */ unsignedint plaintextlen; unsignedchar ciphertext[10 * 16]; /* 1 to 10 blocks */ unsignedint 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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
}
fputs(buf, aesresp); continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (!encrypt) { goto loser;
}
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
plaintextlen = j;
/* * Generate Key[i+1] from Key[i], CT[j-1], and CT[j] for AES Monte Carlo * Test (MCT) in ECB and CBC modes.
*/ void
aes_mct_next_key(unsignedchar *key, unsignedint keysize, constunsignedchar *ciphertext_1, constunsignedchar *ciphertext)
{ int k;
switch (keysize) { case 16: /* 128-bit key */ /* Key[i+1] = Key[i] xor CT[j] */ for (k = 0; k < 16; k++) {
key[k] ^= ciphertext[k];
} break; case 24: /* 192-bit key */ /* * Key[i+1] = Key[i] xor (last 64-bits of * CT[j-1] || CT[j])
*/ for (k = 0; k < 8; k++) {
key[k] ^= ciphertext_1[k + 8];
} for (k = 8; k < 24; k++) {
key[k] ^= ciphertext[k - 8];
} break; case 32: /* 256-bit key */ /* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */ for (k = 0; k < 16; k++) {
key[k] ^= ciphertext_1[k];
} for (k = 16; k < 32; k++) {
key[k] ^= ciphertext[k - 16];
} break;
}
}
/* * Perform the AES Monte Carlo Test (MCT) in ECB mode. MCT exercises * our AES code in streaming mode because the plaintext or ciphertext * is generated block by block as we go, so we can't collect all the * plaintext or ciphertext in one buffer and encrypt or decrypt it in * one shot. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_ecb_mct(char *reqfn)
{ char buf[80]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "KEY = <64 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar plaintext[16]; /* PT[j] */ unsignedchar plaintext_1[16]; /* PT[j-1] */ unsignedchar ciphertext[16]; /* CT[j] */ unsignedchar ciphertext_1[16]; /* CT[j-1] */ unsignedchar doublecheck[16]; unsignedint 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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof plaintext; i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
/* * Perform the AES Monte Carlo Test (MCT) in CBC mode. MCT exercises * our AES code in streaming mode because the plaintext or ciphertext * is generated block by block as we go, so we can't collect all the * plaintext or ciphertext in one buffer and encrypt or decrypt it in * one shot. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
aes_cbc_mct(char *reqfn)
{ char buf[80]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "KEY = <64 hex digits>\n".
*/
FILE *aesreq; /* input stream from the REQUEST file */
FILE *aesresp; /* output stream to the RESPONSE file */ int i, j; int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ unsignedchar key[32]; /* 128, 192, or 256 bits */ unsignedint keysize = 0; unsignedchar iv[16]; unsignedchar plaintext[16]; /* PT[j] */ unsignedchar plaintext_1[16]; /* PT[j-1] */ unsignedchar ciphertext[16]; /* CT[j] */ unsignedchar ciphertext_1[16]; /* CT[j-1] */ unsignedchar doublecheck[16]; unsignedint 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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof iv; i += 2, j++) {
hex_to_byteval(&buf[i], &iv[j]);
} continue;
} /* PLAINTEXT = ... */ if (strncmp(buf, "PLAINTEXT", 9) == 0) { /* sanity check */ if (!encrypt) { goto loser;
} /* PT[0] = PT */
i = 9; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof plaintext; i += 2, j++) {
hex_to_byteval(&buf[i], &plaintext[j]);
}
/* * 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;
}
/* * HASH_ functions are available to full NSS apps and internally inside * freebl, but not exported to users of freebl. Create short stubs to * replace the functionality for fipstest.
*/
SECStatus
fips_hashBuf(HASH_HashType type, unsignedchar *hashBuf, unsignedchar *msg, int len)
{
SECStatus rv = SECFailure;
switch (type) { case HASH_AlgSHA1:
rv = SHA1_HashBuf(hashBuf, msg, len); break; case HASH_AlgSHA224:
rv = SHA224_HashBuf(hashBuf, msg, len); break; case HASH_AlgSHA256:
rv = SHA256_HashBuf(hashBuf, msg, len); break; case HASH_AlgSHA384:
rv = SHA384_HashBuf(hashBuf, msg, len); break; case HASH_AlgSHA512:
rv = SHA512_HashBuf(hashBuf, msg, len); break; default: break;
} return rv;
}
int
fips_hashLen(HASH_HashType type)
{ int len = 0;
switch (type) { case HASH_AlgSHA1:
len = SHA1_LENGTH; break; case HASH_AlgSHA224:
len = SHA224_LENGTH; break; case HASH_AlgSHA256:
len = SHA256_LENGTH; break; case HASH_AlgSHA384:
len = SHA384_LENGTH; break; case HASH_AlgSHA512:
len = SHA512_LENGTH; break; default: break;
} return len;
}
SECOidTag
fips_hashOid(HASH_HashType type)
{
SECOidTag oid = SEC_OID_UNKNOWN;
switch (type) { case HASH_AlgSHA1:
oid = SEC_OID_SHA1; break; case HASH_AlgSHA224:
oid = SEC_OID_SHA224; break; case HASH_AlgSHA256:
oid = SEC_OID_SHA256; break; case HASH_AlgSHA384:
oid = SEC_OID_SHA384; break; case HASH_AlgSHA512:
oid = SEC_OID_SHA512; break; default: break;
} return oid;
}
/* * 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 = NULL; int N; int i; unsignedint 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] == '[') { constchar *src; char *dst;
SECItem *encodedparams;
if (buf[1] == 'B') {
fputs(buf, ecdsaresp); continue;
} if (ecparams) {
PORT_FreeArena(ecparams->arena, PR_FALSE);
ecparams = NULL;
}
src = &buf[1];
dst = &curve[4];
*dst++ = tolower((unsignedchar)*src);
src += 2; /* skip the hyphen */
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst = '\0';
encodedparams = getECParams(curve); if (encodedparams == NULL) {
fprintf(stderr, "Unknown curve %s.", curve); goto loser;
} if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) {
fprintf(stderr, "Curve %s not supported.\n", curve); 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;
/* * 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; unsignedint i; unsignedint 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] == '[') { constchar *src; char *dst;
SECItem *encodedparams;
/* * 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; unsignedint len; unsignedchar msg[512]; /* message to be signed (<= 128 bytes) */ unsignedint msglen; unsignedchar sha[HASH_LENGTH_MAX]; /* SHA digest */ unsignedint shaLength = 0; /* length of SHA */
HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */ unsignedchar 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] == '[') { constchar *src; char *dst;
SECItem *encodedparams;
/* * 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; unsignedint i, j; unsignedint flen = 0; /* length in bytes of the field size */ unsignedint olen = 0; /* length in bytes of the base point order */ unsignedchar msg[512]; /* message that was signed (<= 128 bytes) */ unsignedint msglen = 0; unsignedchar sha[HASH_LENGTH_MAX]; /* SHA digest */ unsignedint shaLength = 0; /* length of SHA */
HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */ unsignedchar 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] == '[') { constchar *src; char *dst;
SECItem *encodedparams;
ECParams *ecparams;
/* * Perform the ECDH Functional Test. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ #define MAX_ECC_PARAMS 256 void
ecdh_functional(char *reqfn, PRBool response)
{ 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 *ecdhreq; /* input stream from the REQUEST file */
FILE *ecdhresp; /* output stream to the RESPONSE file */ char curve[16]; /* "nistxddd" */ unsignedchar hashBuf[HASH_LENGTH_MAX];
ECParams *ecparams[MAX_ECC_PARAMS] = { NULL };
ECPrivateKey *ecpriv = NULL;
ECParams *current_ecparams = NULL;
SECItem pubkey;
SECItem ZZ; unsignedint i; unsignedint len = 0; unsignedint uit_len = 0; int current_curve = -1;
HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
if ((current_curve < 0) || (current_curve > MAX_ECC_PARAMS)) {
fprintf(stderr, "No curve type defined\n"); goto loser;
}
src = &buf[1]; /* skip passed the colon */ while (*src && *src != ':')
src++; if (*src != ':') {
fprintf(stderr, "No colon in curve selected statement\n%s", buf); goto loser;
}
src++; /* skip to the first non-space */ while (*src && *src == ' ')
src++;
dst = &curve[4];
*dst++ = tolower((unsignedchar)*src);
src += 2; /* skip the hyphen */
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst = '\0'; if (ecparams[current_curve] != NULL) {
PORT_FreeArena(ecparams[current_curve]->arena, PR_FALSE);
ecparams[current_curve] = NULL;
}
encodedparams = getECParams(curve); if (encodedparams == NULL) {
fprintf(stderr, "Unknown curve %s.", curve); goto loser;
} if (EC_DecodeParams(encodedparams, &ecparams[current_curve]) != SECSuccess) {
fprintf(stderr, "Curve %s not supported.\n", curve); goto loser;
}
SECITEM_FreeItem(encodedparams, PR_TRUE);
fputs(buf, ecdhresp); continue;
} /* [Ex - SHAxxx] */ if (buf[1] == 'E' && buf[3] == ' ') { constchar *src;
current_curve = buf[2] - 'A'; if ((current_curve < 0) || (current_curve > 256)) {
fprintf(stderr, "bad curve type defined (%c)\n", buf[2]); goto loser;
}
current_ecparams = ecparams[current_curve]; if (current_ecparams == NULL) {
fprintf(stderr, "no curve defined for type %c defined\n",
buf[2]); goto loser;
} /* skip passed the colon */
src = &buf[1]; while (*src && *src != '-')
src++; if (*src != '-') {
fprintf(stderr, "No data in curve selected statement\n%s", buf); goto loser;
}
src++; /* skip to the first non-space */ while (*src && *src == ' ')
src++;
hash = hash_string_to_hashType(src); if (hash == HASH_AlgNULL) {
fprintf(ecdhresp, "ERROR: Unable to find SHAAlg type"); goto loser;
}
fputs(buf, ecdhresp); continue;
}
fputs(buf, ecdhresp); continue;
} /* COUNT = ... */ if (strncmp(buf, "COUNT", 5) == 0) {
fputs(buf, ecdhresp); if (current_ecparams == NULL) {
fprintf(stderr, "no curve defined for type %c defined\n",
buf[2]); goto loser;
}
len = (current_ecparams->fieldID.size + 7) >> 3; if (pubkey.data != NULL) {
PORT_Free(pubkey.data);
pubkey.data = NULL;
}
SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(current_ecparams)); if (pubkey.data == NULL) { goto loser;
}
pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED; continue;
} /* QeCAVSx = ... */ if (strncmp(buf, "QeCAVSx", 7) == 0) {
fputs(buf, ecdhresp);
i = 7; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
from_hex_str(&pubkey.data[1], len, &buf[i]); continue;
} /* QeCAVSy = ... */ if (strncmp(buf, "QeCAVSy", 7) == 0) {
fputs(buf, ecdhresp);
i = 7; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
from_hex_str(&pubkey.data[1 + len], len, &buf[i]); if (current_ecparams == NULL) {
fprintf(stderr, "no curve defined\n"); goto loser;
} /* validate CAVS public key */ if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) {
fprintf(stderr, "BAD key detected\n"); goto loser;
}
/* generate ECC key pair */ if (EC_NewKey(current_ecparams, &ecpriv) != SECSuccess) {
fprintf(stderr, "Failed to generate new key\n"); goto loser;
} /* validate UIT generated public key */ if (EC_ValidatePublicKey(current_ecparams, &ecpriv->publicValue) !=
SECSuccess) {
fprintf(stderr, "generate key did not validate\n"); goto loser;
} /* output UIT public key */
uit_len = ecpriv->publicValue.len; if (uit_len % 2 == 0) {
fprintf(stderr, "generate key had invalid public value len\n"); goto loser;
}
uit_len = (uit_len - 1) / 2; if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
fprintf(stderr, "generate key was compressed\n"); goto loser;
}
fputs("deIUT = ", ecdhresp);
to_hex_str(buf, ecpriv->privateValue.data, ecpriv->privateValue.len);
fputs(buf, ecdhresp);
fputc('\n', ecdhresp);
fputs("QeIUTx = ", ecdhresp);
to_hex_str(buf, &ecpriv->publicValue.data[1], uit_len);
fputs(buf, ecdhresp);
fputc('\n', ecdhresp);
fputs("QeIUTy = ", ecdhresp);
to_hex_str(buf, &ecpriv->publicValue.data[1 + uit_len], uit_len);
fputs(buf, ecdhresp);
fputc('\n', ecdhresp); /* ECDH */ if (ECDH_Derive(&pubkey, current_ecparams, &ecpriv->privateValue,
PR_FALSE, &ZZ) != SECSuccess) {
fprintf(stderr, "Derive failed\n"); goto loser;
} /* output hash of ZZ */ if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess) {
fprintf(stderr, "hash of derived key failed\n"); goto loser;
}
SECITEM_FreeItem(&ZZ, PR_FALSE);
fputs("HashZZ = ", ecdhresp);
to_hex_str(buf, hashBuf, fips_hashLen(hash));
fputs(buf, ecdhresp);
fputc('\n', ecdhresp);
fputc('\n', ecdhresp);
PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
ecpriv = NULL; continue;
}
}
loser: if (ecpriv != NULL) {
PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
} for (i = 0; i < MAX_ECC_PARAMS; i++) { if (ecparams[i] != NULL) {
PORT_FreeArena(ecparams[i]->arena, PR_FALSE);
ecparams[i] = NULL;
}
} if (pubkey.data != NULL) {
PORT_Free(pubkey.data);
}
fclose(ecdhreq);
}
/* * Perform the ECDH Validity Test. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
ecdh_verify(char *reqfn, PRBool response)
{ 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 *ecdhreq; /* input stream from the REQUEST file */
FILE *ecdhresp; /* output stream to the RESPONSE file */ char curve[16]; /* "nistxddd" */ unsignedchar hashBuf[HASH_LENGTH_MAX]; unsignedchar cavsHashBuf[HASH_LENGTH_MAX]; unsignedchar private_data[MAX_ECKEY_LEN];
ECParams *ecparams[MAX_ECC_PARAMS] = { NULL };
ECParams *current_ecparams = NULL;
SECItem pubkey;
SECItem ZZ;
SECItem private_value; unsignedint i; unsignedint len = 0; int current_curve = -1;
HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
/* * Perform the DH Functional Test. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ #define MAX_ECC_PARAMS 256 void
dh_functional(char *reqfn, PRBool response)
{ char buf[1024]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "YephCAVS = <512 hex digits>\n".
*/
FILE *dhreq; /* input stream from the REQUEST file */
FILE *dhresp; /* output stream to the RESPONSE file */ unsignedchar hashBuf[HASH_LENGTH_MAX];
DSAPrivateKey *dsapriv = NULL;
PQGParams pqg = { 0 }; unsignedchar pubkeydata[DSA_MAX_P_BITS / 8];
SECItem pubkey;
SECItem ZZ; unsignedint i, j; unsignedint pgySize;
HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
dhreq = fopen(reqfn, "r");
dhresp = stdout; while (fgets(buf, sizeof buf, dhreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
fputs(buf, dhresp); continue;
} if (buf[0] == '[') { /* [Fx - SHAxxx] */ if (buf[1] == 'F' && buf[3] == ' ') { constchar *src; /* skip passed the colon */
src = &buf[1]; while (*src && *src != '-')
src++; if (*src != '-') {
fprintf(stderr, "No hash specified\n%s", buf); goto loser;
}
src++; /* skip to the first non-space */ while (*src && *src == ' ')
src++;
hash = hash_string_to_hashType(src); if (hash == HASH_AlgNULL) {
fprintf(dhresp, "ERROR: Unable to find SHAAlg type"); goto loser;
} /* clear the PQG parameters */ 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);
}
pgySize = DSA_MAX_P_BITS / 8; /* change if more key sizes are supported in CAVS */
SECITEM_AllocItem(NULL, &pqg.prime, pgySize);
SECITEM_AllocItem(NULL, &pqg.base, pgySize);
pqg.prime.len = pqg.base.len = pgySize;
/* set q to the max allows */
SECITEM_AllocItem(NULL, &pqg.subPrime, DSA_MAX_Q_BITS / 8);
pqg.subPrime.len = DSA_MAX_Q_BITS / 8;
fputs(buf, dhresp); continue;
}
fputs(buf, dhresp); continue;
} if (buf[0] == 'P') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pqg.prime.len; i += 2, j++) { if (!isxdigit((unsignedchar)buf[i])) {
pqg.prime.len = j; break;
}
hex_to_byteval(&buf[i], &pqg.prime.data[j]);
}
fputs(buf, dhresp); continue;
}
/* Q = ... */ if (buf[0] == 'Q') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pqg.subPrime.len; i += 2, j++) { if (!isxdigit((unsignedchar)buf[i])) {
pqg.subPrime.len = j; break;
}
hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
}
fputs(buf, dhresp); continue;
}
/* G = ... */ if (buf[0] == 'G') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pqg.base.len; i += 2, j++) { if (!isxdigit((unsignedchar)buf[i])) {
pqg.base.len = j; break;
}
hex_to_byteval(&buf[i], &pqg.base.data[j]);
}
/* generate FCC key pair, nist uses pqg rather then pg,
* so use DSA to generate the key */ if (DSA_NewKey(&pqg, &dsapriv) != SECSuccess) {
fprintf(stderr, "Failed to generate new key\n"); goto loser;
}
fputs("XephemIUT = ", dhresp);
to_hex_str(buf, dsapriv->privateValue.data, dsapriv->privateValue.len);
fputs(buf, dhresp);
fputc('\n', dhresp);
fputs("YephemIUT = ", dhresp);
to_hex_str(buf, dsapriv->publicValue.data, dsapriv->publicValue.len);
fputs(buf, dhresp);
fputc('\n', dhresp); /* DH */ if (DH_Derive(&pubkey, &pqg.prime, &dsapriv->privateValue,
&ZZ, pqg.prime.len) != SECSuccess) {
fprintf(stderr, "Derive failed\n"); goto loser;
} /* output hash of ZZ */ if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess) {
fprintf(stderr, "hash of derived key failed\n"); goto loser;
}
SECITEM_FreeItem(&ZZ, PR_FALSE);
fputs("HashZZ = ", dhresp);
to_hex_str(buf, hashBuf, fips_hashLen(hash));
fputs(buf, dhresp);
fputc('\n', dhresp);
fputc('\n', dhresp);
PORT_FreeArena(dsapriv->params.arena, PR_TRUE);
dsapriv = NULL; continue;
}
}
loser: if (dsapriv != NULL) {
PORT_FreeArena(dsapriv->params.arena, PR_TRUE);
}
fclose(dhreq);
}
/* * Perform the DH Validity Test. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
dh_verify(char *reqfn, PRBool response)
{ char buf[1024]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "YephCAVS = <512 hex digits>\n".
*/
FILE *dhreq; /* input stream from the REQUEST file */
FILE *dhresp; /* output stream to the RESPONSE file */ unsignedchar hashBuf[HASH_LENGTH_MAX]; unsignedchar cavsHashBuf[HASH_LENGTH_MAX];
PQGParams pqg = { 0 }; unsignedchar pubkeydata[DSA_MAX_P_BITS / 8]; unsignedchar privkeydata[DSA_MAX_P_BITS / 8];
SECItem pubkey;
SECItem privkey;
SECItem ZZ; unsignedint i, j; unsignedint pgySize;
HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
dhreq = fopen(reqfn, "r");
dhresp = stdout; while (fgets(buf, sizeof buf, dhreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
fputs(buf, dhresp); continue;
} if (buf[0] == '[') { /* [Fx - SHAxxx] */ if (buf[1] == 'F' && buf[3] == ' ') { constchar *src; /* skip passed the colon */
src = &buf[1]; while (*src && *src != '-')
src++; if (*src != '-') {
fprintf(stderr, "No hash specified\n%s", buf); goto loser;
}
src++; /* skip to the first non-space */ while (*src && *src == ' ')
src++;
hash = hash_string_to_hashType(src); if (hash == HASH_AlgNULL) {
fprintf(dhresp, "ERROR: Unable to find SHAAlg type"); goto loser;
} /* clear the PQG parameters */ 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);
}
pgySize = DSA_MAX_P_BITS / 8; /* change if more key sizes are supported in CAVS */
SECITEM_AllocItem(NULL, &pqg.prime, pgySize);
SECITEM_AllocItem(NULL, &pqg.base, pgySize);
pqg.prime.len = pqg.base.len = pgySize;
/* set q to the max allows */
SECITEM_AllocItem(NULL, &pqg.subPrime, DSA_MAX_Q_BITS / 8);
pqg.subPrime.len = DSA_MAX_Q_BITS / 8;
fputs(buf, dhresp); continue;
}
fputs(buf, dhresp); continue;
} if (buf[0] == 'P') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pqg.prime.len; i += 2, j++) { if (!isxdigit((unsignedchar)buf[i])) {
pqg.prime.len = j; break;
}
hex_to_byteval(&buf[i], &pqg.prime.data[j]);
}
fputs(buf, dhresp); continue;
}
/* Q = ... */ if (buf[0] == 'Q') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pqg.subPrime.len; i += 2, j++) { if (!isxdigit((unsignedchar)buf[i])) {
pqg.subPrime.len = j; break;
}
hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
}
fputs(buf, dhresp); continue;
}
/* G = ... */ if (buf[0] == 'G') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pqg.base.len; i += 2, j++) { if (!isxdigit((unsignedchar)buf[i])) {
pqg.base.len = j; break;
}
hex_to_byteval(&buf[i], &pqg.base.data[j]);
}
/* * 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 */
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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<entropyInputLen*/
hex_to_byteval(&buf[i], &entropyInput[j]);
}
}
fputs(buf, rngresp); continue;
}
/* AttionalInputReseed = ... */ if (strncmp(buf, "AdditionalInputReseed", 21) == 0) { if (additionalInput) {
memset(additionalInput, 0, additionalInputLen);
i = 21; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<additionalInputLen*/
hex_to_byteval(&buf[i], &additionalInput[j]);
}
}
command = RESEED;
fputs(buf, rngresp); continue;
}
/* Entropy input = ... */ if (strncmp(buf, "EntropyInput", 12) == 0) {
i = 12; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<entropyInputLen*/
hex_to_byteval(&buf[i], &entropyInput[j]);
}
fputs(buf, rngresp); continue;
}
/* nouce = ... */ if (strncmp(buf, "Nonce", 5) == 0) {
i = 5; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<nonceLen*/
hex_to_byteval(&buf[i], &nonce[j]);
}
fputs(buf, rngresp); continue;
}
/* Personalization string = ... */ if (strncmp(buf, "PersonalizationString", 21) == 0) { if (personalizationString) {
i = 21; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<personalizationStringLen*/
hex_to_byteval(&buf[i], &personalizationString[j]);
}
}
fputs(buf, rngresp);
command = INSTANTIATE; continue;
}
/* Additional input = ... */ if (strncmp(buf, "AdditionalInput", 15) == 0) { if (additionalInput) {
i = 15; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<additionalInputLen*/
hex_to_byteval(&buf[i], &additionalInput[j]);
}
} if (genResult) {
command = RESULT;
} else {
command = GENERATE;
genResult = PR_TRUE; /* next time generate result */
}
fputs(buf, rngresp); continue;
}
/* Returned bits = ... */ if (strncmp(buf, "ReturnedBits", 12) == 0) {
i = 12; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)buf[i]); i += 2, j++) { /*j<additionalInputLen*/
hex_to_byteval(&buf[i], &predictedreturn_bytes[j]);
}
continue;
}
}
loser: if (predictedreturn_bytes) {
PORT_Free(predictedreturn_bytes);
} if (return_bytes) {
PORT_Free(return_bytes);
} if (additionalInput) {
PORT_Free(additionalInput);
} if (personalizationString) {
PORT_Free(personalizationString);
} if (nonce) {
PORT_Free(nonce);
} if (entropyInput) {
PORT_Free(entropyInput);
}
fclose(rngreq);
}
/* * Perform the RNG Variable Seed Test (VST) for the RNG algorithm * "DSA - Generation of X", used both as specified and as a generic * purpose RNG. The presence of "Q = ..." in the REQUEST file * indicates we are using the algorithm as specified. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
rng_vst(char *reqfn)
{ char buf[256]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "XSeed = <128 hex digits>\n".
*/
FILE *rngreq; /* input stream from the REQUEST file */
FILE *rngresp; /* output stream to the RESPONSE file */ unsignedint i, j; unsignedchar Q[DSA1_SUBPRIME_LEN];
PRBool hasQ = PR_FALSE; unsignedint b = 0; /* 160 <= b <= 512, b is a multiple of 8 */ unsignedchar XKey[512 / 8]; unsignedchar XSeed[512 / 8]; unsignedchar GENX[DSA1_SIGNATURE_LEN]; unsignedchar 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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof Q; i += 2, j++) {
hex_to_byteval(&buf[i], &Q[j]);
}
fputs(buf, rngresp);
hasQ = PR_TRUE; continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "COUNT", 5) == 0) { /* zeroize the variables for the test with this data set */
b = 0;
memset(XKey, 0, sizeof XKey);
memset(XSeed, 0, sizeof XSeed);
fputs(buf, rngresp); continue;
} /* b = ... */ if (buf[0] == 'b') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
b = atoi(&buf[i]); if (b < 160 || b > 512 || b % 8 != 0) { goto loser;
}
fputs(buf, rngresp); continue;
} /* XKey = ... */ if (strncmp(buf, "XKey", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < b / 8; i += 2, j++) {
hex_to_byteval(&buf[i], &XKey[j]);
}
fputs(buf, rngresp); continue;
} /* XSeed = ... */ if (strncmp(buf, "XSeed", 5) == 0) {
i = 5; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < b / 8; i += 2, j++) {
hex_to_byteval(&buf[i], &XSeed[j]);
}
fputs(buf, rngresp);
/* * Perform the RNG Monte Carlo Test (MCT) for the RNG algorithm * "DSA - Generation of X", used both as specified and as a generic * purpose RNG. The presence of "Q = ..." in the REQUEST file * indicates we are using the algorithm as specified. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
rng_mct(char *reqfn)
{ char buf[256]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "XSeed = <128 hex digits>\n".
*/
FILE *rngreq; /* input stream from the REQUEST file */
FILE *rngresp; /* output stream to the RESPONSE file */ unsignedint i, j; unsignedchar Q[DSA1_SUBPRIME_LEN];
PRBool hasQ = PR_FALSE; unsignedint b = 0; /* 160 <= b <= 512, b is a multiple of 8 */ unsignedchar XKey[512 / 8]; unsignedchar XSeed[512 / 8]; unsignedchar GENX[2 * SHA1_LENGTH]; unsignedchar 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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < sizeof Q; i += 2, j++) {
hex_to_byteval(&buf[i], &Q[j]);
}
fputs(buf, rngresp);
hasQ = PR_TRUE; continue;
} /* "COUNT = x" begins a new data set */ if (strncmp(buf, "COUNT", 5) == 0) { /* zeroize the variables for the test with this data set */
b = 0;
memset(XKey, 0, sizeof XKey);
memset(XSeed, 0, sizeof XSeed);
fputs(buf, rngresp); continue;
} /* b = ... */ if (buf[0] == 'b') {
i = 1; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
b = atoi(&buf[i]); if (b < 160 || b > 512 || b % 8 != 0) { goto loser;
}
fputs(buf, rngresp); continue;
} /* XKey = ... */ if (strncmp(buf, "XKey", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < b / 8; i += 2, j++) {
hex_to_byteval(&buf[i], &XKey[j]);
}
fputs(buf, rngresp); continue;
} /* XSeed = ... */ if (strncmp(buf, "XSeed", 5) == 0) { unsignedint k;
i = 5; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < b / 8; i += 2, j++) {
hex_to_byteval(&buf[i], &XSeed[j]);
}
fputs(buf, rngresp);
/* * Perform the SHA Tests. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
sha_test(char *reqfn)
{ unsignedint i, j; unsignedint MDlen = 0; /* the length of the Message Digest in Bytes */ unsignedint msgLen = 0; /* the length of the input Message in Bytes */ unsignedchar *msg = NULL; /* holds the message to digest.*/
size_t bufSize = 256 * 128; /*MAX buffer size */ char *buf = NULL; /* holds one line from the input REQUEST file.*/ unsignedchar seed[HASH_LENGTH_MAX]; /* max size of seed 64 bytes */ unsignedchar MD[HASH_LENGTH_MAX]; /* message digest */
FILE *req = NULL; /* input stream from the REQUEST file */
FILE *resp; /* output stream to the RESPONSE file */
/* * Perform the HMAC Tests. * * reqfn is the pathname of the input REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
hmac_test(char *reqfn)
{ unsignedint i, j;
size_t bufSize = 400; /* MAX buffer size */ char *buf = NULL; /* holds one line from the input REQUEST file.*/ unsignedint keyLen = 0; /* Key Length */ unsignedchar key[200]; /* key MAX size = 184 */ unsignedint msgLen = 128; /* the length of the input */ /* Message is always 128 Bytes */ unsignedchar *msg = NULL; /* holds the message to digest.*/ unsignedint HMACLen = 0; /* the length of the HMAC Bytes */ unsignedint TLen = 0; /* the length of the requested */ /* truncated HMAC Bytes */ unsignedchar HMAC[HASH_LENGTH_MAX]; /* computed HMAC */ unsignedchar expectedHMAC[HASH_LENGTH_MAX]; /* for .fax files that have */ /* supplied known answer */
HASH_HashType hash_alg = HASH_AlgNULL; /* HMAC type */
FILE *req = NULL; /* input stream from the REQUEST file */
FILE *resp; /* output stream to the RESPONSE file */
/* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, resp); continue;
} /* [L = Length of the MAC and HASH_type */ if (buf[0] == '[') { if (strncmp(&buf[1], "L ", 1) == 0) {
i = 2; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} /* HMACLen will get reused for Tlen */
HMACLen = atoi(&buf[i]);
hash_alg = sha_get_hashType(HMACLen * PR_BITS_PER_BYTE); if (hash_alg == HASH_AlgNULL) { goto loser;
}
fputs(buf, resp); continue;
}
} /* Count = test iteration number*/ if (strncmp(buf, "Count ", 5) == 0) { /* count can just be put into resp file */
fputs(buf, resp); /* zeroize the variables for the test with this data set */
keyLen = 0;
TLen = 0;
memset(key, 0, sizeof key);
memset(msg, 0, msgLen);
memset(HMAC, 0, sizeof HMAC); continue;
} /* KLen = Length of the Input Secret Key ... */ if (strncmp(buf, "Klen", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
keyLen = atoi(&buf[i]); /* in bytes */
fputs(buf, resp); continue;
} /* key = the secret key for the key to MAC */ if (strncmp(buf, "Key", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < keyLen; i += 2, j++) {
hex_to_byteval(&buf[i], &key[j]);
}
fputs(buf, resp);
} /* TLen = Length of the calculated HMAC */ if (strncmp(buf, "Tlen", 4) == 0) {
i = 4; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
}
TLen = atoi(&buf[i]); /* in bytes */
fputs(buf, resp); continue;
} /* MSG = to HMAC always 128 bytes for these tests */ if (strncmp(buf, "Msg", 3) == 0) {
i = 3; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < msgLen; i += 2, j++) {
hex_to_byteval(&buf[i], &msg[j]);
}
fputs(buf, resp); /* calculate the HMAC and output */ if (hmac_calc(HMAC, HMACLen, key, keyLen,
msg, msgLen, hash_alg) != SECSuccess) { goto loser;
}
fputs("Mac = ", resp);
to_hex_str(buf, HMAC, TLen);
fputs(buf, resp);
fputc('\n', resp); continue;
}
}
loser: if (req) {
fclose(req);
} if (buf) {
PORT_ZFree(buf, bufSize);
} if (msg) {
PORT_ZFree(msg, msgLen);
}
}
/* * Perform the DSA Key Pair Generation Test. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
dsa_keypair_test(char *reqfn)
{ char buf[800]; /* holds one line from the input REQUEST file * or to the output RESPONSE file. * 800 to hold (384 public key (x2 for HEX) + 1'\n'
*/
FILE *dsareq; /* input stream from the REQUEST file */
FILE *dsaresp; /* output stream to the RESPONSE file */ int count; int N; int L; int i;
PQGParams *pqg = NULL;
PQGVerify *vfy = NULL;
PRBool use_dsa1 = PR_FALSE; int keySizeIndex; /* index for valid key sizes */
dsareq = fopen(reqfn, "r");
dsaresp = stdout; while (fgets(buf, sizeof buf, dsareq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, dsaresp); continue;
}
/* [Mod = x] */ if (buf[0] == '[') { if (pqg != NULL) {
PQG_DestroyParams(pqg);
pqg = NULL;
} if (vfy != NULL) {
PQG_DestroyVerify(vfy);
vfy = NULL;
}
if (use_dsa1) { /************************************************************* * PQG_ParamGenSeedLen doesn't take a key size, it takes an * index that points to a valid key size.
*/
keySizeIndex = PQG_PBITS_TO_INDEX(L); if (keySizeIndex == -1 || L < 512 || L > 1024) {
fprintf(dsaresp, "DSA key size must be a multiple of 64 between 512 " "and 1024, inclusive"); goto loser;
}
/* Generate the parameters P, Q, and G */ if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
&pqg, &vfy) !=
SECSuccess) {
fprintf(dsaresp, "ERROR: Unable to generate PQG parameters"); goto loser;
}
} else { if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
fprintf(dsaresp, "ERROR: Unable to generate PQG parameters"); goto loser;
}
}
/* output P, Q, and G */
to_hex_str(buf, pqg->prime.data, pqg->prime.len);
fprintf(dsaresp, "P = %s\n", buf);
to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
fprintf(dsaresp, "Q = %s\n", buf);
to_hex_str(buf, pqg->base.data, pqg->base.len);
fprintf(dsaresp, "G = %s\n\n", buf); continue;
} /* N = ...*/ if (buf[0] == 'N') {
if (sscanf(buf, "N = %d", &count) != 1) { goto loser;
} /* Generate a DSA key, and output the key pair for N times */ for (i = 0; i < count; i++) {
DSAPrivateKey *dsakey = NULL; if (DSA_NewKey(pqg, &dsakey) != SECSuccess) {
fprintf(dsaresp, "ERROR: Unable to generate DSA key"); goto loser;
}
to_hex_str(buf, dsakey->privateValue.data,
dsakey->privateValue.len);
fprintf(dsaresp, "X = %s\n", buf);
to_hex_str(buf, dsakey->publicValue.data,
dsakey->publicValue.len);
fprintf(dsaresp, "Y = %s\n\n", buf);
PORT_FreeArena(dsakey->params.arena, PR_TRUE);
dsakey = NULL;
} continue;
}
}
loser:
fclose(dsareq);
}
/* * pqg generation type
*/ typedefenum {
FIPS186_1, /* Generate/Verify P,Q & G according to FIPS 186-1 */
A_1_2_1, /* Generate Provable 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; unsignedint i, j;
PQGParams pqg;
PQGVerify vfy; unsignedint pghSize = 0; /* size for p, g, and h */
dsa_pqg_type type = FIPS186_1;
continue;
} if (strncmp(buf, "index", 4) == 0) {
i = 5; while (isspace((unsignedchar)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((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; isxdigit((unsignedchar)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; unsignedint j; int output_g = 1;
PQGParams *pqg = NULL;
PQGVerify *vfy = NULL; unsignedint 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) {
fprintf(stderr, "NSS does Generate Probablistic Primes\n"); exit(1);
} elseif (strncmp(&buf[1], "A.2.1", 5) == 0) {
type = A_1_2_1;
output_g = 1; exit(1);
} elseif (strncmp(&buf[1], "A.2.3", 5) == 0) {
fprintf(stderr, "NSS only Generates G with P&Q\n"); exit(1);
} elseif (strncmp(&buf[1], "A.1.2.1", 7) == 0) {
type = A_1_2_1;
output_g = 0;
} else {
fprintf(stderr, "Unknown dsa pqggen test %s\n", &buf[1]); exit(1);
}
fputs(buf, dsaresp); continue;
}
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 (strncmp(buf, "Num", 3) == 0) { if (sscanf(buf, "Num = %d", &count) != 1) { goto loser;
}
} elseif (sscanf(buf, "N = %d", &count) != 1) { goto loser;
} for (i = 0; i < count; i++) {
SECStatus rv;
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 */ unsignedchar hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */ unsignedchar 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;
}
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; unsignedint i, j;
SECItem digest, signature;
DSAPublicKey pubkey; unsignedint pgySize; /* size for p, g, and y */ unsignedchar hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */ unsignedchar sig[DSA_MAX_SIGNATURE_LEN];
HASH_HashType hashType = HASH_AlgNULL; int hashNum = 0;
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);
}
}
staticvoid
pad(unsignedchar *buf, int pad_len, unsignedchar *src, int src_len)
{ int offset = 0; /* this shouldn't happen, fail right away rather than produce bad output */ if (pad_len < src_len) {
fprintf(stderr, "data bigger than expected! %d > %d\n", src_len, pad_len); exit(1);
}
/* * Perform the DSA Key Pair Generation Test. * * reqfn is the pathname of the REQUEST file. * * The output RESPONSE file is written to stdout.
*/ void
rsa_keypair_test(char *reqfn)
{ char buf[800]; /* holds one line from the input REQUEST file * or to the output RESPONSE file. * 800 to hold (384 public key (x2 for HEX) + 1'\n'
*/ unsignedchar buf2[400]; /* can't need more then 1/2 buf length */
FILE *rsareq; /* input stream from the REQUEST file */
FILE *rsaresp; /* output stream to the RESPONSE file */ int count; int i; int keySize = 1; /* key size in bits*/ int len = 0; /* key size in bytes */ int len2 = 0; /* key size in bytes/2 (prime size) */
SECItem e; unsignedchar default_e[] = { 0x1, 0x0, 0x1 };
e.data = default_e;
e.len = sizeof(default_e);
rsareq = fopen(reqfn, "r");
rsaresp = stdout; while (fgets(buf, sizeof buf, rsareq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, rsaresp); continue;
}
/* [Mod = x] */ if (buf[0] == '[') { if (buf[1] == 'm') { if (sscanf(buf, "[mod = %d]", &keySize) != 1) { goto loser;
}
len = keySize / 8;
len2 = keySize / 16;
}
fputs(buf, rsaresp); continue;
} /* N = ...*/ if (buf[0] == 'N') {
/* * 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; unsignedchar sha[HASH_LENGTH_MAX]; /* SHA digest */ unsignedint 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 }; unsignedchar 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 &
((unsignedlong)0xff000000L >> (i *
8)))) {
pubEx[peCount] =
(unsignedchar)((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;
}
/* 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; unsignedchar sha[HASH_LENGTH_MAX]; /* SHA digest */ unsignedint shaLength = 0; /* actual length of the digest */
HASH_HashType shaAlg = HASH_AlgNULL;
SECOidTag shaOid = SEC_OID_UNKNOWN; int modulus = 0; /* the Modulus size */ unsignedchar signature[513]; /* largest signature size + '\n' */ unsignedint signatureLength = 0; /* actual length of the signature */
PRBool keyvalid = PR_TRUE;
RSAPublicKey rsaBlapiPublicKey; /* hold RSA public key */
crv = NSC_Initialize((CK_VOID_PTR)&pk11args); if (crv != CKR_OK) {
fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsignedint)crv); goto loser;
}
count = slotListCount;
crv = NSC_GetSlotList(PR_TRUE, slotList, &count); if (crv != CKR_OK) {
fprintf(stderr, "NSC_GetSlotList failed crv=0x%x\n", (unsignedint)crv); goto loser;
} if ((count > slotListCount) || count < 1) {
fprintf(stderr, "NSC_GetSlotList returned too many or too few slots: %d slots max=%d min=1\n",
(int)count, (int)slotListCount); goto loser;
}
slotID = slotList[0];
tlsreq = fopen(reqfn, "r");
tlsresp = stdout; while (fgets(buf, sizeof buf, tlsreq) != NULL) { /* a comment or blank line */ if (buf[0] == '#' || buf[0] == '\n') {
fputs(buf, tlsresp); continue;
} /* [Xchange - SHA1] */ if (buf[0] == '[') { if (strncmp(buf, "[TLS", 4) == 0) { if (buf[7] == '0') { /* CK_SSL3_MASTER_KEY_DERIVE_PARAMS is a subset of * CK_TLS12_MASTER_KEY_DERIVE_PARAMS and * CK_SSL3_KEY_MAT_PARAMS is a subset of * CK_TLS12_KEY_MAT_PARAMS. The latter params have
* an extra prfHashMechanism field at the end. */
master_mech.mechanism = CKM_TLS_MASTER_KEY_DERIVE;
key_block_mech.mechanism = CKM_TLS_KEY_AND_MAC_DERIVE;
master_mech.ulParameterLen = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
key_block_mech.ulParameterLen = sizeof(CK_SSL3_KEY_MAT_PARAMS);
} elseif (buf[7] == '2') { if (strncmp(&buf[10], "SHA-1", 5) == 0) {
master_params.prfHashMechanism = CKM_SHA_1;
key_block_params.prfHashMechanism = CKM_SHA_1;
} elseif (strncmp(&buf[10], "SHA-224", 7) == 0) {
master_params.prfHashMechanism = CKM_SHA224;
key_block_params.prfHashMechanism = CKM_SHA224;
} elseif (strncmp(&buf[10], "SHA-256", 7) == 0) {
master_params.prfHashMechanism = CKM_SHA256;
key_block_params.prfHashMechanism = CKM_SHA256;
} elseif (strncmp(&buf[10], "SHA-384", 7) == 0) {
master_params.prfHashMechanism = CKM_SHA384;
key_block_params.prfHashMechanism = CKM_SHA384;
} elseif (strncmp(&buf[10], "SHA-512", 7) == 0) {
master_params.prfHashMechanism = CKM_SHA512;
key_block_params.prfHashMechanism = CKM_SHA512;
} else {
fprintf(tlsresp, "ERROR: Unable to find prf Hash type"); goto loser;
}
master_mech.mechanism = CKM_TLS12_MASTER_KEY_DERIVE;
key_block_mech.mechanism = CKM_TLS12_KEY_AND_MAC_DERIVE;
master_mech.ulParameterLen = sizeof(master_params);
key_block_mech.ulParameterLen = sizeof(key_block_params);
} else {
fprintf(stderr, "Unknown TLS type %x\n",
(unsignedint)buf[0]); goto loser;
}
} if (strncmp(buf, "[pre-master", 11) == 0) { if (sscanf(buf, "[pre-master secret length = %d]",
&pms_len) != 1) { goto loser;
}
pms_len = pms_len / 8;
pms = malloc(pms_len);
master_secret = malloc(pms_len);
create_template[0].pValue = pms;
create_template[0].ulValueLen = pms_len;
master_template.pValue = master_secret;
master_template.ulValueLen = pms_len;
} if (strncmp(buf, "[key", 4) == 0) { if (sscanf(buf, "[key block length = %d]", &key_block_len) != 1) { goto loser;
}
key_block_params.ulKeySizeInBits = 8;
key_block_params.ulIVSizeInBits = key_block_len / 2 - 8;
key_block_len = key_block_len / 8;
key_block = malloc(key_block_len);
kb1_template.pValue = &key_block[0];
kb1_template.ulValueLen = 1;
kb2_template.pValue = &key_block[1];
kb2_template.ulValueLen = 1;
key_material.pIVClient = &key_block[2];
key_material.pIVServer = &key_block[2 + key_block_len / 2 - 1];
}
fputs(buf, tlsresp); 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(pms, 0, pms_len);
memset(master_secret, 0, pms_len);
memset(key_block, 0, key_block_len);
fputs(buf, tlsresp); continue;
} /* pre_master_secret = ... */ if (strncmp(buf, "pre_master_secret", 17) == 0) {
i = 17; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < pms_len; i += 2, j++) {
hex_to_byteval(&buf[i], &pms[j]);
}
fputs(buf, tlsresp); continue;
} /* serverHello_random = ... */ if (strncmp(buf, "serverHello_random", 18) == 0) {
i = 18; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < SSL3_RANDOM_LENGTH; i += 2, j++) {
hex_to_byteval(&buf[i], &serverHello_random[j]);
}
fputs(buf, tlsresp); continue;
} /* clientHello_random = ... */ if (strncmp(buf, "clientHello_random", 18) == 0) {
i = 18; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < SSL3_RANDOM_LENGTH; i += 2, j++) {
hex_to_byteval(&buf[i], &clientHello_random[j]);
}
fputs(buf, tlsresp); continue;
} /* server_random = ... */ if (strncmp(buf, "server_random", 13) == 0) {
i = 13; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < SSL3_RANDOM_LENGTH; i += 2, j++) {
hex_to_byteval(&buf[i], &server_random[j]);
}
fputs(buf, tlsresp); continue;
} /* client_random = ... */ if (strncmp(buf, "client_random", 13) == 0) {
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE pms_handle;
CK_OBJECT_HANDLE master_handle;
CK_OBJECT_HANDLE fake_handle;
i = 13; while (isspace((unsignedchar)buf[i]) || buf[i] == '=') {
i++;
} for (j = 0; j < SSL3_RANDOM_LENGTH; i += 2, j++) {
hex_to_byteval(&buf[i], &client_random[j]);
}
fputs(buf, tlsresp);
crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session); if (crv != CKR_OK) {
fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
crv = NSC_CreateObject(session, create_template,
create_template_count, &pms_handle); if (crv != CKR_OK) {
fprintf(stderr, "NSC_CreateObject failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
crv = NSC_DeriveKey(session, &master_mech, pms_handle,
derive_template, derive_template_count - 1,
&master_handle); if (crv != CKR_OK) {
fprintf(stderr, "NSC_DeriveKey(master) failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
crv = NSC_GetAttributeValue(session, master_handle,
&master_template, 1); if (crv != CKR_OK) {
fprintf(stderr, "NSC_GetAttribute failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
fputs("master_secret = ", tlsresp);
to_hex_str(buf, master_secret, pms_len);
fputs(buf, tlsresp);
fputc('\n', tlsresp);
crv = NSC_DeriveKey(session, &key_block_mech, master_handle,
derive_template, derive_template_count, &fake_handle); if (crv != CKR_OK) {
fprintf(stderr, "NSC_DeriveKey(keyblock) failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
crv = NSC_GetAttributeValue(session, key_material.hClientKey,
&kb1_template, 1); if (crv != CKR_OK) {
fprintf(stderr, "NSC_GetAttribute failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
crv = NSC_GetAttributeValue(session, key_material.hServerKey,
&kb2_template, 1); if (crv != CKR_OK) {
fprintf(stderr, "NSC_GetAttribute failed crv=0x%x\n",
(unsignedint)crv); goto loser;
}
fputs("key_block = ", tlsresp);
to_hex_str(buf, key_block, key_block_len);
fputs(buf, tlsresp);
fputc('\n', tlsresp);
crv = NSC_CloseSession(session); continue;
}
}
loser:
NSC_Finalize(NULL); if (pms)
free(pms); if (master_secret)
free(master_secret); if (key_block)
free(key_block); if (tlsreq)
fclose(tlsreq);
}
void
ikev1(char *reqfn)
{ char buf[4096]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "g^xy = <2048 hex digits>\n".
*/ unsignedchar *gxy = NULL; int gxy_len; unsignedchar *Ni = NULL; int Ni_len; unsignedchar *Nr = NULL; int Nr_len; unsignedchar CKYi[8]; int CKYi_len; unsignedchar CKYr[8]; int CKYr_len; unsignedint i, j;
FILE *ikereq = NULL; /* input stream from the REQUEST file */
FILE *ikeresp; /* output stream to the RESPONSE file */
crv = NSC_CloseSession(session); continue;
}
}
loser:
NSC_Finalize(NULL); if (gxy)
free(gxy); if (Ni)
free(Ni); if (Nr)
free(Nr); if (ikereq)
fclose(ikereq);
}
void
ikev1_psk(char *reqfn)
{ char buf[4096]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "g^xy = <2048 hex digits>\n".
*/ unsignedchar *gxy = NULL; int gxy_len; unsignedchar *Ni = NULL; int Ni_len; unsignedchar *Nr = NULL; int Nr_len; unsignedchar CKYi[8]; int CKYi_len; unsignedchar CKYr[8]; int CKYr_len; unsignedchar *psk = NULL; int psk_len; unsignedint i, j;
FILE *ikereq = NULL; /* input stream from the REQUEST file */
FILE *ikeresp; /* output stream to the RESPONSE file */
crv = NSC_CloseSession(session); continue;
}
}
loser:
NSC_Finalize(NULL); if (psk)
free(psk); if (gxy)
free(gxy); if (Ni)
free(Ni); if (Nr)
free(Nr); if (ikereq)
fclose(ikereq);
}
void
ikev2(char *reqfn)
{ char buf[4096]; /* holds one line from the input REQUEST file. * needs to be large enough to hold the longest * line "g^xy = <2048 hex digits>\n".
*/ unsignedchar *gir = NULL; unsignedchar *gir_new = NULL; int gir_len; unsignedchar *Ni = NULL; int Ni_len; unsignedchar *Nr = NULL; int Nr_len; unsignedchar *SPIi = NULL; int SPIi_len = 8; unsignedchar *SPIr = NULL; int SPIr_len = 8; unsignedchar *DKM = NULL; int DKM_len; unsignedchar *DKM_child = NULL; int DKM_child_len; unsignedchar *seed_data = NULL; int seed_data_len = 0; unsignedint i, j;
FILE *ikereq = NULL; /* input stream from the REQUEST file */
FILE *ikeresp; /* output stream to the RESPONSE file */
crv = NSC_CloseSession(session); continue;
}
}
loser:
NSC_Finalize(NULL); if (gir)
free(gir); if (gir_new)
free(gir_new); if (seed_data)
free(seed_data); if (DKM)
free(DKM); if (DKM_child)
free(DKM_child); if (ikereq)
fclose(ikereq);
}
void
kbkdf(char *path)
{ /* == Parser data == */ char buf[610]; /* holds one line from the input REQUEST file. Needs to * be large enough to hold the longest line:
* "KO = <600 hex digits>\n". */
CK_ULONG L; unsignedchar KI[64]; unsignedint KI_len = 64; unsignedchar KO[300]; unsignedint KO_len = 300; /* This is used only with feedback mode. */ unsignedchar IV[64]; unsignedint IV_len = 64; /* These are only used in counter mode with counter location as
* MIDDLE_FIXED. */ unsignedchar BeforeFixedInputData[50]; unsignedint BeforeFixedInputData_len = 50; unsignedchar AfterFixedInputData[10]; unsignedint AfterFixedInputData_len = 10; /* These are used with every KDF type. */ unsignedchar FixedInputData[60]; unsignedint FixedInputData_len = 60;
/* Counter locations: * * 0: not used * 1: beginning * 2: middle
* 3: end */ int ctr_location = 0;
CK_ULONG counter_bitlen = 0;
while (fgets(buf, sizeof buf, kbkdf_req) != NULL) { /* If we have a comment, check if it tells us the type of KDF to use.
* This differs per-file, so we have to parse it. */ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') { if (strncmp(buf, "# KDF Mode Supported: Counter Mode", 34) == 0) {
kdf.mechanism = CKM_SP800_108_COUNTER_KDF;
} if (strncmp(buf, "# KDF Mode Supported: Feedback Mode", 35) == 0) {
kdf.mechanism = CKM_SP800_108_FEEDBACK_KDF;
} if (strncmp(buf, "# KDF Mode Supported: DblPipeline Mode", 38) == 0) {
kdf.mechanism = CKM_SP800_108_DOUBLE_PIPELINE_KDF;
}
/* Then comes counter, if present. */ if (strncmp(buf, "[CTRLOCATION=BEFORE_FIXED]", 26) == 0 ||
strncmp(buf, "[CTRLOCATION=BEFORE_ITER]", 24) == 0) {
ctr_location = 1;
} if (strncmp(buf, "[CTRLOCATION=MIDDLE_FIXED]", 26) == 0 ||
strncmp(buf, "[CTRLOCATION=AFTER_ITER]", 24) == 0) {
ctr_location = 2;
} if (strncmp(buf, "[CTRLOCATION=AFTER_FIXED]", 25) == 0) {
ctr_location = 3;
}
/* If counter is present, then we need to know its size. */ if (strncmp(buf, "[RLEN=", 6) == 0) { if (sscanf(buf, "[RLEN=%lu_BITS]", &counter_bitlen) != 1) { goto done;
}
}
fputs(buf, kbkdf_resp); continue;
}
/* Each test contains a counter, an output length L, an input key KI, * maybe an initialization vector IV, one of a couple of fixed data
* buffers, and finally the output key KO. */
/* First comes COUNT. */ if (strncmp(buf, "COUNT=", 6) == 0) { /* Clear all out data fields on each test. */
memset(KI, 0, sizeof KI);
memset(KO, 0, sizeof KO);
memset(IV, 0, sizeof IV);
memset(BeforeFixedInputData, 0, sizeof BeforeFixedInputData);
memset(AfterFixedInputData, 0, sizeof AfterFixedInputData);
memset(FixedInputData, 0, sizeof FixedInputData);
/* Then reset lengths except KI: it was determined by PRF
* selection above. */
KO_len = 0;
IV_len = 0;
BeforeFixedInputData_len = 0;
AfterFixedInputData_len = 0;
FixedInputData_len = 0;
fputs(buf, kbkdf_resp); continue;
}
/* Then comes L. */ if (strncmp(buf, "L = ", 4) == 0) { if (sscanf(buf, "L = %lu", &L) != 1) { goto done;
}
if ((L % 8) != 0) {
fprintf(stderr, "Assumption that L was length in bits incorrect: %lu - %s", L, buf);
fprintf(stderr, "Note that NSS only supports byte-aligned outputs and not bit-aligned outputs.\n"); goto done;
}
L = L / 8;
fputs(buf, kbkdf_resp); continue;
}
/* Then comes KI. */ if (strncmp(buf, "KI = ", 5) == 0) {
buf_offset = 5;
for (offset = 0; offset < KI_len; offset++, buf_offset += 2) {
hex_to_byteval(buf + buf_offset, KI + offset);
}
fputs(buf, kbkdf_resp); continue;
}
/* Then comes IVlen and IV, if present. */ if (strncmp(buf, "IVlen = ", 8) == 0) { if (sscanf(buf, "IVlen = %u", &IV_len) != 1) { goto done;
}
if ((IV_len % 8) != 0) {
fprintf(stderr, "Assumption that IV_len was length in bits incorrect: %u - %s. ", IV_len, buf);
fprintf(stderr, "Note that NSS only supports byte-aligned inputs and not bit-aligned inputs.\n"); goto done;
}
/* Need the IV length in bytes, not bits. */
IV_len = IV_len / 8;
/* Finally, run the KBKDF calculation when KO is passed. */ if (strncmp(buf, "KO = ", 5) == 0) {
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE prf_key;
CK_OBJECT_HANDLE derived_key;
/* Open the session. */
crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session); if (crv != CKR_OK) {
fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n", (unsignedint)crv); goto done;
}
/* Set up the KDF parameters. */ if (kdf.mechanism == CKM_SP800_108_COUNTER_KDF) { /* Counter operates in one of three ways: counter before fixed * input data, counter between fixed input data, and counter * after fixed input data. In all cases, we have an iterator.
*/
iterator.ulWidthInBits = counter_bitlen;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.336Bemerkung:
(vorverarbeitet am 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.