8939 lines
301 KiB
C
8939 lines
301 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#include "secitem.h"
|
|
#include "blapi.h"
|
|
#include "nssutil.h"
|
|
#include "secerr.h"
|
|
#include "secder.h"
|
|
#include "secdig.h"
|
|
#include "secoid.h"
|
|
#include "ec.h"
|
|
#include "hasht.h"
|
|
#include "lowkeyi.h"
|
|
#include "softoken.h"
|
|
#include "pkcs11t.h"
|
|
#define __PASTE(x, y) x##y
|
|
#undef CK_PKCS11_FUNCTION_INFO
|
|
#undef CK_NEED_ARG_LIST
|
|
#define CK_EXTERN extern
|
|
#define CK_PKCS11_FUNCTION_INFO(func) \
|
|
CK_RV __PASTE(NS, func)
|
|
#define CK_NEED_ARG_LIST 1
|
|
#include "pkcs11f.h"
|
|
#undef CK_PKCS11_FUNCTION_INFO
|
|
#undef CK_NEED_ARG_LIST
|
|
#undef __PASTE
|
|
#define SSL3_RANDOM_LENGTH 32
|
|
|
|
#if 0
|
|
#include "../../lib/freebl/mpi/mpi.h"
|
|
#endif
|
|
#define MATCH_OPENSSL 1
|
|
/*#define MATCH_NIST 1 */
|
|
#ifdef MATCH_NIST
|
|
#define VERBOSE_REASON 1
|
|
#endif
|
|
|
|
extern SECStatus
|
|
EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams);
|
|
extern SECStatus
|
|
EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
|
|
const ECParams *srcParams);
|
|
|
|
#define ENCRYPT 1
|
|
#define DECRYPT 0
|
|
#define BYTE unsigned char
|
|
#define DEFAULT_RSA_PUBLIC_EXPONENT 0x10001
|
|
#define RSA_MAX_TEST_MODULUS_BITS 4096
|
|
#define RSA_MAX_TEST_MODULUS_BYTES RSA_MAX_TEST_MODULUS_BITS / 8
|
|
#define RSA_MAX_TEST_EXPONENT_BYTES 8
|
|
#define PQG_TEST_SEED_BYTES 20
|
|
|
|
SECStatus
|
|
hex_to_byteval(const char *c2, unsigned char *byteval)
|
|
{
|
|
int i;
|
|
unsigned char offset;
|
|
*byteval = 0;
|
|
for (i = 0; i < 2; i++) {
|
|
if (c2[i] >= '0' && c2[i] <= '9') {
|
|
offset = c2[i] - '0';
|
|
*byteval |= offset << 4 * (1 - i);
|
|
} else if (c2[i] >= 'a' && c2[i] <= 'f') {
|
|
offset = c2[i] - 'a';
|
|
*byteval |= (offset + 10) << 4 * (1 - i);
|
|
} else if (c2[i] >= 'A' && c2[i] <= 'F') {
|
|
offset = c2[i] - 'A';
|
|
*byteval |= (offset + 10) << 4 * (1 - i);
|
|
} else {
|
|
return SECFailure;
|
|
}
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
byteval_to_hex(unsigned char byteval, char *c2, char a)
|
|
{
|
|
int i;
|
|
unsigned char offset;
|
|
for (i = 0; i < 2; i++) {
|
|
offset = (byteval >> 4 * (1 - i)) & 0x0f;
|
|
if (offset < 10) {
|
|
c2[i] = '0' + offset;
|
|
} else {
|
|
c2[i] = a + offset - 10;
|
|
}
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
void
|
|
to_hex_str(char *str, const unsigned char *buf, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++) {
|
|
byteval_to_hex(buf[i], &str[2 * i], 'a');
|
|
}
|
|
str[2 * len] = '\0';
|
|
}
|
|
|
|
void
|
|
to_hex_str_cap(char *str, const unsigned char *buf, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++) {
|
|
byteval_to_hex(buf[i], &str[2 * i], 'A');
|
|
}
|
|
str[2 * len] = '\0';
|
|
}
|
|
|
|
/*
|
|
* Convert a string of hex digits (str) to an array (buf) of len bytes.
|
|
* Return PR_TRUE if the hex string can fit in the byte array. Return
|
|
* PR_FALSE if the hex string is empty or is too long.
|
|
*/
|
|
PRBool
|
|
from_hex_str(unsigned char *buf, unsigned int len, const char *str)
|
|
{
|
|
unsigned int nxdigit; /* number of hex digits in str */
|
|
unsigned int i; /* index into buf */
|
|
unsigned int j; /* index into str */
|
|
|
|
/* count the hex digits */
|
|
nxdigit = 0;
|
|
for (nxdigit = 0; isxdigit(str[nxdigit]); nxdigit++) {
|
|
/* empty body */
|
|
}
|
|
if (nxdigit == 0) {
|
|
return PR_FALSE;
|
|
}
|
|
if (nxdigit > 2 * len) {
|
|
/*
|
|
* The input hex string is too long, but we allow it if the
|
|
* extra digits are leading 0's.
|
|
*/
|
|
for (j = 0; j < nxdigit - 2 * len; j++) {
|
|
if (str[j] != '0') {
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
/* skip leading 0's */
|
|
str += nxdigit - 2 * len;
|
|
nxdigit = 2 * len;
|
|
}
|
|
for (i = 0, j = 0; i < len; i++) {
|
|
if (2 * i < 2 * len - nxdigit) {
|
|
/* Handle a short input as if we padded it with leading 0's. */
|
|
if (2 * i + 1 < 2 * len - nxdigit) {
|
|
buf[i] = 0;
|
|
} else {
|
|
char tmp[2];
|
|
tmp[0] = '0';
|
|
tmp[1] = str[j];
|
|
hex_to_byteval(tmp, &buf[i]);
|
|
j++;
|
|
}
|
|
} else {
|
|
hex_to_byteval(&str[j], &buf[i]);
|
|
j += 2;
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
SECStatus
|
|
tdea_encrypt_buf(
|
|
int mode,
|
|
const unsigned char *key,
|
|
const unsigned char *iv,
|
|
unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
|
|
const unsigned char *input, unsigned int inputlen)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
DESContext *cx;
|
|
unsigned char doublecheck[8 * 20]; /* 1 to 20 blocks */
|
|
unsigned int doublechecklen = 0;
|
|
|
|
cx = DES_CreateContext(key, iv, mode, PR_TRUE);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = DES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (*outputlen != inputlen) {
|
|
goto loser;
|
|
}
|
|
DES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
|
|
/*
|
|
* Doublecheck our result by decrypting the ciphertext and
|
|
* compare the output with the input plaintext.
|
|
*/
|
|
cx = DES_CreateContext(key, iv, mode, PR_FALSE);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = DES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
|
|
output, *outputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (doublechecklen != *outputlen) {
|
|
goto loser;
|
|
}
|
|
DES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
if (memcmp(doublecheck, input, inputlen) != 0) {
|
|
goto loser;
|
|
}
|
|
rv = SECSuccess;
|
|
|
|
loser:
|
|
if (cx != NULL) {
|
|
DES_DestroyContext(cx, PR_TRUE);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SECStatus
|
|
tdea_decrypt_buf(
|
|
int mode,
|
|
const unsigned char *key,
|
|
const unsigned char *iv,
|
|
unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
|
|
const unsigned char *input, unsigned int inputlen)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
DESContext *cx;
|
|
unsigned char doublecheck[8 * 20]; /* 1 to 20 blocks */
|
|
unsigned int doublechecklen = 0;
|
|
|
|
cx = DES_CreateContext(key, iv, mode, PR_FALSE);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = DES_Decrypt(cx, output, outputlen, maxoutputlen,
|
|
input, inputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (*outputlen != inputlen) {
|
|
goto loser;
|
|
}
|
|
DES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
|
|
/*
|
|
* Doublecheck our result by encrypting the plaintext and
|
|
* compare the output with the input ciphertext.
|
|
*/
|
|
cx = DES_CreateContext(key, iv, mode, PR_TRUE);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = DES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
|
|
output, *outputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (doublechecklen != *outputlen) {
|
|
goto loser;
|
|
}
|
|
DES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
if (memcmp(doublecheck, input, inputlen) != 0) {
|
|
goto loser;
|
|
}
|
|
rv = SECSuccess;
|
|
|
|
loser:
|
|
if (cx != NULL) {
|
|
DES_DestroyContext(cx, PR_TRUE);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Perform the TDEA Known Answer Test (KAT) or Multi-block Message
|
|
* Test (MMT) in ECB or CBC mode. The KAT (there are five types)
|
|
* and MMT have the same structure: given the key and IV (CBC mode
|
|
* only), encrypt the given plaintext or decrypt the given ciphertext.
|
|
* So we can handle them the same way.
|
|
*
|
|
* reqfn is the pathname of the REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
tdea_kat_mmt(char *reqfn)
|
|
{
|
|
char buf[180]; /* holds one line from the input REQUEST file.
|
|
* needs to be large enough to hold the longest
|
|
* line "CIPHERTEXT = <180 hex digits>\n".
|
|
*/
|
|
FILE *req; /* input stream from the REQUEST file */
|
|
FILE *resp; /* output stream to the RESPONSE file */
|
|
int i, j;
|
|
int mode = NSS_DES_EDE3; /* NSS_DES_EDE3 (ECB) or NSS_DES_EDE3_CBC */
|
|
int crypt = DECRYPT; /* 1 means encrypt, 0 means decrypt */
|
|
unsigned char key[24]; /* TDEA 3 key bundle */
|
|
unsigned int numKeys = 0;
|
|
unsigned char iv[8]; /* for all modes except ECB */
|
|
unsigned char plaintext[8 * 20]; /* 1 to 20 blocks */
|
|
unsigned int plaintextlen;
|
|
unsigned char ciphertext[8 * 20]; /* 1 to 20 blocks */
|
|
unsigned int ciphertextlen;
|
|
SECStatus rv;
|
|
|
|
req = fopen(reqfn, "r");
|
|
resp = stdout;
|
|
while (fgets(buf, sizeof buf, req) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* [ENCRYPT] or [DECRYPT] */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
|
|
crypt = ENCRYPT;
|
|
} else {
|
|
crypt = DECRYPT;
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* NumKeys */
|
|
if (strncmp(&buf[0], "NumKeys", 7) == 0) {
|
|
i = 7;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
numKeys = buf[i];
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* "COUNT = x" begins a new data set */
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
/* mode defaults to ECB, if dataset has IV mode will be set CBC */
|
|
mode = NSS_DES_EDE3;
|
|
/* zeroize the variables for the test with this data set */
|
|
memset(key, 0, sizeof key);
|
|
memset(iv, 0, sizeof iv);
|
|
memset(plaintext, 0, sizeof plaintext);
|
|
plaintextlen = 0;
|
|
memset(ciphertext, 0, sizeof ciphertext);
|
|
ciphertextlen = 0;
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
if (numKeys == 0) {
|
|
if (strncmp(buf, "KEYs", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
key[j + 8] = key[j];
|
|
key[j + 16] = key[j];
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
} else {
|
|
/* KEY1 = ... */
|
|
if (strncmp(buf, "KEY1", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* KEY2 = ... */
|
|
if (strncmp(buf, "KEY2", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 8; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* KEY3 = ... */
|
|
if (strncmp(buf, "KEY3", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 16; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* IV = ... */
|
|
if (strncmp(buf, "IV", 2) == 0) {
|
|
mode = NSS_DES_EDE3_CBC;
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < sizeof iv; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &iv[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
|
|
/* PLAINTEXT = ... */
|
|
if (strncmp(buf, "PLAINTEXT", 9) == 0) {
|
|
/* sanity check */
|
|
if (crypt != ENCRYPT) {
|
|
goto loser;
|
|
}
|
|
i = 9;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &plaintext[j]);
|
|
}
|
|
plaintextlen = j;
|
|
rv = tdea_encrypt_buf(mode, key,
|
|
(mode == NSS_DES_EDE3) ? NULL : iv,
|
|
ciphertext, &ciphertextlen, sizeof ciphertext,
|
|
plaintext, plaintextlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
fputs(buf, resp);
|
|
fputs("CIPHERTEXT = ", resp);
|
|
to_hex_str(buf, ciphertext, ciphertextlen);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
continue;
|
|
}
|
|
/* CIPHERTEXT = ... */
|
|
if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
|
|
/* sanity check */
|
|
if (crypt != DECRYPT) {
|
|
goto loser;
|
|
}
|
|
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &ciphertext[j]);
|
|
}
|
|
ciphertextlen = j;
|
|
|
|
rv = tdea_decrypt_buf(mode, key,
|
|
(mode == NSS_DES_EDE3) ? NULL : iv,
|
|
plaintext, &plaintextlen, sizeof plaintext,
|
|
ciphertext, ciphertextlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
fputs(buf, resp);
|
|
fputs("PLAINTEXT = ", resp);
|
|
to_hex_str(buf, plaintext, plaintextlen);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
loser:
|
|
fclose(req);
|
|
}
|
|
|
|
/*
|
|
* Set the parity bit for the given byte
|
|
*/
|
|
BYTE
|
|
odd_parity(BYTE in)
|
|
{
|
|
BYTE out = in;
|
|
in ^= in >> 4;
|
|
in ^= in >> 2;
|
|
in ^= in >> 1;
|
|
return (BYTE)(out ^ !(in & 1));
|
|
}
|
|
|
|
/*
|
|
* Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j]
|
|
* for TDEA Monte Carlo Test (MCT) in ECB and CBC modes.
|
|
*/
|
|
void
|
|
tdea_mct_next_keys(unsigned char *key,
|
|
const unsigned char *text_2, const unsigned char *text_1,
|
|
const unsigned char *text, unsigned int numKeys)
|
|
{
|
|
int k;
|
|
|
|
/* key1[i+1] = key1[i] xor PT/CT[j] */
|
|
for (k = 0; k < 8; k++) {
|
|
key[k] ^= text[k];
|
|
}
|
|
/* key2 */
|
|
if (numKeys == 2 || numKeys == 3) {
|
|
/* key2 independent */
|
|
for (k = 8; k < 16; k++) {
|
|
/* key2[i+1] = KEY2[i] xor PT/CT[j-1] */
|
|
key[k] ^= text_1[k - 8];
|
|
}
|
|
} else {
|
|
/* key2 == key 1 */
|
|
for (k = 8; k < 16; k++) {
|
|
/* key2[i+1] = KEY2[i] xor PT/CT[j] */
|
|
key[k] = key[k - 8];
|
|
}
|
|
}
|
|
/* key3 */
|
|
if (numKeys == 1 || numKeys == 2) {
|
|
/* key3 == key 1 */
|
|
for (k = 16; k < 24; k++) {
|
|
/* key3[i+1] = KEY3[i] xor PT/CT[j] */
|
|
key[k] = key[k - 16];
|
|
}
|
|
} else {
|
|
/* key3 independent */
|
|
for (k = 16; k < 24; k++) {
|
|
/* key3[i+1] = KEY3[i] xor PT/CT[j-2] */
|
|
key[k] ^= text_2[k - 16];
|
|
}
|
|
}
|
|
/* set the parity bits */
|
|
for (k = 0; k < 24; k++) {
|
|
key[k] = odd_parity(key[k]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Perform the Monte Carlo Test
|
|
*
|
|
* mode = NSS_DES_EDE3 or NSS_DES_EDE3_CBC
|
|
* crypt = ENCRYPT || DECRYPT
|
|
* inputtext = plaintext or Cyphertext depending on the value of crypt
|
|
* inputlength is expected to be size 8 bytes
|
|
* iv = needs to be set for NSS_DES_EDE3_CBC mode
|
|
* resp = is the output response file.
|
|
*/
|
|
void
|
|
tdea_mct_test(int mode, unsigned char *key, unsigned int numKeys,
|
|
unsigned int crypt, unsigned char *inputtext,
|
|
unsigned int inputlength, unsigned char *iv, FILE *resp)
|
|
{
|
|
|
|
int i, j;
|
|
unsigned char outputtext_1[8]; /* PT/CT[j-1] */
|
|
unsigned char outputtext_2[8]; /* PT/CT[j-2] */
|
|
char buf[80]; /* holds one line from the input REQUEST file. */
|
|
unsigned int outputlen;
|
|
unsigned char outputtext[8];
|
|
|
|
SECStatus rv;
|
|
|
|
if (mode == NSS_DES_EDE3 && iv != NULL) {
|
|
printf("IV must be NULL for NSS_DES_EDE3 mode");
|
|
goto loser;
|
|
} else if (mode == NSS_DES_EDE3_CBC && iv == NULL) {
|
|
printf("IV must not be NULL for NSS_DES_EDE3_CBC mode");
|
|
goto loser;
|
|
}
|
|
|
|
/* loop 400 times */
|
|
for (i = 0; i < 400; i++) {
|
|
/* if i == 0 CV[0] = IV not necessary */
|
|
/* record the count and key values and plainText */
|
|
sprintf(buf, "COUNT = %d\n", i);
|
|
fputs(buf, resp);
|
|
/* Output KEY1[i] */
|
|
fputs("KEY1 = ", resp);
|
|
to_hex_str(buf, key, 8);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
/* Output KEY2[i] */
|
|
fputs("KEY2 = ", resp);
|
|
to_hex_str(buf, &key[8], 8);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
/* Output KEY3[i] */
|
|
fputs("KEY3 = ", resp);
|
|
to_hex_str(buf, &key[16], 8);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
if (mode == NSS_DES_EDE3_CBC) {
|
|
/* Output CV[i] */
|
|
fputs("IV = ", resp);
|
|
to_hex_str(buf, iv, 8);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
}
|
|
if (crypt == ENCRYPT) {
|
|
/* Output PT[0] */
|
|
fputs("PLAINTEXT = ", resp);
|
|
} else {
|
|
/* Output CT[0] */
|
|
fputs("CIPHERTEXT = ", resp);
|
|
}
|
|
|
|
to_hex_str(buf, inputtext, inputlength);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
|
|
/* loop 10,000 times */
|
|
for (j = 0; j < 10000; j++) {
|
|
|
|
outputlen = 0;
|
|
if (crypt == ENCRYPT) {
|
|
/* inputtext == ciphertext outputtext == plaintext*/
|
|
rv = tdea_encrypt_buf(mode, key,
|
|
(mode ==
|
|
NSS_DES_EDE3)
|
|
? NULL
|
|
: iv,
|
|
outputtext, &outputlen, 8,
|
|
inputtext, 8);
|
|
} else {
|
|
/* inputtext == plaintext outputtext == ciphertext */
|
|
rv = tdea_decrypt_buf(mode, key,
|
|
(mode ==
|
|
NSS_DES_EDE3)
|
|
? NULL
|
|
: iv,
|
|
outputtext, &outputlen, 8,
|
|
inputtext, 8);
|
|
}
|
|
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != inputlength) {
|
|
goto loser;
|
|
}
|
|
|
|
if (mode == NSS_DES_EDE3_CBC) {
|
|
if (crypt == ENCRYPT) {
|
|
if (j == 0) {
|
|
/*P[j+1] = CV[0] */
|
|
memcpy(inputtext, iv, 8);
|
|
} else {
|
|
/* p[j+1] = C[j-1] */
|
|
memcpy(inputtext, outputtext_1, 8);
|
|
}
|
|
/* CV[j+1] = C[j] */
|
|
memcpy(iv, outputtext, 8);
|
|
if (j != 9999) {
|
|
/* save C[j-1] */
|
|
memcpy(outputtext_1, outputtext, 8);
|
|
}
|
|
} else { /* DECRYPT */
|
|
/* CV[j+1] = C[j] */
|
|
memcpy(iv, inputtext, 8);
|
|
/* C[j+1] = P[j] */
|
|
memcpy(inputtext, outputtext, 8);
|
|
}
|
|
} else {
|
|
/* ECB mode PT/CT[j+1] = CT/PT[j] */
|
|
memcpy(inputtext, outputtext, 8);
|
|
}
|
|
|
|
/* Save PT/CT[j-2] and PT/CT[j-1] */
|
|
if (j == 9997)
|
|
memcpy(outputtext_2, outputtext, 8);
|
|
if (j == 9998)
|
|
memcpy(outputtext_1, outputtext, 8);
|
|
/* done at the end of the for(j) loop */
|
|
}
|
|
|
|
if (crypt == ENCRYPT) {
|
|
/* Output CT[j] */
|
|
fputs("CIPHERTEXT = ", resp);
|
|
} else {
|
|
/* Output PT[j] */
|
|
fputs("PLAINTEXT = ", resp);
|
|
}
|
|
to_hex_str(buf, outputtext, 8);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
|
|
/* Key[i+1] = Key[i] xor ... outputtext_2 == PT/CT[j-2]
|
|
* outputtext_1 == PT/CT[j-1] outputtext == PT/CT[j]
|
|
*/
|
|
tdea_mct_next_keys(key, outputtext_2,
|
|
outputtext_1, outputtext, numKeys);
|
|
|
|
if (mode == NSS_DES_EDE3_CBC) {
|
|
/* taken care of in the j=9999 iteration */
|
|
if (crypt == ENCRYPT) {
|
|
/* P[i] = C[j-1] */
|
|
/* CV[i] = C[j] */
|
|
} else {
|
|
/* taken care of in the j=9999 iteration */
|
|
/* CV[i] = C[j] */
|
|
/* C[i] = P[j] */
|
|
}
|
|
} else {
|
|
/* ECB PT/CT[i] = PT/CT[j] */
|
|
memcpy(inputtext, outputtext, 8);
|
|
}
|
|
/* done at the end of the for(i) loop */
|
|
fputc('\n', resp);
|
|
}
|
|
|
|
loser:
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Perform the TDEA Monte Carlo Test (MCT) in ECB/CBC modes.
|
|
* by gathering the input from the request file, and then
|
|
* calling tdea_mct_test.
|
|
*
|
|
* reqfn is the pathname of the input REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
tdea_mct(int mode, char *reqfn)
|
|
{
|
|
int i, j;
|
|
char buf[80]; /* holds one line from the input REQUEST file. */
|
|
FILE *req; /* input stream from the REQUEST file */
|
|
FILE *resp; /* output stream to the RESPONSE file */
|
|
unsigned int crypt = 0; /* 1 means encrypt, 0 means decrypt */
|
|
unsigned char key[24]; /* TDEA 3 key bundle */
|
|
unsigned int numKeys = 0;
|
|
unsigned char plaintext[8]; /* PT[j] */
|
|
unsigned char ciphertext[8]; /* CT[j] */
|
|
unsigned char iv[8];
|
|
|
|
/* zeroize the variables for the test with this data set */
|
|
memset(key, 0, sizeof key);
|
|
memset(plaintext, 0, sizeof plaintext);
|
|
memset(ciphertext, 0, sizeof ciphertext);
|
|
memset(iv, 0, sizeof iv);
|
|
|
|
req = fopen(reqfn, "r");
|
|
resp = stdout;
|
|
while (fgets(buf, sizeof buf, req) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* [ENCRYPT] or [DECRYPT] */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(&buf[1], "ENCRYPT", 7) == 0) {
|
|
crypt = ENCRYPT;
|
|
} else {
|
|
crypt = DECRYPT;
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* NumKeys */
|
|
if (strncmp(&buf[0], "NumKeys", 7) == 0) {
|
|
i = 7;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
numKeys = atoi(&buf[i]);
|
|
continue;
|
|
}
|
|
/* KEY1 = ... */
|
|
if (strncmp(buf, "KEY1", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
continue;
|
|
}
|
|
/* KEY2 = ... */
|
|
if (strncmp(buf, "KEY2", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 8; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
continue;
|
|
}
|
|
/* KEY3 = ... */
|
|
if (strncmp(buf, "KEY3", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 16; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* IV = ... */
|
|
if (strncmp(buf, "IV", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < sizeof iv; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &iv[j]);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* PLAINTEXT = ... */
|
|
if (strncmp(buf, "PLAINTEXT", 9) == 0) {
|
|
|
|
/* sanity check */
|
|
if (crypt != ENCRYPT) {
|
|
goto loser;
|
|
}
|
|
/* PT[0] = PT */
|
|
i = 9;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < sizeof plaintext; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &plaintext[j]);
|
|
}
|
|
|
|
/* do the Monte Carlo test */
|
|
if (mode == NSS_DES_EDE3) {
|
|
tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, plaintext, sizeof plaintext, NULL, resp);
|
|
} else {
|
|
tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, plaintext, sizeof plaintext, iv, resp);
|
|
}
|
|
continue;
|
|
}
|
|
/* CIPHERTEXT = ... */
|
|
if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
|
|
/* sanity check */
|
|
if (crypt != DECRYPT) {
|
|
goto loser;
|
|
}
|
|
/* CT[0] = CT */
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &ciphertext[j]);
|
|
}
|
|
|
|
/* do the Monte Carlo test */
|
|
if (mode == NSS_DES_EDE3) {
|
|
tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, ciphertext, sizeof ciphertext, NULL, resp);
|
|
} else {
|
|
tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, ciphertext, sizeof ciphertext, iv, resp);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
loser:
|
|
fclose(req);
|
|
}
|
|
|
|
SECStatus
|
|
aes_encrypt_buf(
|
|
int mode,
|
|
const unsigned char *key, unsigned int keysize,
|
|
const unsigned char *iv,
|
|
unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
|
|
const unsigned char *input, unsigned int inputlen)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
AESContext *cx;
|
|
unsigned char doublecheck[10 * 16]; /* 1 to 10 blocks */
|
|
unsigned int doublechecklen = 0;
|
|
|
|
cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = AES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (*outputlen != inputlen) {
|
|
goto loser;
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
|
|
/*
|
|
* Doublecheck our result by decrypting the ciphertext and
|
|
* compare the output with the input plaintext.
|
|
*/
|
|
cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = AES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
|
|
output, *outputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (doublechecklen != *outputlen) {
|
|
goto loser;
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
if (memcmp(doublecheck, input, inputlen) != 0) {
|
|
goto loser;
|
|
}
|
|
rv = SECSuccess;
|
|
|
|
loser:
|
|
if (cx != NULL) {
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SECStatus
|
|
aes_decrypt_buf(
|
|
int mode,
|
|
const unsigned char *key, unsigned int keysize,
|
|
const unsigned char *iv,
|
|
unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen,
|
|
const unsigned char *input, unsigned int inputlen)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
AESContext *cx;
|
|
unsigned char doublecheck[10 * 16]; /* 1 to 10 blocks */
|
|
unsigned int doublechecklen = 0;
|
|
|
|
cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = AES_Decrypt(cx, output, outputlen, maxoutputlen,
|
|
input, inputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (*outputlen != inputlen) {
|
|
goto loser;
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
|
|
/*
|
|
* Doublecheck our result by encrypting the plaintext and
|
|
* compare the output with the input ciphertext.
|
|
*/
|
|
cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
rv = AES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck,
|
|
output, *outputlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (doublechecklen != *outputlen) {
|
|
goto loser;
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
if (memcmp(doublecheck, input, inputlen) != 0) {
|
|
goto loser;
|
|
}
|
|
rv = SECSuccess;
|
|
|
|
loser:
|
|
if (cx != NULL) {
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
}
|
|
return rv;
|
|
}
|
|
/*
|
|
* Perform the AES 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;
|
|
unsigned char key[32]; /* 128, 192, or 256 bits */
|
|
unsigned int keysize = 0;
|
|
unsigned char iv[128]; /* handle large gcm IV's */
|
|
unsigned char plaintext[10 * 16]; /* 1 to 10 blocks */
|
|
unsigned int plaintextlen;
|
|
unsigned char ciphertext[11 * 16]; /* 1 to 10 blocks + tag */
|
|
unsigned int ciphertextlen;
|
|
unsigned char aad[11 * 16]; /* 1 to 10 blocks + tag */
|
|
unsigned int aadlen = 0;
|
|
unsigned int tagbits;
|
|
unsigned int taglen = 0;
|
|
unsigned int 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(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) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < sizeof iv; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &iv[j]);
|
|
}
|
|
fputs(buf, aesresp);
|
|
continue;
|
|
}
|
|
/* PLAINTEXT = ... */
|
|
if (strncmp(buf, "PT", 2) == 0) {
|
|
/* sanity check */
|
|
if (!encrypt) {
|
|
goto loser;
|
|
}
|
|
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &plaintext[j]);
|
|
}
|
|
plaintextlen = j;
|
|
fputs(buf, aesresp);
|
|
continue;
|
|
}
|
|
/* CIPHERTEXT = ... */
|
|
if (strncmp(buf, "CT", 2) == 0) {
|
|
/* sanity check */
|
|
if (encrypt) {
|
|
goto loser;
|
|
}
|
|
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &ciphertext[j]);
|
|
}
|
|
ciphertextlen = j;
|
|
fputs(buf, aesresp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "AAD", 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], &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,
|
|
(unsigned char *)¶ms,
|
|
ciphertext, &ciphertextlen, sizeof ciphertext,
|
|
plaintext, plaintextlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (encrypt == 2) {
|
|
fputs("IV = ", aesresp);
|
|
to_hex_str(buf, iv, ivlen);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
}
|
|
fputs("CT = ", aesresp);
|
|
j = ciphertextlen - taglen;
|
|
to_hex_str(buf, ciphertext, j);
|
|
fputs(buf, aesresp);
|
|
fputs("\nTag = ", aesresp);
|
|
to_hex_str(buf, ciphertext + j, taglen);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
}
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "Tag", 3) == 0) {
|
|
/* sanity check */
|
|
if (encrypt) {
|
|
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], &ciphertext[j + ciphertextlen]);
|
|
}
|
|
ciphertextlen += j;
|
|
params.pIv = iv;
|
|
params.ulIvLen = ivlen;
|
|
params.pAAD = aad;
|
|
params.ulAADLen = aadlen;
|
|
params.ulTagBits = tagbits;
|
|
rv = aes_decrypt_buf(NSS_AES_GCM, key, keysize,
|
|
(unsigned char *)¶ms,
|
|
plaintext, &plaintextlen, sizeof plaintext,
|
|
ciphertext, ciphertextlen);
|
|
fputs(buf, aesresp);
|
|
if (rv != SECSuccess) {
|
|
fprintf(aesresp, "FAIL\n");
|
|
} else {
|
|
fputs("PT = ", aesresp);
|
|
to_hex_str(buf, plaintext, plaintextlen);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(aesreq);
|
|
}
|
|
|
|
/*
|
|
* 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 */
|
|
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 < sizeof iv; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &iv[j]);
|
|
}
|
|
fputs(buf, aesresp);
|
|
continue;
|
|
}
|
|
/* PLAINTEXT = ... */
|
|
if (strncmp(buf, "PLAINTEXT", 9) == 0) {
|
|
/* sanity check */
|
|
if (!encrypt) {
|
|
goto loser;
|
|
}
|
|
|
|
i = 9;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &plaintext[j]);
|
|
}
|
|
plaintextlen = j;
|
|
|
|
rv = aes_encrypt_buf(mode, key, keysize,
|
|
(mode ==
|
|
NSS_AES)
|
|
? NULL
|
|
: iv,
|
|
ciphertext, &ciphertextlen, sizeof ciphertext,
|
|
plaintext, plaintextlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
fputs(buf, aesresp);
|
|
fputs("CIPHERTEXT = ", aesresp);
|
|
to_hex_str(buf, ciphertext, ciphertextlen);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
continue;
|
|
}
|
|
/* CIPHERTEXT = ... */
|
|
if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
|
|
/* sanity check */
|
|
if (encrypt) {
|
|
goto loser;
|
|
}
|
|
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &ciphertext[j]);
|
|
}
|
|
ciphertextlen = j;
|
|
|
|
rv = aes_decrypt_buf(mode, key, keysize,
|
|
(mode ==
|
|
NSS_AES)
|
|
? NULL
|
|
: iv,
|
|
plaintext, &plaintextlen, sizeof plaintext,
|
|
ciphertext, ciphertextlen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
fputs(buf, aesresp);
|
|
fputs("PLAINTEXT = ", aesresp);
|
|
to_hex_str(buf, plaintext, plaintextlen);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(aesreq);
|
|
}
|
|
|
|
/*
|
|
* Generate Key[i+1] from Key[i], CT[j-1], and CT[j] for AES Monte Carlo
|
|
* Test (MCT) in ECB and CBC modes.
|
|
*/
|
|
void
|
|
aes_mct_next_key(unsigned char *key, unsigned int keysize,
|
|
const unsigned char *ciphertext_1, const unsigned char *ciphertext)
|
|
{
|
|
int k;
|
|
|
|
switch (keysize) {
|
|
case 16: /* 128-bit key */
|
|
/* Key[i+1] = Key[i] xor CT[j] */
|
|
for (k = 0; k < 16; k++) {
|
|
key[k] ^= ciphertext[k];
|
|
}
|
|
break;
|
|
case 24: /* 192-bit key */
|
|
/*
|
|
* Key[i+1] = Key[i] xor (last 64-bits of
|
|
* CT[j-1] || CT[j])
|
|
*/
|
|
for (k = 0; k < 8; k++) {
|
|
key[k] ^= ciphertext_1[k + 8];
|
|
}
|
|
for (k = 8; k < 24; k++) {
|
|
key[k] ^= ciphertext[k - 8];
|
|
}
|
|
break;
|
|
case 32: /* 256-bit key */
|
|
/* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */
|
|
for (k = 0; k < 16; k++) {
|
|
key[k] ^= ciphertext_1[k];
|
|
}
|
|
for (k = 16; k < 32; k++) {
|
|
key[k] ^= ciphertext[k - 16];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Perform the AES Monte Carlo Test (MCT) in ECB mode. MCT exercises
|
|
* our AES code in streaming mode because the plaintext or ciphertext
|
|
* is generated block by block as we go, so we can't collect all the
|
|
* plaintext or ciphertext in one buffer and encrypt or decrypt it in
|
|
* one shot.
|
|
*
|
|
* reqfn is the pathname of the input REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
aes_ecb_mct(char *reqfn)
|
|
{
|
|
char buf[80]; /* holds one line from the input REQUEST file.
|
|
* needs to be large enough to hold the longest
|
|
* line "KEY = <64 hex digits>\n".
|
|
*/
|
|
FILE *aesreq; /* input stream from the REQUEST file */
|
|
FILE *aesresp; /* output stream to the RESPONSE file */
|
|
int i, j;
|
|
int encrypt = 0; /* 1 means encrypt, 0 means decrypt */
|
|
unsigned char key[32]; /* 128, 192, or 256 bits */
|
|
unsigned int keysize = 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 < sizeof plaintext; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &plaintext[j]);
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
sprintf(buf, "COUNT = %d\n", i);
|
|
fputs(buf, aesresp);
|
|
/* Output Key[i] */
|
|
fputs("KEY = ", aesresp);
|
|
to_hex_str(buf, key, keysize);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
/* Output PT[0] */
|
|
fputs("PLAINTEXT = ", aesresp);
|
|
to_hex_str(buf, plaintext, sizeof plaintext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
cx = AES_CreateContext(key, NULL, NSS_AES,
|
|
PR_TRUE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
/*
|
|
* doublecheck our result by decrypting the result
|
|
* and comparing the output with the plaintext.
|
|
*/
|
|
cx2 = AES_CreateContext(key, NULL, NSS_AES,
|
|
PR_FALSE, keysize, 16);
|
|
if (cx2 == NULL) {
|
|
goto loser;
|
|
}
|
|
for (j = 0; j < 1000; j++) {
|
|
/* Save CT[j-1] */
|
|
memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
|
|
|
|
/* CT[j] = AES(Key[i], PT[j]) */
|
|
outputlen = 0;
|
|
rv = AES_Encrypt(cx,
|
|
ciphertext, &outputlen, sizeof ciphertext,
|
|
plaintext, sizeof plaintext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof plaintext) {
|
|
goto loser;
|
|
}
|
|
|
|
/* doublecheck our result */
|
|
outputlen = 0;
|
|
rv = AES_Decrypt(cx2,
|
|
doublecheck, &outputlen, sizeof doublecheck,
|
|
ciphertext, sizeof ciphertext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof ciphertext) {
|
|
goto loser;
|
|
}
|
|
if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
|
|
goto loser;
|
|
}
|
|
|
|
/* PT[j+1] = CT[j] */
|
|
memcpy(plaintext, ciphertext, sizeof plaintext);
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
AES_DestroyContext(cx2, PR_TRUE);
|
|
cx2 = NULL;
|
|
|
|
/* Output CT[j] */
|
|
fputs("CIPHERTEXT = ", aesresp);
|
|
to_hex_str(buf, ciphertext, sizeof ciphertext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
/* Key[i+1] = Key[i] xor ... */
|
|
aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
|
|
/* PT[0] = CT[j] */
|
|
/* done at the end of the for(j) loop */
|
|
|
|
fputc('\n', aesresp);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
/* CIPHERTEXT = ... */
|
|
if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
|
|
/* sanity check */
|
|
if (encrypt) {
|
|
goto loser;
|
|
}
|
|
/* CT[0] = CT */
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &ciphertext[j]);
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
sprintf(buf, "COUNT = %d\n", i);
|
|
fputs(buf, aesresp);
|
|
/* Output Key[i] */
|
|
fputs("KEY = ", aesresp);
|
|
to_hex_str(buf, key, keysize);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
/* Output CT[0] */
|
|
fputs("CIPHERTEXT = ", aesresp);
|
|
to_hex_str(buf, ciphertext, sizeof ciphertext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
cx = AES_CreateContext(key, NULL, NSS_AES,
|
|
PR_FALSE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
/*
|
|
* doublecheck our result by encrypting the result
|
|
* and comparing the output with the ciphertext.
|
|
*/
|
|
cx2 = AES_CreateContext(key, NULL, NSS_AES,
|
|
PR_TRUE, keysize, 16);
|
|
if (cx2 == NULL) {
|
|
goto loser;
|
|
}
|
|
for (j = 0; j < 1000; j++) {
|
|
/* Save PT[j-1] */
|
|
memcpy(plaintext_1, plaintext, sizeof plaintext);
|
|
|
|
/* PT[j] = AES(Key[i], CT[j]) */
|
|
outputlen = 0;
|
|
rv = AES_Decrypt(cx,
|
|
plaintext, &outputlen, sizeof plaintext,
|
|
ciphertext, sizeof ciphertext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof ciphertext) {
|
|
goto loser;
|
|
}
|
|
|
|
/* doublecheck our result */
|
|
outputlen = 0;
|
|
rv = AES_Encrypt(cx2,
|
|
doublecheck, &outputlen, sizeof doublecheck,
|
|
plaintext, sizeof plaintext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof plaintext) {
|
|
goto loser;
|
|
}
|
|
if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
|
|
goto loser;
|
|
}
|
|
|
|
/* CT[j+1] = PT[j] */
|
|
memcpy(ciphertext, plaintext, sizeof ciphertext);
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
AES_DestroyContext(cx2, PR_TRUE);
|
|
cx2 = NULL;
|
|
|
|
/* Output PT[j] */
|
|
fputs("PLAINTEXT = ", aesresp);
|
|
to_hex_str(buf, plaintext, sizeof plaintext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
/* Key[i+1] = Key[i] xor ... */
|
|
aes_mct_next_key(key, keysize, plaintext_1, plaintext);
|
|
/* CT[0] = PT[j] */
|
|
/* done at the end of the for(j) loop */
|
|
|
|
fputc('\n', aesresp);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
if (cx != NULL) {
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
}
|
|
if (cx2 != NULL) {
|
|
AES_DestroyContext(cx2, PR_TRUE);
|
|
}
|
|
fclose(aesreq);
|
|
}
|
|
|
|
/*
|
|
* Perform the AES Monte Carlo Test (MCT) in CBC mode. MCT exercises
|
|
* our AES code in streaming mode because the plaintext or ciphertext
|
|
* is generated block by block as we go, so we can't collect all the
|
|
* plaintext or ciphertext in one buffer and encrypt or decrypt it in
|
|
* one shot.
|
|
*
|
|
* reqfn is the pathname of the input REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
aes_cbc_mct(char *reqfn)
|
|
{
|
|
char buf[80]; /* holds one line from the input REQUEST file.
|
|
* needs to be large enough to hold the longest
|
|
* line "KEY = <64 hex digits>\n".
|
|
*/
|
|
FILE *aesreq; /* input stream from the REQUEST file */
|
|
FILE *aesresp; /* output stream to the RESPONSE file */
|
|
int i, j;
|
|
int encrypt = 0; /* 1 means encrypt, 0 means decrypt */
|
|
unsigned char key[32]; /* 128, 192, or 256 bits */
|
|
unsigned int keysize = 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; j < sizeof iv; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &iv[j]);
|
|
}
|
|
continue;
|
|
}
|
|
/* PLAINTEXT = ... */
|
|
if (strncmp(buf, "PLAINTEXT", 9) == 0) {
|
|
/* sanity check */
|
|
if (!encrypt) {
|
|
goto loser;
|
|
}
|
|
/* PT[0] = PT */
|
|
i = 9;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < sizeof plaintext; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &plaintext[j]);
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
sprintf(buf, "COUNT = %d\n", i);
|
|
fputs(buf, aesresp);
|
|
/* Output Key[i] */
|
|
fputs("KEY = ", aesresp);
|
|
to_hex_str(buf, key, keysize);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
/* Output IV[i] */
|
|
fputs("IV = ", aesresp);
|
|
to_hex_str(buf, iv, sizeof iv);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
/* Output PT[0] */
|
|
fputs("PLAINTEXT = ", aesresp);
|
|
to_hex_str(buf, plaintext, sizeof plaintext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
cx = AES_CreateContext(key, iv, NSS_AES_CBC,
|
|
PR_TRUE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
/*
|
|
* doublecheck our result by decrypting the result
|
|
* and comparing the output with the plaintext.
|
|
*/
|
|
cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
|
|
PR_FALSE, keysize, 16);
|
|
if (cx2 == NULL) {
|
|
goto loser;
|
|
}
|
|
/* CT[-1] = IV[i] */
|
|
memcpy(ciphertext, iv, sizeof ciphertext);
|
|
for (j = 0; j < 1000; j++) {
|
|
/* Save CT[j-1] */
|
|
memcpy(ciphertext_1, ciphertext, sizeof ciphertext);
|
|
/*
|
|
* If ( j=0 )
|
|
* CT[j] = AES(Key[i], IV[i], PT[j])
|
|
* PT[j+1] = IV[i] (= CT[j-1])
|
|
* Else
|
|
* CT[j] = AES(Key[i], PT[j])
|
|
* PT[j+1] = CT[j-1]
|
|
*/
|
|
outputlen = 0;
|
|
rv = AES_Encrypt(cx,
|
|
ciphertext, &outputlen, sizeof ciphertext,
|
|
plaintext, sizeof plaintext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof plaintext) {
|
|
goto loser;
|
|
}
|
|
|
|
/* doublecheck our result */
|
|
outputlen = 0;
|
|
rv = AES_Decrypt(cx2,
|
|
doublecheck, &outputlen, sizeof doublecheck,
|
|
ciphertext, sizeof ciphertext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof ciphertext) {
|
|
goto loser;
|
|
}
|
|
if (memcmp(doublecheck, plaintext, sizeof plaintext)) {
|
|
goto loser;
|
|
}
|
|
|
|
memcpy(plaintext, ciphertext_1, sizeof plaintext);
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
AES_DestroyContext(cx2, PR_TRUE);
|
|
cx2 = NULL;
|
|
|
|
/* Output CT[j] */
|
|
fputs("CIPHERTEXT = ", aesresp);
|
|
to_hex_str(buf, ciphertext, sizeof ciphertext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
/* Key[i+1] = Key[i] xor ... */
|
|
aes_mct_next_key(key, keysize, ciphertext_1, ciphertext);
|
|
/* IV[i+1] = CT[j] */
|
|
memcpy(iv, ciphertext, sizeof iv);
|
|
/* PT[0] = CT[j-1] */
|
|
/* done at the end of the for(j) loop */
|
|
|
|
fputc('\n', aesresp);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
/* CIPHERTEXT = ... */
|
|
if (strncmp(buf, "CIPHERTEXT", 10) == 0) {
|
|
/* sanity check */
|
|
if (encrypt) {
|
|
goto loser;
|
|
}
|
|
/* CT[0] = CT */
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &ciphertext[j]);
|
|
}
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
sprintf(buf, "COUNT = %d\n", i);
|
|
fputs(buf, aesresp);
|
|
/* Output Key[i] */
|
|
fputs("KEY = ", aesresp);
|
|
to_hex_str(buf, key, keysize);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
/* Output IV[i] */
|
|
fputs("IV = ", aesresp);
|
|
to_hex_str(buf, iv, sizeof iv);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
/* Output CT[0] */
|
|
fputs("CIPHERTEXT = ", aesresp);
|
|
to_hex_str(buf, ciphertext, sizeof ciphertext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
cx = AES_CreateContext(key, iv, NSS_AES_CBC,
|
|
PR_FALSE, keysize, 16);
|
|
if (cx == NULL) {
|
|
goto loser;
|
|
}
|
|
/*
|
|
* doublecheck our result by encrypting the result
|
|
* and comparing the output with the ciphertext.
|
|
*/
|
|
cx2 = AES_CreateContext(key, iv, NSS_AES_CBC,
|
|
PR_TRUE, keysize, 16);
|
|
if (cx2 == NULL) {
|
|
goto loser;
|
|
}
|
|
/* PT[-1] = IV[i] */
|
|
memcpy(plaintext, iv, sizeof plaintext);
|
|
for (j = 0; j < 1000; j++) {
|
|
/* Save PT[j-1] */
|
|
memcpy(plaintext_1, plaintext, sizeof plaintext);
|
|
/*
|
|
* If ( j=0 )
|
|
* PT[j] = AES(Key[i], IV[i], CT[j])
|
|
* CT[j+1] = IV[i] (= PT[j-1])
|
|
* Else
|
|
* PT[j] = AES(Key[i], CT[j])
|
|
* CT[j+1] = PT[j-1]
|
|
*/
|
|
outputlen = 0;
|
|
rv = AES_Decrypt(cx,
|
|
plaintext, &outputlen, sizeof plaintext,
|
|
ciphertext, sizeof ciphertext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof ciphertext) {
|
|
goto loser;
|
|
}
|
|
|
|
/* doublecheck our result */
|
|
outputlen = 0;
|
|
rv = AES_Encrypt(cx2,
|
|
doublecheck, &outputlen, sizeof doublecheck,
|
|
plaintext, sizeof plaintext);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
if (outputlen != sizeof plaintext) {
|
|
goto loser;
|
|
}
|
|
if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) {
|
|
goto loser;
|
|
}
|
|
|
|
memcpy(ciphertext, plaintext_1, sizeof ciphertext);
|
|
}
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
cx = NULL;
|
|
AES_DestroyContext(cx2, PR_TRUE);
|
|
cx2 = NULL;
|
|
|
|
/* Output PT[j] */
|
|
fputs("PLAINTEXT = ", aesresp);
|
|
to_hex_str(buf, plaintext, sizeof plaintext);
|
|
fputs(buf, aesresp);
|
|
fputc('\n', aesresp);
|
|
|
|
/* Key[i+1] = Key[i] xor ... */
|
|
aes_mct_next_key(key, keysize, plaintext_1, plaintext);
|
|
/* IV[i+1] = PT[j] */
|
|
memcpy(iv, plaintext, sizeof iv);
|
|
/* CT[0] = PT[j-1] */
|
|
/* done at the end of the for(j) loop */
|
|
|
|
fputc('\n', aesresp);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
if (cx != NULL) {
|
|
AES_DestroyContext(cx, PR_TRUE);
|
|
}
|
|
if (cx2 != NULL) {
|
|
AES_DestroyContext(cx2, PR_TRUE);
|
|
}
|
|
fclose(aesreq);
|
|
}
|
|
|
|
void
|
|
write_compact_string(FILE *out, unsigned char *hash, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
int j, count = 0, last = -1, z = 0;
|
|
long start = ftell(out);
|
|
for (i = 0; i < len; i++) {
|
|
for (j = 7; j >= 0; j--) {
|
|
if (last < 0) {
|
|
last = (hash[i] & (1 << j)) ? 1 : 0;
|
|
fprintf(out, "%d ", last);
|
|
count = 1;
|
|
} else if (hash[i] & (1 << j)) {
|
|
if (last) {
|
|
count++;
|
|
} else {
|
|
last = 0;
|
|
fprintf(out, "%d ", count);
|
|
count = 1;
|
|
z++;
|
|
}
|
|
} else {
|
|
if (!last) {
|
|
count++;
|
|
} else {
|
|
last = 1;
|
|
fprintf(out, "%d ", count);
|
|
count = 1;
|
|
z++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fprintf(out, "^\n");
|
|
fseek(out, start, SEEK_SET);
|
|
fprintf(out, "%d ", z);
|
|
fseek(out, 0, SEEK_END);
|
|
}
|
|
|
|
int
|
|
get_next_line(FILE *req, char *key, char *val, FILE *rsp)
|
|
{
|
|
int ignore = 0;
|
|
char *writeto = key;
|
|
int w = 0;
|
|
int c;
|
|
while ((c = fgetc(req)) != EOF) {
|
|
if (ignore) {
|
|
fprintf(rsp, "%c", c);
|
|
if (c == '\n')
|
|
return ignore;
|
|
} else if (c == '\n') {
|
|
break;
|
|
} else if (c == '#') {
|
|
ignore = 1;
|
|
fprintf(rsp, "%c", c);
|
|
} else if (c == '=') {
|
|
writeto[w] = '\0';
|
|
w = 0;
|
|
writeto = val;
|
|
} else if (c == ' ' || c == '[' || c == ']') {
|
|
continue;
|
|
} else {
|
|
writeto[w++] = c;
|
|
}
|
|
}
|
|
writeto[w] = '\0';
|
|
return (c == EOF) ? -1 : ignore;
|
|
}
|
|
|
|
typedef struct curveNameTagPairStr {
|
|
char *curveName;
|
|
SECOidTag curveOidTag;
|
|
} CurveNameTagPair;
|
|
|
|
#define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1
|
|
/* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */
|
|
|
|
static CurveNameTagPair nameTagPair[] =
|
|
{
|
|
{ "sect163k1", SEC_OID_SECG_EC_SECT163K1 },
|
|
{ "nistk163", SEC_OID_SECG_EC_SECT163K1 },
|
|
{ "sect163r1", SEC_OID_SECG_EC_SECT163R1 },
|
|
{ "sect163r2", SEC_OID_SECG_EC_SECT163R2 },
|
|
{ "nistb163", SEC_OID_SECG_EC_SECT163R2 },
|
|
{ "sect193r1", SEC_OID_SECG_EC_SECT193R1 },
|
|
{ "sect193r2", SEC_OID_SECG_EC_SECT193R2 },
|
|
{ "sect233k1", SEC_OID_SECG_EC_SECT233K1 },
|
|
{ "nistk233", SEC_OID_SECG_EC_SECT233K1 },
|
|
{ "sect233r1", SEC_OID_SECG_EC_SECT233R1 },
|
|
{ "nistb233", SEC_OID_SECG_EC_SECT233R1 },
|
|
{ "sect239k1", SEC_OID_SECG_EC_SECT239K1 },
|
|
{ "sect283k1", SEC_OID_SECG_EC_SECT283K1 },
|
|
{ "nistk283", SEC_OID_SECG_EC_SECT283K1 },
|
|
{ "sect283r1", SEC_OID_SECG_EC_SECT283R1 },
|
|
{ "nistb283", SEC_OID_SECG_EC_SECT283R1 },
|
|
{ "sect409k1", SEC_OID_SECG_EC_SECT409K1 },
|
|
{ "nistk409", SEC_OID_SECG_EC_SECT409K1 },
|
|
{ "sect409r1", SEC_OID_SECG_EC_SECT409R1 },
|
|
{ "nistb409", SEC_OID_SECG_EC_SECT409R1 },
|
|
{ "sect571k1", SEC_OID_SECG_EC_SECT571K1 },
|
|
{ "nistk571", SEC_OID_SECG_EC_SECT571K1 },
|
|
{ "sect571r1", SEC_OID_SECG_EC_SECT571R1 },
|
|
{ "nistb571", SEC_OID_SECG_EC_SECT571R1 },
|
|
{ "secp160k1", SEC_OID_SECG_EC_SECP160K1 },
|
|
{ "secp160r1", SEC_OID_SECG_EC_SECP160R1 },
|
|
{ "secp160r2", SEC_OID_SECG_EC_SECP160R2 },
|
|
{ "secp192k1", SEC_OID_SECG_EC_SECP192K1 },
|
|
{ "secp192r1", SEC_OID_SECG_EC_SECP192R1 },
|
|
{ "nistp192", SEC_OID_SECG_EC_SECP192R1 },
|
|
{ "secp224k1", SEC_OID_SECG_EC_SECP224K1 },
|
|
{ "secp224r1", SEC_OID_SECG_EC_SECP224R1 },
|
|
{ "nistp224", SEC_OID_SECG_EC_SECP224R1 },
|
|
{ "secp256k1", SEC_OID_SECG_EC_SECP256K1 },
|
|
{ "secp256r1", SEC_OID_SECG_EC_SECP256R1 },
|
|
{ "nistp256", SEC_OID_SECG_EC_SECP256R1 },
|
|
{ "secp384r1", SEC_OID_SECG_EC_SECP384R1 },
|
|
{ "nistp384", SEC_OID_SECG_EC_SECP384R1 },
|
|
{ "secp521r1", SEC_OID_SECG_EC_SECP521R1 },
|
|
{ "nistp521", SEC_OID_SECG_EC_SECP521R1 },
|
|
|
|
{ "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
|
|
{ "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
|
|
{ "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
|
|
{ "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
|
|
{ "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
|
|
{ "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
|
|
|
|
{ "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
|
|
{ "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
|
|
{ "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
|
|
{ "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
|
|
{ "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
|
|
{ "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
|
|
{ "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
|
|
{ "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
|
|
{ "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
|
|
{ "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
|
|
{ "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
|
|
{ "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
|
|
{ "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
|
|
{ "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
|
|
{ "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
|
|
{ "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
|
|
{ "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
|
|
{ "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
|
|
{ "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
|
|
{ "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
|
|
|
|
{ "secp112r1", SEC_OID_SECG_EC_SECP112R1 },
|
|
{ "secp112r2", SEC_OID_SECG_EC_SECP112R2 },
|
|
{ "secp128r1", SEC_OID_SECG_EC_SECP128R1 },
|
|
{ "secp128r2", SEC_OID_SECG_EC_SECP128R2 },
|
|
|
|
{ "sect113r1", SEC_OID_SECG_EC_SECT113R1 },
|
|
{ "sect113r2", SEC_OID_SECG_EC_SECT113R2 },
|
|
{ "sect131r1", SEC_OID_SECG_EC_SECT131R1 },
|
|
{ "sect131r2", SEC_OID_SECG_EC_SECT131R2 },
|
|
};
|
|
|
|
static SECItem *
|
|
getECParams(const char *curve)
|
|
{
|
|
SECItem *ecparams;
|
|
SECOidData *oidData = NULL;
|
|
SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
|
|
int i, numCurves;
|
|
|
|
if (curve != NULL) {
|
|
numCurves = sizeof(nameTagPair) / sizeof(CurveNameTagPair);
|
|
for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
|
|
i++) {
|
|
if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
|
|
curveOidTag = nameTagPair[i].curveOidTag;
|
|
}
|
|
}
|
|
|
|
/* Return NULL if curve name is not recognized */
|
|
if ((curveOidTag == SEC_OID_UNKNOWN) ||
|
|
(oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
|
|
fprintf(stderr, "Unrecognized elliptic curve %s\n", curve);
|
|
return NULL;
|
|
}
|
|
|
|
ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
|
|
|
|
/*
|
|
* ecparams->data needs to contain the ASN encoding of an object ID (OID)
|
|
* representing the named curve. The actual OID is in
|
|
* oidData->oid.data so we simply prepend 0x06 and OID length
|
|
*/
|
|
ecparams->data[0] = SEC_ASN1_OBJECT_ID;
|
|
ecparams->data[1] = oidData->oid.len;
|
|
memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
|
|
|
|
return ecparams;
|
|
}
|
|
|
|
/*
|
|
* HASH_ functions are available to full NSS apps and internally inside
|
|
* freebl, but not exported to users of freebl. Create short stubs to
|
|
* replace the functionality for fipstest.
|
|
*/
|
|
SECStatus
|
|
fips_hashBuf(HASH_HashType type, unsigned char *hashBuf,
|
|
unsigned char *msg, int len)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
|
|
switch (type) {
|
|
case HASH_AlgSHA1:
|
|
rv = SHA1_HashBuf(hashBuf, msg, len);
|
|
break;
|
|
case HASH_AlgSHA224:
|
|
rv = SHA224_HashBuf(hashBuf, msg, len);
|
|
break;
|
|
case HASH_AlgSHA256:
|
|
rv = SHA256_HashBuf(hashBuf, msg, len);
|
|
break;
|
|
case HASH_AlgSHA384:
|
|
rv = SHA384_HashBuf(hashBuf, msg, len);
|
|
break;
|
|
case HASH_AlgSHA512:
|
|
rv = SHA512_HashBuf(hashBuf, msg, len);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
int
|
|
fips_hashLen(HASH_HashType type)
|
|
{
|
|
int len = 0;
|
|
|
|
switch (type) {
|
|
case HASH_AlgSHA1:
|
|
len = SHA1_LENGTH;
|
|
break;
|
|
case HASH_AlgSHA224:
|
|
len = SHA224_LENGTH;
|
|
break;
|
|
case HASH_AlgSHA256:
|
|
len = SHA256_LENGTH;
|
|
break;
|
|
case HASH_AlgSHA384:
|
|
len = SHA384_LENGTH;
|
|
break;
|
|
case HASH_AlgSHA512:
|
|
len = SHA512_LENGTH;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
SECOidTag
|
|
fips_hashOid(HASH_HashType type)
|
|
{
|
|
SECOidTag oid = SEC_OID_UNKNOWN;
|
|
|
|
switch (type) {
|
|
case HASH_AlgSHA1:
|
|
oid = SEC_OID_SHA1;
|
|
break;
|
|
case HASH_AlgSHA224:
|
|
oid = SEC_OID_SHA224;
|
|
break;
|
|
case HASH_AlgSHA256:
|
|
oid = SEC_OID_SHA256;
|
|
break;
|
|
case HASH_AlgSHA384:
|
|
oid = SEC_OID_SHA384;
|
|
break;
|
|
case HASH_AlgSHA512:
|
|
oid = SEC_OID_SHA512;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return oid;
|
|
}
|
|
|
|
HASH_HashType
|
|
sha_get_hashType(int hashbits)
|
|
{
|
|
HASH_HashType hashType = HASH_AlgNULL;
|
|
|
|
switch (hashbits) {
|
|
case 1:
|
|
case (SHA1_LENGTH * PR_BITS_PER_BYTE):
|
|
hashType = HASH_AlgSHA1;
|
|
break;
|
|
case (SHA224_LENGTH * PR_BITS_PER_BYTE):
|
|
hashType = HASH_AlgSHA224;
|
|
break;
|
|
case (SHA256_LENGTH * PR_BITS_PER_BYTE):
|
|
hashType = HASH_AlgSHA256;
|
|
break;
|
|
case (SHA384_LENGTH * PR_BITS_PER_BYTE):
|
|
hashType = HASH_AlgSHA384;
|
|
break;
|
|
case (SHA512_LENGTH * PR_BITS_PER_BYTE):
|
|
hashType = HASH_AlgSHA512;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return hashType;
|
|
}
|
|
|
|
HASH_HashType
|
|
hash_string_to_hashType(const char *src)
|
|
{
|
|
HASH_HashType shaAlg = HASH_AlgNULL;
|
|
if (strncmp(src, "SHA-1", 5) == 0) {
|
|
shaAlg = HASH_AlgSHA1;
|
|
} else if (strncmp(src, "SHA-224", 7) == 0) {
|
|
shaAlg = HASH_AlgSHA224;
|
|
} else if (strncmp(src, "SHA-256", 7) == 0) {
|
|
shaAlg = HASH_AlgSHA256;
|
|
} else if (strncmp(src, "SHA-384", 7) == 0) {
|
|
shaAlg = HASH_AlgSHA384;
|
|
} else if (strncmp(src, "SHA-512", 7) == 0) {
|
|
shaAlg = HASH_AlgSHA512;
|
|
} else if (strncmp(src, "SHA1", 4) == 0) {
|
|
shaAlg = HASH_AlgSHA1;
|
|
} else if (strncmp(src, "SHA224", 6) == 0) {
|
|
shaAlg = HASH_AlgSHA224;
|
|
} else if (strncmp(src, "SHA256", 6) == 0) {
|
|
shaAlg = HASH_AlgSHA256;
|
|
} else if (strncmp(src, "SHA384", 6) == 0) {
|
|
shaAlg = HASH_AlgSHA384;
|
|
} else if (strncmp(src, "SHA512", 6) == 0) {
|
|
shaAlg = HASH_AlgSHA512;
|
|
}
|
|
return shaAlg;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
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;
|
|
|
|
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(*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;
|
|
|
|
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);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
if (ecparams) {
|
|
PORT_FreeArena(ecparams->arena, PR_FALSE);
|
|
ecparams = NULL;
|
|
}
|
|
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) {
|
|
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);
|
|
len = (ecparams->fieldID.size + 7) >> 3;
|
|
if (pubkey.data != NULL) {
|
|
PORT_Free(pubkey.data);
|
|
pubkey.data = NULL;
|
|
}
|
|
SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(ecparams));
|
|
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 sha[HASH_LENGTH_MAX]; /* SHA digest */
|
|
unsigned int shaLength = 0; /* length of SHA */
|
|
HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */
|
|
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';
|
|
src++; /* skip the comma */
|
|
/* set the SHA Algorithm */
|
|
shaAlg = hash_string_to_hashType(src);
|
|
if (shaAlg == HASH_AlgNULL) {
|
|
fprintf(ecdsaresp, "ERROR: Unable to find SHAAlg type");
|
|
goto loser;
|
|
}
|
|
if (ecparams != NULL) {
|
|
PORT_FreeArena(ecparams->arena, PR_FALSE);
|
|
ecparams = NULL;
|
|
}
|
|
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;
|
|
}
|
|
/* 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;
|
|
shaLength = fips_hashLen(shaAlg);
|
|
if (fips_hashBuf(shaAlg, sha, msg, msglen) != SECSuccess) {
|
|
if (shaLength == 0) {
|
|
fprintf(ecdsaresp, "ERROR: SHAAlg not defined.");
|
|
}
|
|
fprintf(ecdsaresp, "ERROR: Unable to generate SHA%x",
|
|
shaLength == 160 ? 1 : shaLength);
|
|
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 = sha;
|
|
digest.len = shaLength;
|
|
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 sha[HASH_LENGTH_MAX]; /* SHA digest */
|
|
unsigned int shaLength = 0; /* length of SHA */
|
|
HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */
|
|
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';
|
|
src++; /* skip the comma */
|
|
/* set the SHA Algorithm */
|
|
shaAlg = hash_string_to_hashType(src);
|
|
if (shaAlg == HASH_AlgNULL) {
|
|
fprintf(ecdsaresp, "ERROR: Unable to find SHAAlg type");
|
|
goto loser;
|
|
}
|
|
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);
|
|
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;
|
|
shaLength = fips_hashLen(shaAlg);
|
|
if (fips_hashBuf(shaAlg, sha, msg, msglen) != SECSuccess) {
|
|
if (shaLength == 0) {
|
|
fprintf(ecdsaresp, "ERROR: SHAAlg not defined.");
|
|
}
|
|
fprintf(ecdsaresp, "ERROR: Unable to generate SHA%x",
|
|
shaLength == 160 ? 1 : shaLength);
|
|
goto loser;
|
|
}
|
|
fputs(buf, ecdsaresp);
|
|
|
|
digest.type = siBuffer;
|
|
digest.data = sha;
|
|
digest.len = shaLength;
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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" */
|
|
unsigned char hashBuf[HASH_LENGTH_MAX];
|
|
ECParams *ecparams[MAX_ECC_PARAMS] = { NULL };
|
|
ECPrivateKey *ecpriv = NULL;
|
|
ECParams *current_ecparams = NULL;
|
|
SECItem pubkey;
|
|
SECItem ZZ;
|
|
unsigned int i;
|
|
unsigned int len = 0;
|
|
unsigned int uit_len = 0;
|
|
int current_curve = -1;
|
|
HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
|
|
|
|
ecdhreq = fopen(reqfn, "r");
|
|
ecdhresp = stdout;
|
|
strcpy(curve, "nist");
|
|
pubkey.data = NULL;
|
|
while (fgets(buf, sizeof buf, ecdhreq) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
|
|
fputs(buf, ecdhresp);
|
|
continue;
|
|
}
|
|
if (buf[0] == '[') {
|
|
/* [Ex] */
|
|
if (buf[1] == 'E' && buf[3] == ']') {
|
|
current_curve = buf[2] - 'A';
|
|
fputs(buf, ecdhresp);
|
|
continue;
|
|
}
|
|
/* [Curve selected: x-nnn */
|
|
if (strncmp(buf, "[Curve ", 7) == 0) {
|
|
const char *src;
|
|
char *dst;
|
|
SECItem *encodedparams;
|
|
|
|
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(*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] == ' ') {
|
|
const char *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(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(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" */
|
|
unsigned char hashBuf[HASH_LENGTH_MAX];
|
|
unsigned char cavsHashBuf[HASH_LENGTH_MAX];
|
|
unsigned char private_data[MAX_ECKEY_LEN];
|
|
ECParams *ecparams[MAX_ECC_PARAMS] = { NULL };
|
|
ECParams *current_ecparams = NULL;
|
|
SECItem pubkey;
|
|
SECItem ZZ;
|
|
SECItem private_value;
|
|
unsigned int i;
|
|
unsigned int len = 0;
|
|
int current_curve = -1;
|
|
HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
|
|
|
|
ecdhreq = fopen(reqfn, "r");
|
|
ecdhresp = stdout;
|
|
strcpy(curve, "nist");
|
|
pubkey.data = NULL;
|
|
while (fgets(buf, sizeof buf, ecdhreq) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
|
|
fputs(buf, ecdhresp);
|
|
continue;
|
|
}
|
|
if (buf[0] == '[') {
|
|
/* [Ex] */
|
|
if (buf[1] == 'E' && buf[3] == ']') {
|
|
current_curve = buf[2] - 'A';
|
|
fputs(buf, ecdhresp);
|
|
continue;
|
|
}
|
|
/* [Curve selected: x-nnn */
|
|
if (strncmp(buf, "[Curve ", 7) == 0) {
|
|
const char *src;
|
|
char *dst;
|
|
SECItem *encodedparams;
|
|
|
|
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(*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.\n", 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] == ' ') {
|
|
const char *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(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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(&pubkey.data[1 + len], len, &buf[i]);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "deIUT", 5) == 0) {
|
|
fputs(buf, ecdhresp);
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(private_data, len, &buf[i]);
|
|
private_value.data = private_data;
|
|
private_value.len = len;
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "QeIUTx", 6) == 0) {
|
|
fputs(buf, ecdhresp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "QeIUTy", 6) == 0) {
|
|
fputs(buf, ecdhresp);
|
|
continue;
|
|
}
|
|
if ((strncmp(buf, "CAVSHashZZ", 10) == 0) ||
|
|
(strncmp(buf, "HashZZ", 6) == 0)) {
|
|
fputs(buf, ecdhresp);
|
|
i = (buf[0] == 'C') ? 10 : 6;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]);
|
|
if (current_ecparams == NULL) {
|
|
fprintf(stderr, "no curve defined for type defined\n");
|
|
goto loser;
|
|
}
|
|
/* validate CAVS public key */
|
|
if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) {
|
|
#ifdef VERBOSE_REASON
|
|
fprintf(ecdhresp, "Result = F # key didn't validate\n");
|
|
#else
|
|
fprintf(ecdhresp, "Result = F\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
/* ECDH */
|
|
if (ECDH_Derive(&pubkey, current_ecparams, &private_value,
|
|
PR_FALSE, &ZZ) != SECSuccess) {
|
|
#ifdef VERBOSE_REASON
|
|
fprintf(ecdhresp, "Result = F # derive failure\n");
|
|
#else
|
|
fprintf(ecdhresp, "Result = F\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
/* output ZZ */
|
|
#ifndef MATCH_OPENSSL
|
|
fputs("Z = ", ecdhresp);
|
|
to_hex_str(buf, ZZ.data, ZZ.len);
|
|
fputs(buf, ecdhresp);
|
|
fputc('\n', ecdhresp);
|
|
#endif
|
|
|
|
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);
|
|
#ifndef MATCH_NIST
|
|
fputs("IUTHashZZ = ", ecdhresp);
|
|
to_hex_str(buf, hashBuf, fips_hashLen(hash));
|
|
fputs(buf, ecdhresp);
|
|
fputc('\n', ecdhresp);
|
|
#endif
|
|
if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) {
|
|
#ifdef VERBOSE_REASON
|
|
fprintf(ecdhresp, "Result = F # hash doesn't match\n");
|
|
#else
|
|
fprintf(ecdhresp, "Result = F\n");
|
|
#endif
|
|
} else {
|
|
fprintf(ecdhresp, "Result = P\n");
|
|
}
|
|
#ifndef MATCH_OPENSSL
|
|
fputc('\n', ecdhresp);
|
|
#endif
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
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 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 */
|
|
unsigned char hashBuf[HASH_LENGTH_MAX];
|
|
DSAPrivateKey *dsapriv = NULL;
|
|
PQGParams pqg = { 0 };
|
|
unsigned char pubkeydata[DSA_MAX_P_BITS / 8];
|
|
SECItem pubkey;
|
|
SECItem ZZ;
|
|
unsigned int i, j;
|
|
unsigned int 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] == ' ') {
|
|
const char *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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < pqg.prime.len; i += 2, j++) {
|
|
if (!isxdigit(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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < pqg.subPrime.len; i += 2, j++) {
|
|
if (!isxdigit(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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < pqg.base.len; i += 2, j++) {
|
|
if (!isxdigit(buf[i])) {
|
|
pqg.base.len = j;
|
|
break;
|
|
}
|
|
hex_to_byteval(&buf[i], &pqg.base.data[j]);
|
|
}
|
|
|
|
fputs(buf, dhresp);
|
|
continue;
|
|
}
|
|
|
|
/* COUNT = ... */
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
fputs(buf, dhresp);
|
|
continue;
|
|
}
|
|
|
|
/* YephemCAVS = ... */
|
|
if (strncmp(buf, "YephemCAVS", 10) == 0) {
|
|
fputs(buf, dhresp);
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(pubkeydata, pqg.prime.len, &buf[i]);
|
|
pubkey.data = pubkeydata;
|
|
pubkey.len = pqg.prime.len;
|
|
|
|
/* 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 */
|
|
unsigned char hashBuf[HASH_LENGTH_MAX];
|
|
unsigned char cavsHashBuf[HASH_LENGTH_MAX];
|
|
PQGParams pqg = { 0 };
|
|
unsigned char pubkeydata[DSA_MAX_P_BITS / 8];
|
|
unsigned char privkeydata[DSA_MAX_P_BITS / 8];
|
|
SECItem pubkey;
|
|
SECItem privkey;
|
|
SECItem ZZ;
|
|
unsigned int i, j;
|
|
unsigned int 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] == ' ') {
|
|
const char *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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < pqg.prime.len; i += 2, j++) {
|
|
if (!isxdigit(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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < pqg.subPrime.len; i += 2, j++) {
|
|
if (!isxdigit(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(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < pqg.base.len; i += 2, j++) {
|
|
if (!isxdigit(buf[i])) {
|
|
pqg.base.len = j;
|
|
break;
|
|
}
|
|
hex_to_byteval(&buf[i], &pqg.base.data[j]);
|
|
}
|
|
|
|
fputs(buf, dhresp);
|
|
continue;
|
|
}
|
|
|
|
/* COUNT = ... */
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
fputs(buf, dhresp);
|
|
continue;
|
|
}
|
|
|
|
/* YephemCAVS = ... */
|
|
if (strncmp(buf, "YephemCAVS", 10) == 0) {
|
|
fputs(buf, dhresp);
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(pubkeydata, pqg.prime.len, &buf[i]);
|
|
pubkey.data = pubkeydata;
|
|
pubkey.len = pqg.prime.len;
|
|
continue;
|
|
}
|
|
/* XephemUIT = ... */
|
|
if (strncmp(buf, "XephemIUT", 9) == 0) {
|
|
fputs(buf, dhresp);
|
|
i = 9;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(privkeydata, pqg.subPrime.len, &buf[i]);
|
|
privkey.data = privkeydata;
|
|
privkey.len = pqg.subPrime.len;
|
|
continue;
|
|
}
|
|
/* YephemUIT = ... */
|
|
if (strncmp(buf, "YephemIUT", 9) == 0) {
|
|
fputs(buf, dhresp);
|
|
continue;
|
|
}
|
|
/* CAVSHashZZ = ... */
|
|
if ((strncmp(buf, "CAVSHashZZ", 10) == 0) ||
|
|
(strncmp(buf, "HashZZ", 6) == 0)) {
|
|
fputs(buf, dhresp);
|
|
i = buf[0] == 'C' ? 10 : 6;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]);
|
|
/* do the DH operation*/
|
|
if (DH_Derive(&pubkey, &pqg.prime, &privkey,
|
|
&ZZ, pqg.prime.len) != SECSuccess) {
|
|
fprintf(stderr, "Derive failed\n");
|
|
goto loser;
|
|
}
|
|
/* output ZZ */
|
|
#ifndef MATCH_OPENSSL
|
|
fputs("Z = ", dhresp);
|
|
to_hex_str(buf, ZZ.data, ZZ.len);
|
|
fputs(buf, dhresp);
|
|
fputc('\n', dhresp);
|
|
#endif
|
|
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);
|
|
#ifndef MATCH_NIST
|
|
fputs("IUTHashZZ = ", dhresp);
|
|
to_hex_str(buf, hashBuf, fips_hashLen(hash));
|
|
fputs(buf, dhresp);
|
|
fputc('\n', dhresp);
|
|
#endif
|
|
if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) {
|
|
fprintf(dhresp, "Result = F\n");
|
|
} else {
|
|
fprintf(dhresp, "Result = P\n");
|
|
}
|
|
#ifndef MATCH_OPENSSL
|
|
fputc('\n', dhresp);
|
|
#endif
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(dhreq);
|
|
}
|
|
|
|
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;
|
|
#ifdef HANDLE_PREDICTION_RESISTANCE
|
|
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 = NULL;
|
|
unsigned char *return_bytes = NULL;
|
|
int return_bytes_len = 0;
|
|
enum { NONE,
|
|
INSTANTIATE,
|
|
GENERATE,
|
|
RESEED,
|
|
RESULT } command =
|
|
NONE;
|
|
PRBool genResult = PR_FALSE;
|
|
SECStatus rv;
|
|
|
|
rngreq = fopen(reqfn, "r");
|
|
rngresp = stdout;
|
|
while (fgets(buf, sizeof buf, rngreq) != NULL) {
|
|
switch (command) {
|
|
case INSTANTIATE:
|
|
if (debug) {
|
|
fputs("# PRNGTEST_Instantiate(", rngresp);
|
|
to_hex_str(buf2, entropyInput, entropyInputLen);
|
|
fputs(buf2, rngresp);
|
|
fprintf(rngresp, ",%d,", entropyInputLen);
|
|
to_hex_str(buf2, nonce, nonceLen);
|
|
fputs(buf2, rngresp);
|
|
fprintf(rngresp, ",%d,", nonceLen);
|
|
to_hex_str(buf2, personalizationString,
|
|
personalizationStringLen);
|
|
fputs(buf2, rngresp);
|
|
fprintf(rngresp, ",%d)\n", personalizationStringLen);
|
|
}
|
|
rv = PRNGTEST_Instantiate(entropyInput, entropyInputLen,
|
|
nonce, nonceLen,
|
|
personalizationString,
|
|
personalizationStringLen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
break;
|
|
|
|
case GENERATE:
|
|
case RESULT:
|
|
memset(return_bytes, 0, return_bytes_len);
|
|
if (debug) {
|
|
fputs("# PRNGTEST_Generate(returnbytes", rngresp);
|
|
fprintf(rngresp, ",%d,", return_bytes_len);
|
|
to_hex_str(buf2, additionalInput, additionalInputLen);
|
|
fputs(buf2, rngresp);
|
|
fprintf(rngresp, ",%d)\n", additionalInputLen);
|
|
}
|
|
rv = PRNGTEST_Generate((PRUint8 *)return_bytes,
|
|
return_bytes_len,
|
|
(PRUint8 *)additionalInput,
|
|
additionalInputLen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (command == RESULT) {
|
|
fputs("ReturnedBits = ", rngresp);
|
|
to_hex_str(buf2, return_bytes, return_bytes_len);
|
|
fputs(buf2, rngresp);
|
|
fputc('\n', rngresp);
|
|
if (debug) {
|
|
fputs("# PRNGTEST_Uninstantiate()\n", rngresp);
|
|
}
|
|
rv = PRNGTEST_Uninstantiate();
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
} else if (debug) {
|
|
fputs("#ReturnedBits = ", rngresp);
|
|
to_hex_str(buf2, return_bytes, return_bytes_len);
|
|
fputs(buf2, rngresp);
|
|
fputc('\n', rngresp);
|
|
}
|
|
|
|
memset(additionalInput, 0, additionalInputLen);
|
|
break;
|
|
|
|
case RESEED:
|
|
if (entropyInput || additionalInput) {
|
|
if (debug) {
|
|
fputs("# PRNGTEST_Reseed(", rngresp);
|
|
fprintf(rngresp, ",%d,", return_bytes_len);
|
|
to_hex_str(buf2, entropyInput, entropyInputLen);
|
|
fputs(buf2, rngresp);
|
|
fprintf(rngresp, ",%d,", entropyInputLen);
|
|
to_hex_str(buf2, additionalInput, additionalInputLen);
|
|
fputs(buf2, rngresp);
|
|
fprintf(rngresp, ",%d)\n", additionalInputLen);
|
|
}
|
|
rv = PRNGTEST_Reseed(entropyInput, entropyInputLen,
|
|
additionalInput, additionalInputLen);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
}
|
|
memset(entropyInput, 0, entropyInputLen);
|
|
memset(additionalInput, 0, additionalInputLen);
|
|
break;
|
|
case NONE:
|
|
break;
|
|
}
|
|
command = NONE;
|
|
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* [Hash - SHA256] */
|
|
if (strncmp(buf, "[SHA-256]", 9) == 0) {
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "[PredictionResistance", 21) == 0) {
|
|
#ifdef HANDLE_PREDICTION_RESISTANCE
|
|
i = 21;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
if (strncmp(buf, "False", 5) == 0) {
|
|
predictionResistance = PR_FALSE;
|
|
} else {
|
|
predictionResistance = PR_TRUE;
|
|
}
|
|
#endif
|
|
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "[ReturnedBitsLen", 16) == 0) {
|
|
if (return_bytes) {
|
|
PORT_ZFree(return_bytes, return_bytes_len);
|
|
return_bytes = NULL;
|
|
}
|
|
if (predictedreturn_bytes) {
|
|
PORT_ZFree(predictedreturn_bytes, return_bytes_len);
|
|
predictedreturn_bytes = NULL;
|
|
}
|
|
return_bytes_len = 0;
|
|
if (sscanf(buf, "[ReturnedBitsLen = %d]", &return_bytes_len) != 1) {
|
|
goto loser;
|
|
}
|
|
return_bytes_len = return_bytes_len / 8;
|
|
if (return_bytes_len > 0) {
|
|
return_bytes = PORT_Alloc(return_bytes_len);
|
|
predictedreturn_bytes = PORT_Alloc(return_bytes_len);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "[EntropyInputLen", 16) == 0) {
|
|
if (entropyInput) {
|
|
PORT_ZFree(entropyInput, entropyInputLen);
|
|
entropyInput = NULL;
|
|
entropyInputLen = 0;
|
|
}
|
|
if (sscanf(buf, "[EntropyInputLen = %d]", &entropyInputLen) != 1) {
|
|
goto loser;
|
|
}
|
|
entropyInputLen = entropyInputLen / 8;
|
|
if (entropyInputLen > 0) {
|
|
entropyInput = PORT_Alloc(entropyInputLen);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "[NonceLen", 9) == 0) {
|
|
if (nonce) {
|
|
PORT_ZFree(nonce, nonceLen);
|
|
nonce = NULL;
|
|
nonceLen = 0;
|
|
}
|
|
|
|
if (sscanf(buf, "[NonceLen = %d]", &nonceLen) != 1) {
|
|
goto loser;
|
|
}
|
|
nonceLen = nonceLen / 8;
|
|
if (nonceLen > 0) {
|
|
nonce = PORT_Alloc(nonceLen);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "[PersonalizationStringLen", 16) == 0) {
|
|
if (personalizationString) {
|
|
PORT_ZFree(personalizationString, personalizationStringLen);
|
|
personalizationString = NULL;
|
|
personalizationStringLen = 0;
|
|
}
|
|
|
|
if (sscanf(buf, "[PersonalizationStringLen = %d]", &personalizationStringLen) != 1) {
|
|
goto loser;
|
|
}
|
|
personalizationStringLen = personalizationStringLen / 8;
|
|
if (personalizationStringLen > 0) {
|
|
personalizationString = PORT_Alloc(personalizationStringLen);
|
|
}
|
|
fputs(buf, rngresp);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "[AdditionalInputLen", 16) == 0) {
|
|
if (additionalInput) {
|
|
PORT_ZFree(additionalInput, additionalInputLen);
|
|
additionalInput = NULL;
|
|
additionalInputLen = 0;
|
|
}
|
|
|
|
if (sscanf(buf, "[AdditionalInputLen = %d]", &additionalInputLen) != 1) {
|
|
goto loser;
|
|
}
|
|
additionalInputLen = additionalInputLen / 8;
|
|
if (additionalInputLen > 0) {
|
|
additionalInput = PORT_Alloc(additionalInputLen);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
/* zeroize the variables for the test with this data set */
|
|
if (entropyInput) {
|
|
memset(entropyInput, 0, entropyInputLen);
|
|
}
|
|
if (nonce) {
|
|
memset(nonce, 0, nonceLen);
|
|
}
|
|
if (personalizationString) {
|
|
memset(personalizationString, 0, personalizationStringLen);
|
|
}
|
|
if (additionalInput) {
|
|
memset(additionalInput, 0, additionalInputLen);
|
|
}
|
|
genResult = PR_FALSE;
|
|
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* EntropyInputReseed = ... */
|
|
if (strncmp(buf, "EntropyInputReseed", 18) == 0) {
|
|
if (entropyInput) {
|
|
memset(entropyInput, 0, entropyInputLen);
|
|
i = 18;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<entropyInputLen*/
|
|
hex_to_byteval(&buf[i], &entropyInput[j]);
|
|
}
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* AttionalInputReseed = ... */
|
|
if (strncmp(buf, "AdditionalInputReseed", 21) == 0) {
|
|
if (additionalInput) {
|
|
memset(additionalInput, 0, additionalInputLen);
|
|
i = 21;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<additionalInputLen*/
|
|
hex_to_byteval(&buf[i], &additionalInput[j]);
|
|
}
|
|
}
|
|
command = RESEED;
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* Entropy input = ... */
|
|
if (strncmp(buf, "EntropyInput", 12) == 0) {
|
|
i = 12;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<entropyInputLen*/
|
|
hex_to_byteval(&buf[i], &entropyInput[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* nouce = ... */
|
|
if (strncmp(buf, "Nonce", 5) == 0) {
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<nonceLen*/
|
|
hex_to_byteval(&buf[i], &nonce[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* Personalization string = ... */
|
|
if (strncmp(buf, "PersonalizationString", 21) == 0) {
|
|
if (personalizationString) {
|
|
i = 21;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<personalizationStringLen*/
|
|
hex_to_byteval(&buf[i], &personalizationString[j]);
|
|
}
|
|
}
|
|
fputs(buf, rngresp);
|
|
command = INSTANTIATE;
|
|
continue;
|
|
}
|
|
|
|
/* Additional input = ... */
|
|
if (strncmp(buf, "AdditionalInput", 15) == 0) {
|
|
if (additionalInput) {
|
|
i = 15;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<additionalInputLen*/
|
|
hex_to_byteval(&buf[i], &additionalInput[j]);
|
|
}
|
|
}
|
|
if (genResult) {
|
|
command = RESULT;
|
|
} else {
|
|
command = GENERATE;
|
|
genResult = PR_TRUE; /* next time generate result */
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
|
|
/* Returned bits = ... */
|
|
if (strncmp(buf, "ReturnedBits", 12) == 0) {
|
|
i = 12;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) { /*j<additionalInputLen*/
|
|
hex_to_byteval(&buf[i], &predictedreturn_bytes[j]);
|
|
}
|
|
|
|
if (memcmp(return_bytes,
|
|
predictedreturn_bytes, return_bytes_len) != 0) {
|
|
if (debug) {
|
|
fprintf(rngresp, "# Generate failed:\n");
|
|
fputs("# predicted=", rngresp);
|
|
to_hex_str(buf, predictedreturn_bytes,
|
|
return_bytes_len);
|
|
fputs(buf, rngresp);
|
|
fputs("\n# actual = ", rngresp);
|
|
fputs(buf2, rngresp);
|
|
fputc('\n', rngresp);
|
|
|
|
} else {
|
|
fprintf(stderr, "Generate failed:\n");
|
|
fputs(" predicted=", stderr);
|
|
to_hex_str(buf, predictedreturn_bytes,
|
|
return_bytes_len);
|
|
fputs(buf, stderr);
|
|
fputs("\n actual = ", stderr);
|
|
fputs(buf2, stderr);
|
|
fputc('\n', stderr);
|
|
}
|
|
}
|
|
memset(predictedreturn_bytes, 0, return_bytes_len);
|
|
|
|
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 */
|
|
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 < sizeof Q; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Q[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
hasQ = PR_TRUE;
|
|
continue;
|
|
}
|
|
/* "COUNT = x" begins a new data set */
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
/* zeroize the variables for the test with this data set */
|
|
b = 0;
|
|
memset(XKey, 0, sizeof XKey);
|
|
memset(XSeed, 0, sizeof XSeed);
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
/* b = ... */
|
|
if (buf[0] == 'b') {
|
|
i = 1;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
b = atoi(&buf[i]);
|
|
if (b < 160 || b > 512 || b % 8 != 0) {
|
|
goto loser;
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
/* XKey = ... */
|
|
if (strncmp(buf, "XKey", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < b / 8; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &XKey[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
/* XSeed = ... */
|
|
if (strncmp(buf, "XSeed", 5) == 0) {
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < b / 8; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &XSeed[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
|
|
rv = FIPS186Change_GenerateX(XKey, XSeed, GENX);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
fputs("X = ", rngresp);
|
|
if (hasQ) {
|
|
rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
to_hex_str(buf, DSAX, sizeof DSAX);
|
|
} else {
|
|
to_hex_str(buf, GENX, sizeof GENX);
|
|
}
|
|
fputs(buf, rngresp);
|
|
fputc('\n', rngresp);
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(rngreq);
|
|
}
|
|
|
|
/*
|
|
* Perform the RNG Monte Carlo Test (MCT) for the RNG algorithm
|
|
* "DSA - Generation of X", used both as specified and as a generic
|
|
* purpose RNG. The presence of "Q = ..." in the REQUEST file
|
|
* indicates we are using the algorithm as specified.
|
|
*
|
|
* reqfn is the pathname of the REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
rng_mct(char *reqfn)
|
|
{
|
|
char buf[256]; /* holds one line from the input REQUEST file.
|
|
* needs to be large enough to hold the longest
|
|
* line "XSeed = <128 hex digits>\n".
|
|
*/
|
|
FILE *rngreq; /* input stream from the REQUEST file */
|
|
FILE *rngresp; /* output stream to the RESPONSE file */
|
|
unsigned int i, j;
|
|
unsigned char Q[DSA1_SUBPRIME_LEN];
|
|
PRBool hasQ = PR_FALSE;
|
|
unsigned int b = 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; j < sizeof Q; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Q[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
hasQ = PR_TRUE;
|
|
continue;
|
|
}
|
|
/* "COUNT = x" begins a new data set */
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
/* zeroize the variables for the test with this data set */
|
|
b = 0;
|
|
memset(XKey, 0, sizeof XKey);
|
|
memset(XSeed, 0, sizeof XSeed);
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
/* b = ... */
|
|
if (buf[0] == 'b') {
|
|
i = 1;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
b = atoi(&buf[i]);
|
|
if (b < 160 || b > 512 || b % 8 != 0) {
|
|
goto loser;
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
/* XKey = ... */
|
|
if (strncmp(buf, "XKey", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < b / 8; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &XKey[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
continue;
|
|
}
|
|
/* XSeed = ... */
|
|
if (strncmp(buf, "XSeed", 5) == 0) {
|
|
unsigned int k;
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < b / 8; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &XSeed[j]);
|
|
}
|
|
fputs(buf, rngresp);
|
|
|
|
for (k = 0; k < 10000; k++) {
|
|
rv = FIPS186Change_GenerateX(XKey, XSeed, GENX);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
}
|
|
fputs("X = ", rngresp);
|
|
if (hasQ) {
|
|
rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
to_hex_str(buf, DSAX, sizeof DSAX);
|
|
} else {
|
|
to_hex_str(buf, GENX, sizeof GENX);
|
|
}
|
|
fputs(buf, rngresp);
|
|
fputc('\n', rngresp);
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(rngreq);
|
|
}
|
|
|
|
/*
|
|
* Calculate the SHA Message Digest
|
|
*
|
|
* MD = Message digest
|
|
* MDLen = length of Message Digest and SHA_Type
|
|
* msg = message to digest
|
|
* msgLen = length of message to digest
|
|
*/
|
|
SECStatus
|
|
sha_calcMD(unsigned char *MD, unsigned int MDLen, unsigned char *msg, unsigned int msgLen)
|
|
{
|
|
HASH_HashType hashType = sha_get_hashType(MDLen * PR_BITS_PER_BYTE);
|
|
|
|
return fips_hashBuf(hashType, MD, msg, msgLen);
|
|
}
|
|
|
|
/*
|
|
* Perform the SHA Monte Carlo Test
|
|
*
|
|
* MDLen = length of Message Digest and SHA_Type
|
|
* seed = input seed value
|
|
* resp = is the output response file.
|
|
*/
|
|
SECStatus
|
|
sha_mct_test(unsigned int MDLen, unsigned char *seed, FILE *resp)
|
|
{
|
|
int i, j;
|
|
unsigned int msgLen = MDLen * 3;
|
|
unsigned char MD_i3[HASH_LENGTH_MAX]; /* MD[i-3] */
|
|
unsigned char MD_i2[HASH_LENGTH_MAX]; /* MD[i-2] */
|
|
unsigned char MD_i1[HASH_LENGTH_MAX]; /* MD[i-1] */
|
|
unsigned char MD_i[HASH_LENGTH_MAX]; /* MD[i] */
|
|
unsigned char msg[HASH_LENGTH_MAX * 3];
|
|
char buf[HASH_LENGTH_MAX * 2 + 1]; /* MAX buf MD_i as a hex string */
|
|
|
|
for (j = 0; j < 100; j++) {
|
|
/* MD_0 = MD_1 = MD_2 = seed */
|
|
memcpy(MD_i3, seed, MDLen);
|
|
memcpy(MD_i2, seed, MDLen);
|
|
memcpy(MD_i1, seed, MDLen);
|
|
|
|
for (i = 3; i < 1003; i++) {
|
|
/* Mi = MD[i-3] || MD [i-2] || MD [i-1] */
|
|
memcpy(msg, MD_i3, MDLen);
|
|
memcpy(&msg[MDLen], MD_i2, MDLen);
|
|
memcpy(&msg[MDLen * 2], MD_i1, MDLen);
|
|
|
|
/* MDi = SHA(Msg) */
|
|
if (sha_calcMD(MD_i, MDLen,
|
|
msg, msgLen) != SECSuccess) {
|
|
return SECFailure;
|
|
}
|
|
|
|
/* save MD[i-3] MD[i-2] MD[i-1] */
|
|
memcpy(MD_i3, MD_i2, MDLen);
|
|
memcpy(MD_i2, MD_i1, MDLen);
|
|
memcpy(MD_i1, MD_i, MDLen);
|
|
}
|
|
|
|
/* seed = MD_i */
|
|
memcpy(seed, MD_i, MDLen);
|
|
|
|
sprintf(buf, "COUNT = %d\n", j);
|
|
fputs(buf, resp);
|
|
|
|
/* output MD_i */
|
|
fputs("MD = ", resp);
|
|
to_hex_str(buf, MD_i, MDLen);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
}
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* Perform the SHA Tests.
|
|
*
|
|
* reqfn is the pathname of the input REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
sha_test(char *reqfn)
|
|
{
|
|
unsigned int i, j;
|
|
unsigned int MDlen = 0; /* the length of the Message Digest in Bytes */
|
|
unsigned int msgLen = 0; /* the length of the input Message in Bytes */
|
|
unsigned char *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.*/
|
|
unsigned char seed[HASH_LENGTH_MAX]; /* max size of seed 64 bytes */
|
|
unsigned char MD[HASH_LENGTH_MAX]; /* message digest */
|
|
|
|
FILE *req = NULL; /* input stream from the REQUEST file */
|
|
FILE *resp; /* output stream to the RESPONSE file */
|
|
|
|
buf = PORT_ZAlloc(bufSize);
|
|
if (buf == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
/* zeroize the variables for the test with this data set */
|
|
memset(seed, 0, sizeof seed);
|
|
|
|
req = fopen(reqfn, "r");
|
|
resp = stdout;
|
|
while (fgets(buf, bufSize, req) != NULL) {
|
|
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* [L = Length of the Message Digest and sha_type */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(&buf[1], "L ", 1) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
MDlen = atoi(&buf[i]);
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
}
|
|
/* Len = Length of the Input Message Length ... */
|
|
if (strncmp(buf, "Len", 3) == 0) {
|
|
i = 3;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
if (msg) {
|
|
PORT_ZFree(msg, msgLen);
|
|
msg = NULL;
|
|
}
|
|
msgLen = atoi(&buf[i]); /* in bits */
|
|
if (msgLen % 8 != 0) {
|
|
fprintf(stderr, "SHA tests are incorrectly configured for "
|
|
"BIT oriented implementations\n");
|
|
goto loser;
|
|
}
|
|
msgLen = msgLen / 8; /* convert to bytes */
|
|
fputs(buf, resp);
|
|
msg = PORT_ZAlloc(msgLen);
|
|
if (msg == NULL && msgLen != 0) {
|
|
goto loser;
|
|
}
|
|
continue;
|
|
}
|
|
/* MSG = ... */
|
|
if (strncmp(buf, "Msg", 3) == 0) {
|
|
i = 3;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < msgLen; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &msg[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
/* calculate the Message Digest */
|
|
memset(MD, 0, sizeof MD);
|
|
if (sha_calcMD(MD, MDlen,
|
|
msg, msgLen) != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
fputs("MD = ", resp);
|
|
to_hex_str(buf, MD, MDlen);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
|
|
continue;
|
|
}
|
|
/* Seed = ... */
|
|
if (strncmp(buf, "Seed", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < sizeof seed; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &seed[j]);
|
|
}
|
|
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
|
|
/* do the Monte Carlo test */
|
|
if (sha_mct_test(MDlen, seed, resp) != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
if (req) {
|
|
fclose(req);
|
|
}
|
|
if (buf) {
|
|
PORT_ZFree(buf, bufSize);
|
|
}
|
|
if (msg) {
|
|
PORT_ZFree(msg, msgLen);
|
|
}
|
|
}
|
|
|
|
/****************************************************/
|
|
/* HMAC SHA-X calc */
|
|
/* hmac_computed - the computed HMAC */
|
|
/* hmac_length - the length of the computed HMAC */
|
|
/* secret_key - secret key to HMAC */
|
|
/* secret_key_length - length of secret key, */
|
|
/* message - message to HMAC */
|
|
/* message_length - length ofthe message */
|
|
/****************************************************/
|
|
static SECStatus
|
|
hmac_calc(unsigned char *hmac_computed,
|
|
const unsigned int hmac_length,
|
|
const unsigned char *secret_key,
|
|
const unsigned int secret_key_length,
|
|
const unsigned char *message,
|
|
const unsigned int message_length,
|
|
const HASH_HashType hashAlg)
|
|
{
|
|
SECStatus hmac_status = SECFailure;
|
|
HMACContext *cx = NULL;
|
|
SECHashObject *hashObj = NULL;
|
|
unsigned int bytes_hashed = 0;
|
|
|
|
hashObj = (SECHashObject *)HASH_GetRawHashObject(hashAlg);
|
|
|
|
if (!hashObj)
|
|
return (SECFailure);
|
|
|
|
cx = HMAC_Create(hashObj, secret_key,
|
|
secret_key_length,
|
|
PR_TRUE); /* PR_TRUE for in FIPS mode */
|
|
|
|
if (cx == NULL)
|
|
return (SECFailure);
|
|
|
|
HMAC_Begin(cx);
|
|
HMAC_Update(cx, message, message_length);
|
|
hmac_status = HMAC_Finish(cx, hmac_computed, &bytes_hashed,
|
|
hmac_length);
|
|
|
|
HMAC_Destroy(cx, PR_TRUE);
|
|
|
|
return (hmac_status);
|
|
}
|
|
|
|
/*
|
|
* Perform the HMAC Tests.
|
|
*
|
|
* reqfn is the pathname of the input REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
hmac_test(char *reqfn)
|
|
{
|
|
unsigned int i, j;
|
|
size_t bufSize = 400; /* MAX buffer size */
|
|
char *buf = NULL; /* holds one line from the input REQUEST file.*/
|
|
unsigned int keyLen = 0; /* Key Length */
|
|
unsigned char key[200]; /* key MAX size = 184 */
|
|
unsigned int msgLen = 128; /* the length of the input */
|
|
/* Message is always 128 Bytes */
|
|
unsigned char *msg = NULL; /* holds the message to digest.*/
|
|
unsigned int HMACLen = 0; /* the length of the HMAC Bytes */
|
|
unsigned int TLen = 0; /* the length of the requested */
|
|
/* truncated HMAC Bytes */
|
|
unsigned char HMAC[HASH_LENGTH_MAX]; /* computed HMAC */
|
|
unsigned char expectedHMAC[HASH_LENGTH_MAX]; /* for .fax files that have */
|
|
/* supplied known answer */
|
|
HASH_HashType hash_alg = HASH_AlgNULL; /* HMAC type */
|
|
|
|
FILE *req = NULL; /* input stream from the REQUEST file */
|
|
FILE *resp; /* output stream to the RESPONSE file */
|
|
|
|
buf = PORT_ZAlloc(bufSize);
|
|
if (buf == NULL) {
|
|
goto loser;
|
|
}
|
|
msg = PORT_ZAlloc(msgLen);
|
|
if (msg == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
req = fopen(reqfn, "r");
|
|
resp = stdout;
|
|
while (fgets(buf, bufSize, req) != NULL) {
|
|
if (strncmp(buf, "Mac", 3) == 0) {
|
|
i = 3;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
memset(expectedHMAC, 0, HASH_LENGTH_MAX);
|
|
for (j = 0; isxdigit(buf[i]); i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &expectedHMAC[j]);
|
|
}
|
|
if (memcmp(HMAC, expectedHMAC, TLen) != 0) {
|
|
fprintf(stderr, "Generate failed:\n");
|
|
fputs(" expected=", stderr);
|
|
to_hex_str(buf, expectedHMAC,
|
|
TLen);
|
|
fputs(buf, stderr);
|
|
fputs("\n generated=", stderr);
|
|
to_hex_str(buf, HMAC,
|
|
TLen);
|
|
fputs(buf, stderr);
|
|
fputc('\n', stderr);
|
|
}
|
|
}
|
|
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* [L = Length of the MAC and HASH_type */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(&buf[1], "L ", 1) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
/* HMACLen will get reused for Tlen */
|
|
HMACLen = atoi(&buf[i]);
|
|
hash_alg = sha_get_hashType(HMACLen * PR_BITS_PER_BYTE);
|
|
if (hash_alg == HASH_AlgNULL) {
|
|
goto loser;
|
|
}
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
}
|
|
/* Count = test iteration number*/
|
|
if (strncmp(buf, "Count ", 5) == 0) {
|
|
/* count can just be put into resp file */
|
|
fputs(buf, resp);
|
|
/* zeroize the variables for the test with this data set */
|
|
keyLen = 0;
|
|
TLen = 0;
|
|
memset(key, 0, sizeof key);
|
|
memset(msg, 0, msgLen);
|
|
memset(HMAC, 0, sizeof HMAC);
|
|
continue;
|
|
}
|
|
/* KLen = Length of the Input Secret Key ... */
|
|
if (strncmp(buf, "Klen", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
keyLen = atoi(&buf[i]); /* in bytes */
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* key = the secret key for the key to MAC */
|
|
if (strncmp(buf, "Key", 3) == 0) {
|
|
i = 3;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < keyLen; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &key[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
}
|
|
/* TLen = Length of the calculated HMAC */
|
|
if (strncmp(buf, "Tlen", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
TLen = atoi(&buf[i]); /* in bytes */
|
|
fputs(buf, resp);
|
|
continue;
|
|
}
|
|
/* MSG = to HMAC always 128 bytes for these tests */
|
|
if (strncmp(buf, "Msg", 3) == 0) {
|
|
i = 3;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < msgLen; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &msg[j]);
|
|
}
|
|
fputs(buf, resp);
|
|
/* calculate the HMAC and output */
|
|
if (hmac_calc(HMAC, HMACLen, key, keyLen,
|
|
msg, msgLen, hash_alg) != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
fputs("Mac = ", resp);
|
|
to_hex_str(buf, HMAC, TLen);
|
|
fputs(buf, resp);
|
|
fputc('\n', resp);
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
if (req) {
|
|
fclose(req);
|
|
}
|
|
if (buf) {
|
|
PORT_ZFree(buf, bufSize);
|
|
}
|
|
if (msg) {
|
|
PORT_ZFree(msg, msgLen);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Perform the DSA Key Pair Generation Test.
|
|
*
|
|
* reqfn is the pathname of the REQUEST file.
|
|
*
|
|
* The output RESPONSE file is written to stdout.
|
|
*/
|
|
void
|
|
dsa_keypair_test(char *reqfn)
|
|
{
|
|
char buf[800]; /* holds one line from the input REQUEST file
|
|
* or to the output RESPONSE file.
|
|
* 800 to hold (384 public key (x2 for HEX) + 1'\n'
|
|
*/
|
|
FILE *dsareq; /* input stream from the REQUEST file */
|
|
FILE *dsaresp; /* output stream to the RESPONSE file */
|
|
int count;
|
|
int N;
|
|
int L;
|
|
int i;
|
|
PQGParams *pqg = NULL;
|
|
PQGVerify *vfy = NULL;
|
|
PRBool use_dsa1 = PR_FALSE;
|
|
int keySizeIndex; /* index for valid key sizes */
|
|
|
|
dsareq = fopen(reqfn, "r");
|
|
dsaresp = stdout;
|
|
while (fgets(buf, sizeof buf, dsareq) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, dsaresp);
|
|
continue;
|
|
}
|
|
|
|
/* [Mod = x] */
|
|
if (buf[0] == '[') {
|
|
if (pqg != NULL) {
|
|
PQG_DestroyParams(pqg);
|
|
pqg = NULL;
|
|
}
|
|
if (vfy != NULL) {
|
|
PQG_DestroyVerify(vfy);
|
|
vfy = NULL;
|
|
}
|
|
|
|
if (sscanf(buf, "[mod = L=%d, N=%d]", &L, &N) != 2) {
|
|
use_dsa1 = PR_TRUE;
|
|
if (sscanf(buf, "[mod = %d]", &L) != 1) {
|
|
goto loser;
|
|
}
|
|
}
|
|
fputs(buf, dsaresp);
|
|
fputc('\n', dsaresp);
|
|
|
|
if (use_dsa1) {
|
|
/*************************************************************
|
|
* PQG_ParamGenSeedLen doesn't take a key size, it takes an
|
|
* index that points to a valid key size.
|
|
*/
|
|
keySizeIndex = PQG_PBITS_TO_INDEX(L);
|
|
if (keySizeIndex == -1 || L < 512 || L > 1024) {
|
|
fprintf(dsaresp,
|
|
"DSA key size must be a multiple of 64 between 512 "
|
|
"and 1024, inclusive");
|
|
goto loser;
|
|
}
|
|
|
|
/* Generate the parameters P, Q, and G */
|
|
if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES,
|
|
&pqg, &vfy) !=
|
|
SECSuccess) {
|
|
fprintf(dsaresp,
|
|
"ERROR: Unable to generate PQG parameters");
|
|
goto loser;
|
|
}
|
|
} else {
|
|
if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) {
|
|
fprintf(dsaresp,
|
|
"ERROR: Unable to generate PQG parameters");
|
|
goto loser;
|
|
}
|
|
}
|
|
|
|
/* output P, Q, and G */
|
|
to_hex_str(buf, pqg->prime.data, pqg->prime.len);
|
|
fprintf(dsaresp, "P = %s\n", buf);
|
|
to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len);
|
|
fprintf(dsaresp, "Q = %s\n", buf);
|
|
to_hex_str(buf, pqg->base.data, pqg->base.len);
|
|
fprintf(dsaresp, "G = %s\n\n", buf);
|
|
continue;
|
|
}
|
|
/* N = ...*/
|
|
if (buf[0] == 'N') {
|
|
|
|
if (sscanf(buf, "N = %d", &count) != 1) {
|
|
goto loser;
|
|
}
|
|
/* Generate a DSA key, and output the key pair for N times */
|
|
for (i = 0; i < count; i++) {
|
|
DSAPrivateKey *dsakey = NULL;
|
|
if (DSA_NewKey(pqg, &dsakey) != SECSuccess) {
|
|
fprintf(dsaresp, "ERROR: Unable to generate DSA key");
|
|
goto loser;
|
|
}
|
|
to_hex_str(buf, dsakey->privateValue.data,
|
|
dsakey->privateValue.len);
|
|
fprintf(dsaresp, "X = %s\n", buf);
|
|
to_hex_str(buf, dsakey->publicValue.data,
|
|
dsakey->publicValue.len);
|
|
fprintf(dsaresp, "Y = %s\n\n", buf);
|
|
PORT_FreeArena(dsakey->params.arena, PR_TRUE);
|
|
dsakey = NULL;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(dsareq);
|
|
}
|
|
|
|
/*
|
|
* pqg generation type
|
|
*/
|
|
typedef enum {
|
|
FIPS186_1, /* Generate/Verify P,Q & G according to FIPS 186-1 */
|
|
A_1_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;
|
|
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;
|
|
int output_g = 1;
|
|
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) {
|
|
fprintf(stderr, "NSS does Generate Probablistic Primes\n");
|
|
exit(1);
|
|
} else if (strncmp(&buf[1], "A.2.1", 5) == 0) {
|
|
type = A_1_2_1;
|
|
output_g = 1;
|
|
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) {
|
|
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;
|
|
}
|
|
|
|
/* [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 (strncmp(buf, "Num", 3) == 0) {
|
|
if (sscanf(buf, "Num = %d", &count) != 1) {
|
|
goto loser;
|
|
}
|
|
} else 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);
|
|
if (output_g) {
|
|
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 {
|
|
unsigned int seedlen = vfy->seed.len / 2;
|
|
unsigned int pgen_counter = vfy->counter >> 16;
|
|
unsigned int qgen_counter = vfy->counter & 0xffff;
|
|
/*fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]); */
|
|
to_hex_str(buf, vfy->seed.data, seedlen);
|
|
fprintf(dsaresp, "pseed = %s\n", buf);
|
|
to_hex_str(buf, vfy->seed.data + seedlen, seedlen);
|
|
fprintf(dsaresp, "qseed = %s\n", buf);
|
|
fprintf(dsaresp, "pgen_counter = %d\n", pgen_counter);
|
|
fprintf(dsaresp, "qgen_counter = %d\n", qgen_counter);
|
|
if (output_g) {
|
|
to_hex_str(buf, vfy->seed.data, vfy->seed.len);
|
|
fprintf(dsaresp, "domain_parameter_seed = %s\n", buf);
|
|
fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]);
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void
|
|
pad(unsigned char *buf, int pad_len, unsigned char *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);
|
|
}
|
|
|
|
offset = pad_len - src_len;
|
|
memset(buf, 0, offset);
|
|
memcpy(buf + offset, src, src_len);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* 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'
|
|
*/
|
|
unsigned char 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;
|
|
unsigned char 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') {
|
|
|
|
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++) {
|
|
RSAPrivateKey *rsakey = NULL;
|
|
if ((rsakey = RSA_NewKey(keySize, &e)) == NULL) {
|
|
fprintf(rsaresp, "ERROR: Unable to generate RSA key");
|
|
goto loser;
|
|
}
|
|
pad(buf2, len, rsakey->publicExponent.data,
|
|
rsakey->publicExponent.len);
|
|
to_hex_str(buf, buf2, len);
|
|
fprintf(rsaresp, "e = %s\n", buf);
|
|
pad(buf2, len2, rsakey->prime1.data,
|
|
rsakey->prime1.len);
|
|
to_hex_str(buf, buf2, len2);
|
|
fprintf(rsaresp, "p = %s\n", buf);
|
|
pad(buf2, len2, rsakey->prime2.data,
|
|
rsakey->prime2.len);
|
|
to_hex_str(buf, buf2, len2);
|
|
fprintf(rsaresp, "q = %s\n", buf);
|
|
pad(buf2, len, rsakey->modulus.data,
|
|
rsakey->modulus.len);
|
|
to_hex_str(buf, buf2, len);
|
|
fprintf(rsaresp, "n = %s\n", buf);
|
|
pad(buf2, len, rsakey->privateExponent.data,
|
|
rsakey->privateExponent.len);
|
|
to_hex_str(buf, buf2, len);
|
|
fprintf(rsaresp, "d = %s\n", buf);
|
|
fprintf(rsaresp, "\n");
|
|
PORT_FreeArena(rsakey->arena, PR_TRUE);
|
|
rsakey = NULL;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
loser:
|
|
fclose(rsareq);
|
|
}
|
|
|
|
/*
|
|
* 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 */
|
|
shaAlg = hash_string_to_hashType(&buf[i]);
|
|
if (shaAlg == HASH_AlgNULL) {
|
|
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 */
|
|
shaAlg = hash_string_to_hashType(&buf[i]);
|
|
if (shaAlg == HASH_AlgNULL) {
|
|
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);
|
|
|
|
shaOid = fips_hashOid(shaAlg);
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
void
|
|
tls(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".
|
|
*/
|
|
unsigned char *pms = NULL;
|
|
int pms_len;
|
|
unsigned char *master_secret = NULL;
|
|
unsigned char *key_block = NULL;
|
|
int key_block_len;
|
|
unsigned char serverHello_random[SSL3_RANDOM_LENGTH];
|
|
unsigned char clientHello_random[SSL3_RANDOM_LENGTH];
|
|
unsigned char server_random[SSL3_RANDOM_LENGTH];
|
|
unsigned char client_random[SSL3_RANDOM_LENGTH];
|
|
FILE *tlsreq = NULL; /* input stream from the REQUEST file */
|
|
FILE *tlsresp; /* output stream to the RESPONSE file */
|
|
unsigned int i, j;
|
|
CK_SLOT_ID slotList[10];
|
|
CK_SLOT_ID slotID;
|
|
CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]);
|
|
CK_ULONG count;
|
|
static const CK_C_INITIALIZE_ARGS pk11args = {
|
|
NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS,
|
|
(void *)"flags=readOnly,noCertDB,noModDB", NULL
|
|
};
|
|
static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY;
|
|
static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET;
|
|
static CK_BBOOL ck_true = CK_TRUE;
|
|
static CK_ULONG one = 1;
|
|
CK_ATTRIBUTE create_template[] = {
|
|
{ CKA_VALUE, NULL, 0 },
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
};
|
|
CK_ULONG create_template_count =
|
|
sizeof(create_template) / sizeof(create_template[0]);
|
|
CK_ATTRIBUTE derive_template[] = {
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
{ CKA_VALUE_LEN, &one, sizeof(one) },
|
|
};
|
|
CK_ULONG derive_template_count =
|
|
sizeof(derive_template) / sizeof(derive_template[0]);
|
|
CK_ATTRIBUTE master_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE kb1_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE kb2_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
|
|
CK_MECHANISM master_mech = { CKM_TLS_MASTER_KEY_DERIVE, NULL, 0 };
|
|
CK_MECHANISM key_block_mech = { CKM_TLS_KEY_AND_MAC_DERIVE, NULL, 0 };
|
|
CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params;
|
|
CK_TLS12_KEY_MAT_PARAMS key_block_params;
|
|
CK_SSL3_KEY_MAT_OUT key_material;
|
|
CK_RV crv;
|
|
|
|
/* set up PKCS #11 parameters */
|
|
master_params.prfHashMechanism = CKM_SHA256;
|
|
master_params.pVersion = NULL;
|
|
master_params.RandomInfo.pClientRandom = clientHello_random;
|
|
master_params.RandomInfo.ulClientRandomLen = sizeof(clientHello_random);
|
|
master_params.RandomInfo.pServerRandom = serverHello_random;
|
|
master_params.RandomInfo.ulServerRandomLen = sizeof(serverHello_random);
|
|
master_mech.pParameter = (void *)&master_params;
|
|
master_mech.ulParameterLen = sizeof(master_params);
|
|
key_block_params.prfHashMechanism = CKM_SHA256;
|
|
key_block_params.ulMacSizeInBits = 0;
|
|
key_block_params.ulKeySizeInBits = 0;
|
|
key_block_params.ulIVSizeInBits = 0;
|
|
key_block_params.bIsExport = PR_FALSE; /* ignored anyway for TLS mech */
|
|
key_block_params.RandomInfo.pClientRandom = client_random;
|
|
key_block_params.RandomInfo.ulClientRandomLen = sizeof(client_random);
|
|
key_block_params.RandomInfo.pServerRandom = server_random;
|
|
key_block_params.RandomInfo.ulServerRandomLen = sizeof(server_random);
|
|
key_block_params.pReturnedKeyMaterial = &key_material;
|
|
key_block_mech.pParameter = (void *)&key_block_params;
|
|
key_block_mech.ulParameterLen = sizeof(key_block_params);
|
|
|
|
crv = NSC_Initialize((CK_VOID_PTR)&pk11args);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)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", (unsigned int)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);
|
|
} else if (buf[7] == '2') {
|
|
if (strncmp(&buf[10], "SHA-1", 5) == 0) {
|
|
master_params.prfHashMechanism = CKM_SHA_1;
|
|
key_block_params.prfHashMechanism = CKM_SHA_1;
|
|
} else if (strncmp(&buf[10], "SHA-224", 7) == 0) {
|
|
master_params.prfHashMechanism = CKM_SHA224;
|
|
key_block_params.prfHashMechanism = CKM_SHA224;
|
|
} else if (strncmp(&buf[10], "SHA-256", 7) == 0) {
|
|
master_params.prfHashMechanism = CKM_SHA256;
|
|
key_block_params.prfHashMechanism = CKM_SHA256;
|
|
} else if (strncmp(&buf[10], "SHA-384", 7) == 0) {
|
|
master_params.prfHashMechanism = CKM_SHA384;
|
|
key_block_params.prfHashMechanism = CKM_SHA384;
|
|
} else if (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",
|
|
(unsigned int)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(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(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(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(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(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",
|
|
(unsigned int)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",
|
|
(unsigned int)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",
|
|
(unsigned int)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",
|
|
(unsigned int)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",
|
|
(unsigned int)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",
|
|
(unsigned int)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",
|
|
(unsigned int)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".
|
|
*/
|
|
unsigned char *gxy = NULL;
|
|
int gxy_len;
|
|
unsigned char *Ni = NULL;
|
|
int Ni_len;
|
|
unsigned char *Nr = NULL;
|
|
int Nr_len;
|
|
unsigned char CKYi[8];
|
|
int CKYi_len;
|
|
unsigned char CKYr[8];
|
|
int CKYr_len;
|
|
unsigned int i, j;
|
|
FILE *ikereq = NULL; /* input stream from the REQUEST file */
|
|
FILE *ikeresp; /* output stream to the RESPONSE file */
|
|
|
|
CK_SLOT_ID slotList[10];
|
|
CK_SLOT_ID slotID;
|
|
CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]);
|
|
CK_ULONG count;
|
|
static const CK_C_INITIALIZE_ARGS pk11args = {
|
|
NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS,
|
|
(void *)"flags=readOnly,noCertDB,noModDB", NULL
|
|
};
|
|
static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY;
|
|
static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET;
|
|
static CK_BBOOL ck_true = CK_TRUE;
|
|
static CK_ULONG keyLen = 1;
|
|
CK_ATTRIBUTE gxy_template[] = {
|
|
{ CKA_VALUE, NULL, 0 }, /* must be first */
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
};
|
|
CK_ULONG gxy_template_count =
|
|
sizeof(gxy_template) / sizeof(gxy_template[0]);
|
|
CK_ATTRIBUTE derive_template[] = {
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
{ CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }, /* must be last */
|
|
};
|
|
CK_ULONG derive_template_count =
|
|
sizeof(derive_template) / sizeof(derive_template[0]);
|
|
CK_ATTRIBUTE skeyid_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE skeyid_d_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE skeyid_a_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE skeyid_e_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
unsigned char skeyid_secret[HASH_LENGTH_MAX];
|
|
unsigned char skeyid_d_secret[HASH_LENGTH_MAX];
|
|
unsigned char skeyid_a_secret[HASH_LENGTH_MAX];
|
|
unsigned char skeyid_e_secret[HASH_LENGTH_MAX];
|
|
|
|
CK_MECHANISM ike_mech = { CKM_NSS_IKE_PRF_DERIVE, NULL, 0 };
|
|
CK_MECHANISM ike1_mech = { CKM_NSS_IKE1_PRF_DERIVE, NULL, 0 };
|
|
CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf;
|
|
CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf;
|
|
CK_RV crv;
|
|
|
|
/* set up PKCS #11 parameters */
|
|
ike_prf.bDataAsKey = PR_TRUE;
|
|
ike_prf.bRekey = PR_FALSE;
|
|
ike_prf.hNewKey = CK_INVALID_HANDLE;
|
|
CKYi_len = sizeof(CKYi);
|
|
CKYr_len = sizeof(CKYr);
|
|
ike1_prf.pCKYi = CKYi;
|
|
ike1_prf.ulCKYiLen = CKYi_len;
|
|
ike1_prf.pCKYr = CKYr;
|
|
ike1_prf.ulCKYrLen = CKYr_len;
|
|
ike_mech.pParameter = &ike_prf;
|
|
ike_mech.ulParameterLen = sizeof(ike_prf);
|
|
ike1_mech.pParameter = &ike1_prf;
|
|
ike1_mech.ulParameterLen = sizeof(ike1_prf);
|
|
skeyid_template.pValue = skeyid_secret;
|
|
skeyid_template.ulValueLen = HASH_LENGTH_MAX;
|
|
skeyid_d_template.pValue = skeyid_d_secret;
|
|
skeyid_d_template.ulValueLen = HASH_LENGTH_MAX;
|
|
skeyid_a_template.pValue = skeyid_a_secret;
|
|
skeyid_a_template.ulValueLen = HASH_LENGTH_MAX;
|
|
skeyid_e_template.pValue = skeyid_e_secret;
|
|
skeyid_e_template.ulValueLen = HASH_LENGTH_MAX;
|
|
|
|
crv = NSC_Initialize((CK_VOID_PTR)&pk11args);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)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", (unsigned int)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];
|
|
ikereq = fopen(reqfn, "r");
|
|
ikeresp = stdout;
|
|
while (fgets(buf, sizeof buf, ikereq) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* [.....] */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(buf, "[SHA-1]", 7) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA_1_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA_1_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-224]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA224_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA224_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-256]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA256_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA256_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-384]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA384_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA384_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-512]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA512_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA512_HMAC;
|
|
}
|
|
if (strncmp(buf, "[AES-XCBC", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_AES_XCBC_MAC;
|
|
ike1_prf.prfMechanism = CKM_AES_XCBC_MAC;
|
|
}
|
|
if (strncmp(buf, "[g^xy", 5) == 0) {
|
|
if (sscanf(buf, "[g^xy length = %d]",
|
|
&gxy_len) != 1) {
|
|
goto loser;
|
|
}
|
|
gxy_len = gxy_len / 8;
|
|
if (gxy)
|
|
free(gxy);
|
|
gxy = malloc(gxy_len);
|
|
gxy_template[0].pValue = gxy;
|
|
gxy_template[0].ulValueLen = gxy_len;
|
|
}
|
|
if (strncmp(buf, "[Ni", 3) == 0) {
|
|
if (sscanf(buf, "[Ni length = %d]", &Ni_len) != 1) {
|
|
goto loser;
|
|
}
|
|
Ni_len = Ni_len / 8;
|
|
if (Ni)
|
|
free(Ni);
|
|
Ni = malloc(Ni_len);
|
|
ike_prf.pNi = Ni;
|
|
ike_prf.ulNiLen = Ni_len;
|
|
}
|
|
if (strncmp(buf, "[Nr", 3) == 0) {
|
|
if (sscanf(buf, "[Nr length = %d]", &Nr_len) != 1) {
|
|
goto loser;
|
|
}
|
|
Nr_len = Nr_len / 8;
|
|
if (Nr)
|
|
free(Nr);
|
|
Nr = malloc(Nr_len);
|
|
ike_prf.pNr = Nr;
|
|
ike_prf.ulNrLen = Nr_len;
|
|
}
|
|
fputs(buf, ikeresp);
|
|
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(gxy, 0, gxy_len);
|
|
memset(Ni, 0, Ni_len);
|
|
memset(Nr, 0, Nr_len);
|
|
memset(CKYi, 0, CKYi_len);
|
|
memset(CKYr, 0, CKYr_len);
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* Ni = ... */
|
|
if (strncmp(buf, "Ni", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < Ni_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Ni[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* Nr = ... */
|
|
if (strncmp(buf, "Nr", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < Nr_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Nr[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* CKYi = ... */
|
|
if (strncmp(buf, "CKY_I", 5) == 0) {
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < CKYi_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &CKYi[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* CKYr = ... */
|
|
if (strncmp(buf, "CKY_R", 5) == 0) {
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < CKYr_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &CKYr[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* g^xy = ... */
|
|
if (strncmp(buf, "g^xy", 4) == 0) {
|
|
CK_SESSION_HANDLE session;
|
|
CK_OBJECT_HANDLE gxy_handle;
|
|
CK_OBJECT_HANDLE skeyid_handle;
|
|
CK_OBJECT_HANDLE skeyid_d_handle;
|
|
CK_OBJECT_HANDLE skeyid_a_handle;
|
|
CK_OBJECT_HANDLE skeyid_e_handle;
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < gxy_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &gxy[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_CreateObject(session, gxy_template,
|
|
gxy_template_count, &gxy_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_CreateObject failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
/* get the skeyid key */
|
|
crv = NSC_DeriveKey(session, &ike_mech, gxy_handle,
|
|
derive_template, derive_template_count - 1,
|
|
&skeyid_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
skeyid_template.ulValueLen = HASH_LENGTH_MAX;
|
|
crv = NSC_GetAttributeValue(session, skeyid_handle,
|
|
&skeyid_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
/* use the length of the skeyid to set the target length of all the
|
|
* other keys */
|
|
keyLen = skeyid_template.ulValueLen;
|
|
ike1_prf.hKeygxy = gxy_handle;
|
|
ike1_prf.bHasPrevKey = PR_FALSE;
|
|
ike1_prf.keyNumber = 0;
|
|
crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle,
|
|
derive_template, derive_template_count,
|
|
&skeyid_d_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid_d) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
|
|
ike1_prf.hKeygxy = gxy_handle;
|
|
ike1_prf.bHasPrevKey = CK_TRUE;
|
|
ike1_prf.hPrevKey = skeyid_d_handle;
|
|
ike1_prf.keyNumber = 1;
|
|
crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle,
|
|
derive_template, derive_template_count,
|
|
&skeyid_a_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid_a) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
ike1_prf.hKeygxy = gxy_handle;
|
|
ike1_prf.bHasPrevKey = CK_TRUE;
|
|
ike1_prf.hPrevKey = skeyid_a_handle;
|
|
ike1_prf.keyNumber = 2;
|
|
crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle,
|
|
derive_template, derive_template_count,
|
|
&skeyid_e_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid_e) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID = ", ikeresp);
|
|
to_hex_str(buf, skeyid_secret, keyLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
skeyid_d_template.ulValueLen = keyLen;
|
|
crv = NSC_GetAttributeValue(session, skeyid_d_handle,
|
|
&skeyid_d_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid_d) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID_d = ", ikeresp);
|
|
to_hex_str(buf, skeyid_d_secret, skeyid_d_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
skeyid_a_template.ulValueLen = keyLen;
|
|
crv = NSC_GetAttributeValue(session, skeyid_a_handle,
|
|
&skeyid_a_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid_a) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID_a = ", ikeresp);
|
|
to_hex_str(buf, skeyid_a_secret, skeyid_a_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
skeyid_e_template.ulValueLen = keyLen;
|
|
crv = NSC_GetAttributeValue(session, skeyid_e_handle,
|
|
&skeyid_e_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid_e) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID_e = ", ikeresp);
|
|
to_hex_str(buf, skeyid_e_secret, skeyid_e_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
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".
|
|
*/
|
|
unsigned char *gxy = NULL;
|
|
int gxy_len;
|
|
unsigned char *Ni = NULL;
|
|
int Ni_len;
|
|
unsigned char *Nr = NULL;
|
|
int Nr_len;
|
|
unsigned char CKYi[8];
|
|
int CKYi_len;
|
|
unsigned char CKYr[8];
|
|
int CKYr_len;
|
|
unsigned char *psk = NULL;
|
|
int psk_len;
|
|
unsigned int i, j;
|
|
FILE *ikereq = NULL; /* input stream from the REQUEST file */
|
|
FILE *ikeresp; /* output stream to the RESPONSE file */
|
|
|
|
CK_SLOT_ID slotList[10];
|
|
CK_SLOT_ID slotID;
|
|
CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]);
|
|
CK_ULONG count;
|
|
static const CK_C_INITIALIZE_ARGS pk11args = {
|
|
NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS,
|
|
(void *)"flags=readOnly,noCertDB,noModDB", NULL
|
|
};
|
|
static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY;
|
|
static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET;
|
|
static CK_BBOOL ck_true = CK_TRUE;
|
|
static CK_ULONG keyLen = 1;
|
|
CK_ATTRIBUTE gxy_template[] = {
|
|
{ CKA_VALUE, NULL, 0 }, /* must be first */
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
};
|
|
CK_ULONG gxy_template_count =
|
|
sizeof(gxy_template) / sizeof(gxy_template[0]);
|
|
CK_ATTRIBUTE psk_template[] = {
|
|
{ CKA_VALUE, NULL, 0 }, /* must be first */
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
};
|
|
CK_ULONG psk_template_count =
|
|
sizeof(psk_template) / sizeof(psk_template[0]);
|
|
CK_ATTRIBUTE derive_template[] = {
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
{ CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }, /* must be last */
|
|
};
|
|
CK_ULONG derive_template_count =
|
|
sizeof(derive_template) / sizeof(derive_template[0]);
|
|
CK_ATTRIBUTE skeyid_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE skeyid_d_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE skeyid_a_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE skeyid_e_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
unsigned char skeyid_secret[HASH_LENGTH_MAX];
|
|
unsigned char skeyid_d_secret[HASH_LENGTH_MAX];
|
|
unsigned char skeyid_a_secret[HASH_LENGTH_MAX];
|
|
unsigned char skeyid_e_secret[HASH_LENGTH_MAX];
|
|
|
|
CK_MECHANISM ike_mech = { CKM_NSS_IKE_PRF_DERIVE, NULL, 0 };
|
|
CK_MECHANISM ike1_mech = { CKM_NSS_IKE1_PRF_DERIVE, NULL, 0 };
|
|
CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf;
|
|
CK_NSS_IKE1_PRF_DERIVE_PARAMS ike1_prf;
|
|
CK_RV crv;
|
|
|
|
/* set up PKCS #11 parameters */
|
|
ike_prf.bDataAsKey = PR_FALSE;
|
|
ike_prf.bRekey = PR_FALSE;
|
|
ike_prf.hNewKey = CK_INVALID_HANDLE;
|
|
CKYi_len = 8;
|
|
CKYr_len = 8;
|
|
ike1_prf.pCKYi = CKYi;
|
|
ike1_prf.ulCKYiLen = CKYi_len;
|
|
ike1_prf.pCKYr = CKYr;
|
|
ike1_prf.ulCKYrLen = CKYr_len;
|
|
ike_mech.pParameter = &ike_prf;
|
|
ike_mech.ulParameterLen = sizeof(ike_prf);
|
|
ike1_mech.pParameter = &ike1_prf;
|
|
ike1_mech.ulParameterLen = sizeof(ike1_prf);
|
|
skeyid_template.pValue = skeyid_secret;
|
|
skeyid_template.ulValueLen = HASH_LENGTH_MAX;
|
|
skeyid_d_template.pValue = skeyid_d_secret;
|
|
skeyid_d_template.ulValueLen = HASH_LENGTH_MAX;
|
|
skeyid_a_template.pValue = skeyid_a_secret;
|
|
skeyid_a_template.ulValueLen = HASH_LENGTH_MAX;
|
|
skeyid_e_template.pValue = skeyid_e_secret;
|
|
skeyid_e_template.ulValueLen = HASH_LENGTH_MAX;
|
|
|
|
crv = NSC_Initialize((CK_VOID_PTR)&pk11args);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)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", (unsigned int)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];
|
|
ikereq = fopen(reqfn, "r");
|
|
ikeresp = stdout;
|
|
while (fgets(buf, sizeof buf, ikereq) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* [.....] */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(buf, "[SHA-1]", 7) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA_1_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA_1_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-224]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA224_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA224_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-256]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA256_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA256_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-384]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA384_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA384_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-512]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA512_HMAC;
|
|
ike1_prf.prfMechanism = CKM_SHA512_HMAC;
|
|
}
|
|
if (strncmp(buf, "[AES-XCBC", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_AES_XCBC_MAC;
|
|
ike1_prf.prfMechanism = CKM_AES_XCBC_MAC;
|
|
}
|
|
if (strncmp(buf, "[g^xy", 5) == 0) {
|
|
if (sscanf(buf, "[g^xy length = %d]",
|
|
&gxy_len) != 1) {
|
|
goto loser;
|
|
}
|
|
gxy_len = gxy_len / 8;
|
|
if (gxy)
|
|
free(gxy);
|
|
gxy = malloc(gxy_len);
|
|
gxy_template[0].pValue = gxy;
|
|
gxy_template[0].ulValueLen = gxy_len;
|
|
}
|
|
if (strncmp(buf, "[pre-shared-key", 15) == 0) {
|
|
if (sscanf(buf, "[pre-shared-key length = %d]",
|
|
&psk_len) != 1) {
|
|
goto loser;
|
|
}
|
|
psk_len = psk_len / 8;
|
|
if (psk)
|
|
free(psk);
|
|
psk = malloc(psk_len);
|
|
psk_template[0].pValue = psk;
|
|
psk_template[0].ulValueLen = psk_len;
|
|
}
|
|
if (strncmp(buf, "[Ni", 3) == 0) {
|
|
if (sscanf(buf, "[Ni length = %d]", &Ni_len) != 1) {
|
|
goto loser;
|
|
}
|
|
Ni_len = Ni_len / 8;
|
|
if (Ni)
|
|
free(Ni);
|
|
Ni = malloc(Ni_len);
|
|
ike_prf.pNi = Ni;
|
|
ike_prf.ulNiLen = Ni_len;
|
|
}
|
|
if (strncmp(buf, "[Nr", 3) == 0) {
|
|
if (sscanf(buf, "[Nr length = %d]", &Nr_len) != 1) {
|
|
goto loser;
|
|
}
|
|
Nr_len = Nr_len / 8;
|
|
if (Nr)
|
|
free(Nr);
|
|
Nr = malloc(Nr_len);
|
|
ike_prf.pNr = Nr;
|
|
ike_prf.ulNrLen = Nr_len;
|
|
}
|
|
fputs(buf, ikeresp);
|
|
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(gxy, 0, gxy_len);
|
|
memset(Ni, 0, Ni_len);
|
|
memset(Nr, 0, Nr_len);
|
|
memset(CKYi, 0, CKYi_len);
|
|
memset(CKYr, 0, CKYr_len);
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* Ni = ... */
|
|
if (strncmp(buf, "Ni", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < Ni_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Ni[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* Nr = ... */
|
|
if (strncmp(buf, "Nr", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < Nr_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Nr[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* CKYi = ... */
|
|
if (strncmp(buf, "CKY_I", 5) == 0) {
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < CKYi_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &CKYi[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* CKYr = ... */
|
|
if (strncmp(buf, "CKY_R", 5) == 0) {
|
|
i = 5;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < CKYr_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &CKYr[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* g^xy = ... */
|
|
if (strncmp(buf, "g^xy", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < gxy_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &gxy[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* pre-shared-key = ... */
|
|
if (strncmp(buf, "pre-shared-key", 14) == 0) {
|
|
CK_SESSION_HANDLE session;
|
|
CK_OBJECT_HANDLE gxy_handle;
|
|
CK_OBJECT_HANDLE psk_handle;
|
|
CK_OBJECT_HANDLE skeyid_handle;
|
|
CK_OBJECT_HANDLE skeyid_d_handle;
|
|
CK_OBJECT_HANDLE skeyid_a_handle;
|
|
CK_OBJECT_HANDLE skeyid_e_handle;
|
|
i = 14;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < psk_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &psk[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_CreateObject(session, psk_template,
|
|
psk_template_count, &psk_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_CreateObject(psk) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_CreateObject(session, gxy_template,
|
|
gxy_template_count, &gxy_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_CreateObject(gxy) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
/* get the skeyid key */
|
|
crv = NSC_DeriveKey(session, &ike_mech, psk_handle,
|
|
derive_template, derive_template_count - 1,
|
|
&skeyid_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
skeyid_template.ulValueLen = HASH_LENGTH_MAX;
|
|
crv = NSC_GetAttributeValue(session, skeyid_handle,
|
|
&skeyid_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
/* use the length of the skeyid to set the target length of all the
|
|
* other keys */
|
|
keyLen = skeyid_template.ulValueLen;
|
|
ike1_prf.hKeygxy = gxy_handle;
|
|
ike1_prf.bHasPrevKey = PR_FALSE;
|
|
ike1_prf.keyNumber = 0;
|
|
crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle,
|
|
derive_template, derive_template_count,
|
|
&skeyid_d_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid_d) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
|
|
ike1_prf.hKeygxy = gxy_handle;
|
|
ike1_prf.bHasPrevKey = CK_TRUE;
|
|
ike1_prf.hPrevKey = skeyid_d_handle;
|
|
ike1_prf.keyNumber = 1;
|
|
crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle,
|
|
derive_template, derive_template_count,
|
|
&skeyid_a_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid_a) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
ike1_prf.hKeygxy = gxy_handle;
|
|
ike1_prf.bHasPrevKey = CK_TRUE;
|
|
ike1_prf.hPrevKey = skeyid_a_handle;
|
|
ike1_prf.keyNumber = 2;
|
|
crv = NSC_DeriveKey(session, &ike1_mech, skeyid_handle,
|
|
derive_template, derive_template_count,
|
|
&skeyid_e_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid_e) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID = ", ikeresp);
|
|
to_hex_str(buf, skeyid_secret, keyLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
skeyid_d_template.ulValueLen = keyLen;
|
|
crv = NSC_GetAttributeValue(session, skeyid_d_handle,
|
|
&skeyid_d_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid_d) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID_d = ", ikeresp);
|
|
to_hex_str(buf, skeyid_d_secret, skeyid_d_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
skeyid_a_template.ulValueLen = keyLen;
|
|
crv = NSC_GetAttributeValue(session, skeyid_a_handle,
|
|
&skeyid_a_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid_a) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID_a = ", ikeresp);
|
|
to_hex_str(buf, skeyid_a_secret, skeyid_a_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
skeyid_e_template.ulValueLen = keyLen;
|
|
crv = NSC_GetAttributeValue(session, skeyid_e_handle,
|
|
&skeyid_e_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid_e) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYID_e = ", ikeresp);
|
|
to_hex_str(buf, skeyid_e_secret, skeyid_e_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
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".
|
|
*/
|
|
unsigned char *gir = NULL;
|
|
unsigned char *gir_new = NULL;
|
|
int gir_len;
|
|
unsigned char *Ni = NULL;
|
|
int Ni_len;
|
|
unsigned char *Nr = NULL;
|
|
int Nr_len;
|
|
unsigned char *SPIi = NULL;
|
|
int SPIi_len = 8;
|
|
unsigned char *SPIr = NULL;
|
|
int SPIr_len = 8;
|
|
unsigned char *DKM = NULL;
|
|
int DKM_len;
|
|
unsigned char *DKM_child = NULL;
|
|
int DKM_child_len;
|
|
unsigned char *seed_data = NULL;
|
|
int seed_data_len = 0;
|
|
unsigned int i, j;
|
|
FILE *ikereq = NULL; /* input stream from the REQUEST file */
|
|
FILE *ikeresp; /* output stream to the RESPONSE file */
|
|
|
|
CK_SLOT_ID slotList[10];
|
|
CK_SLOT_ID slotID;
|
|
CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]);
|
|
CK_ULONG count;
|
|
static const CK_C_INITIALIZE_ARGS pk11args = {
|
|
NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS,
|
|
(void *)"flags=readOnly,noCertDB,noModDB", NULL
|
|
};
|
|
static CK_OBJECT_CLASS ck_secret = CKO_SECRET_KEY;
|
|
static CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET;
|
|
static CK_BBOOL ck_true = CK_TRUE;
|
|
static CK_ULONG keyLen = 1;
|
|
CK_ATTRIBUTE gir_template[] = {
|
|
{ CKA_VALUE, NULL, 0 },
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
};
|
|
CK_ULONG gir_template_count =
|
|
sizeof(gir_template) / sizeof(gir_template[0]);
|
|
CK_ATTRIBUTE gir_new_template[] = {
|
|
{ CKA_VALUE, NULL, 0 },
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
};
|
|
CK_ULONG gir_new_template_count =
|
|
sizeof(gir_new_template) / sizeof(gir_new_template[0]);
|
|
CK_ATTRIBUTE derive_template[] = {
|
|
{ CKA_CLASS, &ck_secret, sizeof(ck_secret) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
{ CKA_VALUE_LEN, &keyLen, sizeof(keyLen) },
|
|
};
|
|
CK_ULONG derive_template_count =
|
|
sizeof(derive_template) / sizeof(derive_template[0]);
|
|
CK_ATTRIBUTE skeyseed_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE dkm_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
CK_ATTRIBUTE dkm_child_template =
|
|
{ CKA_VALUE, NULL, 0 };
|
|
unsigned char skeyseed_secret[HASH_LENGTH_MAX];
|
|
|
|
CK_MECHANISM ike_mech = { CKM_NSS_IKE_PRF_DERIVE, NULL, 0 };
|
|
CK_MECHANISM ike2_mech = { CKM_NSS_IKE_PRF_PLUS_DERIVE, NULL, 0 };
|
|
CK_MECHANISM subset_mech = { CKM_EXTRACT_KEY_FROM_KEY, NULL, 0 };
|
|
CK_NSS_IKE_PRF_DERIVE_PARAMS ike_prf;
|
|
CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS ike2_prf;
|
|
CK_EXTRACT_PARAMS subset_params;
|
|
CK_RV crv;
|
|
|
|
/* set up PKCS #11 parameters */
|
|
ike_mech.pParameter = &ike_prf;
|
|
ike_mech.ulParameterLen = sizeof(ike_prf);
|
|
ike2_mech.pParameter = &ike2_prf;
|
|
ike2_mech.ulParameterLen = sizeof(ike2_prf);
|
|
subset_mech.pParameter = &subset_params;
|
|
subset_mech.ulParameterLen = sizeof(subset_params);
|
|
subset_params = 0;
|
|
skeyseed_template.pValue = skeyseed_secret;
|
|
skeyseed_template.ulValueLen = HASH_LENGTH_MAX;
|
|
|
|
crv = NSC_Initialize((CK_VOID_PTR)&pk11args);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)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", (unsigned int)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];
|
|
ikereq = fopen(reqfn, "r");
|
|
ikeresp = stdout;
|
|
while (fgets(buf, sizeof buf, ikereq) != NULL) {
|
|
/* a comment or blank line */
|
|
if (buf[0] == '#' || buf[0] == '\n') {
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* [.....] */
|
|
if (buf[0] == '[') {
|
|
if (strncmp(buf, "[SHA-1]", 7) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA_1_HMAC;
|
|
ike2_prf.prfMechanism = CKM_SHA_1_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-224]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA224_HMAC;
|
|
ike2_prf.prfMechanism = CKM_SHA224_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-256]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA256_HMAC;
|
|
ike2_prf.prfMechanism = CKM_SHA256_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-384]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA384_HMAC;
|
|
ike2_prf.prfMechanism = CKM_SHA384_HMAC;
|
|
}
|
|
if (strncmp(buf, "[SHA-512]", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_SHA512_HMAC;
|
|
ike2_prf.prfMechanism = CKM_SHA512_HMAC;
|
|
}
|
|
if (strncmp(buf, "[AES-XCBC", 9) == 0) {
|
|
ike_prf.prfMechanism = CKM_AES_XCBC_MAC;
|
|
ike2_prf.prfMechanism = CKM_AES_XCBC_MAC;
|
|
}
|
|
if (strncmp(buf, "[g^ir", 5) == 0) {
|
|
if (sscanf(buf, "[g^ir length = %d]",
|
|
&gir_len) != 1) {
|
|
goto loser;
|
|
}
|
|
gir_len = gir_len / 8;
|
|
if (gir)
|
|
free(gir);
|
|
if (gir_new)
|
|
free(gir_new);
|
|
gir = malloc(gir_len);
|
|
gir_new = malloc(gir_len);
|
|
gir_template[0].pValue = gir;
|
|
gir_template[0].ulValueLen = gir_len;
|
|
gir_new_template[0].pValue = gir_new;
|
|
gir_new_template[0].ulValueLen = gir_len;
|
|
}
|
|
if (strncmp(buf, "[Ni", 3) == 0) {
|
|
if (sscanf(buf, "[Ni length = %d]", &Ni_len) != 1) {
|
|
goto loser;
|
|
}
|
|
Ni_len = Ni_len / 8;
|
|
}
|
|
if (strncmp(buf, "[Nr", 3) == 0) {
|
|
if (sscanf(buf, "[Nr length = %d]", &Nr_len) != 1) {
|
|
goto loser;
|
|
}
|
|
Nr_len = Nr_len / 8;
|
|
}
|
|
if (strncmp(buf, "[DKM", 4) == 0) {
|
|
if (sscanf(buf, "[DKM length = %d]",
|
|
&DKM_len) != 1) {
|
|
goto loser;
|
|
}
|
|
DKM_len = DKM_len / 8;
|
|
if (DKM)
|
|
free(DKM);
|
|
DKM = malloc(DKM_len);
|
|
dkm_template.pValue = DKM;
|
|
dkm_template.ulValueLen = DKM_len;
|
|
}
|
|
if (strncmp(buf, "[Child SA DKM", 13) == 0) {
|
|
if (sscanf(buf, "[Child SA DKM length = %d]",
|
|
&DKM_child_len) != 1) {
|
|
goto loser;
|
|
}
|
|
DKM_child_len = DKM_child_len / 8;
|
|
if (DKM_child)
|
|
free(DKM_child);
|
|
DKM_child = malloc(DKM_child_len);
|
|
dkm_child_template.pValue = DKM_child;
|
|
dkm_child_template.ulValueLen = DKM_child_len;
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* "COUNT = x" begins a new data set */
|
|
if (strncmp(buf, "COUNT", 5) == 0) {
|
|
/* zeroize the variables for the test with this data set */
|
|
int new_seed_len = Ni_len + Nr_len + SPIi_len + SPIr_len;
|
|
if (seed_data_len != new_seed_len) {
|
|
if (seed_data)
|
|
free(seed_data);
|
|
seed_data_len = new_seed_len;
|
|
seed_data = malloc(seed_data_len);
|
|
Ni = seed_data;
|
|
Nr = &seed_data[Ni_len];
|
|
SPIi = &seed_data[Ni_len + Nr_len];
|
|
SPIr = &seed_data[new_seed_len - SPIr_len];
|
|
ike_prf.pNi = Ni;
|
|
ike_prf.ulNiLen = Ni_len;
|
|
ike_prf.pNr = Nr;
|
|
ike_prf.ulNrLen = Nr_len;
|
|
ike2_prf.pSeedData = seed_data;
|
|
}
|
|
memset(gir, 0, gir_len);
|
|
memset(gir_new, 0, gir_len);
|
|
memset(seed_data, 0, seed_data_len);
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* Ni = ... */
|
|
if (strncmp(buf, "Ni", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < Ni_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Ni[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* Nr = ... */
|
|
if (strncmp(buf, "Nr", 2) == 0) {
|
|
i = 2;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < Nr_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &Nr[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* g^ir (new) = ... */
|
|
if (strncmp(buf, "g^ir (new)", 10) == 0) {
|
|
i = 10;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < gir_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &gir_new[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* g^ir = ... */
|
|
if (strncmp(buf, "g^ir", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < gir_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &gir[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* SPIi = ... */
|
|
if (strncmp(buf, "SPIi", 4) == 0) {
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < SPIi_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &SPIi[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
continue;
|
|
}
|
|
/* SPIr = ... */
|
|
if (strncmp(buf, "SPIr", 4) == 0) {
|
|
CK_SESSION_HANDLE session;
|
|
CK_OBJECT_HANDLE gir_handle;
|
|
CK_OBJECT_HANDLE gir_new_handle;
|
|
CK_OBJECT_HANDLE skeyseed_handle;
|
|
CK_OBJECT_HANDLE sk_d_handle;
|
|
CK_OBJECT_HANDLE skeyseed_new_handle;
|
|
CK_OBJECT_HANDLE dkm_handle;
|
|
CK_OBJECT_HANDLE dkm_child_handle;
|
|
i = 4;
|
|
while (isspace(buf[i]) || buf[i] == '=') {
|
|
i++;
|
|
}
|
|
for (j = 0; j < SPIr_len; i += 2, j++) {
|
|
hex_to_byteval(&buf[i], &SPIr[j]);
|
|
}
|
|
fputs(buf, ikeresp);
|
|
crv = NSC_OpenSession(slotID, 0, NULL, NULL, &session);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_OpenSession failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_CreateObject(session, gir_template,
|
|
gir_template_count, &gir_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_CreateObject (g^ir) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_CreateObject(session, gir_new_template,
|
|
gir_new_template_count, &gir_new_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_CreateObject (g^ir new) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
/* get the SKEYSEED key */
|
|
ike_prf.bDataAsKey = CK_TRUE;
|
|
ike_prf.bRekey = CK_FALSE;
|
|
ike_prf.hNewKey = CK_INVALID_HANDLE;
|
|
crv = NSC_DeriveKey(session, &ike_mech, gir_handle,
|
|
derive_template, derive_template_count - 1,
|
|
&skeyseed_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
skeyseed_template.ulValueLen = HASH_LENGTH_MAX;
|
|
crv = NSC_GetAttributeValue(session, skeyseed_handle,
|
|
&skeyseed_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYSEED = ", ikeresp);
|
|
to_hex_str(buf, skeyseed_secret, skeyseed_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
/* get DKM */
|
|
keyLen = DKM_len;
|
|
ike2_prf.bHasSeedKey = CK_FALSE;
|
|
ike2_prf.hSeedKey = CK_INVALID_HANDLE;
|
|
ike2_prf.ulSeedDataLen = seed_data_len;
|
|
crv = NSC_DeriveKey(session, &ike2_mech, skeyseed_handle,
|
|
derive_template, derive_template_count,
|
|
&dkm_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(DKM) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_GetAttributeValue(session, dkm_handle,
|
|
&dkm_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(DKM) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("DKM = ", ikeresp);
|
|
to_hex_str(buf, DKM, DKM_len);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
/* get the sk_d from the DKM */
|
|
keyLen = skeyseed_template.ulValueLen;
|
|
crv = NSC_DeriveKey(session, &subset_mech, dkm_handle,
|
|
derive_template, derive_template_count,
|
|
&sk_d_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(sk_d) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
|
|
/* get DKM child */
|
|
keyLen = DKM_child_len;
|
|
ike2_prf.bHasSeedKey = CK_FALSE;
|
|
ike2_prf.hSeedKey = CK_INVALID_HANDLE;
|
|
ike2_prf.ulSeedDataLen = Ni_len + Nr_len;
|
|
crv = NSC_DeriveKey(session, &ike2_mech, sk_d_handle,
|
|
derive_template, derive_template_count,
|
|
&dkm_child_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(DKM Child SA) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_GetAttributeValue(session, dkm_child_handle,
|
|
&dkm_child_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(DKM Child SA) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("DKM(Child SA) = ", ikeresp);
|
|
to_hex_str(buf, DKM_child, DKM_child_len);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
/* get DKM child D-H*/
|
|
keyLen = DKM_child_len;
|
|
ike2_prf.bHasSeedKey = CK_TRUE;
|
|
ike2_prf.hSeedKey = gir_new_handle;
|
|
ike2_prf.ulSeedDataLen = Ni_len + Nr_len;
|
|
crv = NSC_DeriveKey(session, &ike2_mech, sk_d_handle,
|
|
derive_template, derive_template_count,
|
|
&dkm_child_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(DKM Child SA D-H) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
crv = NSC_GetAttributeValue(session, dkm_child_handle,
|
|
&dkm_child_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(DKM Child SA D-H) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("DKM(Child SA D-H) = ", ikeresp);
|
|
to_hex_str(buf, DKM_child, DKM_child_len);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
/* get SKEYSEED(rekey) */
|
|
ike_prf.bDataAsKey = CK_FALSE;
|
|
ike_prf.bRekey = CK_TRUE;
|
|
ike_prf.hNewKey = gir_new_handle;
|
|
crv = NSC_DeriveKey(session, &ike_mech, sk_d_handle,
|
|
derive_template, derive_template_count - 1,
|
|
&skeyseed_new_handle);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(skeyid rekey) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
skeyseed_template.ulValueLen = HASH_LENGTH_MAX;
|
|
crv = NSC_GetAttributeValue(session, skeyseed_new_handle,
|
|
&skeyseed_template, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(skeyid) failed crv=0x%x\n",
|
|
(unsigned int)crv);
|
|
goto loser;
|
|
}
|
|
fputs("SKEYSEED(rekey) = ", ikeresp);
|
|
to_hex_str(buf, skeyseed_secret, skeyseed_template.ulValueLen);
|
|
fputs(buf, ikeresp);
|
|
fputc('\n', ikeresp);
|
|
|
|
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;
|
|
unsigned char KI[64];
|
|
unsigned int KI_len = 64;
|
|
unsigned char KO[300];
|
|
unsigned int KO_len = 300;
|
|
/* This is used only with feedback mode. */
|
|
unsigned char IV[64];
|
|
unsigned int IV_len = 64;
|
|
/* These are only used in counter mode with counter location as
|
|
* MIDDLE_FIXED. */
|
|
unsigned char BeforeFixedInputData[50];
|
|
unsigned int BeforeFixedInputData_len = 50;
|
|
unsigned char AfterFixedInputData[10];
|
|
unsigned int AfterFixedInputData_len = 10;
|
|
/* These are used with every KDF type. */
|
|
unsigned char FixedInputData[60];
|
|
unsigned int FixedInputData_len = 60;
|
|
|
|
/* Counter locations:
|
|
*
|
|
* 0: not used
|
|
* 1: beginning
|
|
* 2: middle
|
|
* 3: end */
|
|
int ctr_location = 0;
|
|
CK_ULONG counter_bitlen = 0;
|
|
|
|
size_t buf_offset;
|
|
size_t offset;
|
|
|
|
FILE *kbkdf_req = NULL;
|
|
FILE *kbkdf_resp = NULL;
|
|
|
|
/* == PKCS#11 data == */
|
|
CK_RV crv;
|
|
|
|
CK_SLOT_ID slotList[10];
|
|
CK_SLOT_ID slotID;
|
|
CK_ULONG slotListCount = sizeof(slotList) / sizeof(slotList[0]);
|
|
CK_ULONG slotCount = 0;
|
|
|
|
CK_MECHANISM kdf = { 0 };
|
|
|
|
CK_MECHANISM_TYPE prf_mech = 0;
|
|
CK_BBOOL ck_true = CK_TRUE;
|
|
|
|
/* We never need more than 3 data parameters. */
|
|
CK_PRF_DATA_PARAM dataParams[3];
|
|
CK_ULONG dataParams_len = 3;
|
|
|
|
CK_SP800_108_COUNTER_FORMAT iterator = { CK_FALSE, 0 };
|
|
|
|
CK_SP800_108_KDF_PARAMS kdfParams = { 0 };
|
|
CK_SP800_108_FEEDBACK_KDF_PARAMS feedbackParams = { 0 };
|
|
|
|
CK_OBJECT_CLASS ck_secret_key = CKO_SECRET_KEY;
|
|
CK_KEY_TYPE ck_generic = CKK_GENERIC_SECRET;
|
|
|
|
CK_ATTRIBUTE prf_template[] = {
|
|
{ CKA_VALUE, &KI, sizeof(KI) },
|
|
{ CKA_CLASS, &ck_secret_key, sizeof(ck_secret_key) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) }
|
|
};
|
|
CK_ULONG prf_template_count = sizeof(prf_template) / sizeof(prf_template[0]);
|
|
|
|
CK_ATTRIBUTE derive_template[] = {
|
|
{ CKA_CLASS, &ck_secret_key, sizeof(ck_secret_key) },
|
|
{ CKA_KEY_TYPE, &ck_generic, sizeof(ck_generic) },
|
|
{ CKA_DERIVE, &ck_true, sizeof(ck_true) },
|
|
{ CKA_VALUE_LEN, &L, sizeof(L) }
|
|
};
|
|
CK_ULONG derive_template_count = sizeof(derive_template) / sizeof(derive_template[0]);
|
|
|
|
CK_ATTRIBUTE output_key = { CKA_VALUE, KO, KO_len };
|
|
|
|
const CK_C_INITIALIZE_ARGS pk11args = {
|
|
NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS,
|
|
(void *)"flags=readOnly,noCertDB,noModDB", NULL
|
|
};
|
|
|
|
/* == Start up PKCS#11 == */
|
|
crv = NSC_Initialize((CK_VOID_PTR)&pk11args);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)crv);
|
|
goto done;
|
|
}
|
|
|
|
slotCount = slotListCount;
|
|
crv = NSC_GetSlotList(PR_TRUE, slotList, &slotCount);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetSlotList failed crv=0x%x\n", (unsigned int)crv);
|
|
goto done;
|
|
}
|
|
if ((slotCount > slotListCount) || slotCount < 1) {
|
|
fprintf(stderr,
|
|
"NSC_GetSlotList returned too many or too few slots: %d slots max=%d min=1\n",
|
|
(int)slotCount, (int)slotListCount);
|
|
goto done;
|
|
}
|
|
slotID = slotList[0];
|
|
|
|
/* == Start parsing the file == */
|
|
kbkdf_req = fopen(path, "r");
|
|
kbkdf_resp = stdout;
|
|
|
|
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;
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
|
|
/* [....] - context directive */
|
|
if (buf[0] == '[') {
|
|
/* PRF begins each new section. */
|
|
if (strncmp(buf, "[PRF=CMAC_AES128]", 17) == 0) {
|
|
prf_mech = CKM_AES_CMAC;
|
|
KI_len = 16;
|
|
} else if (strncmp(buf, "[PRF=CMAC_AES192]", 17) == 0) {
|
|
prf_mech = CKM_AES_CMAC;
|
|
KI_len = 24;
|
|
} else if (strncmp(buf, "[PRF=CMAC_AES256]", 17) == 0) {
|
|
prf_mech = CKM_AES_CMAC;
|
|
KI_len = 32;
|
|
} else if (strncmp(buf, "[PRF=HMAC_SHA1]", 15) == 0) {
|
|
prf_mech = CKM_SHA_1_HMAC;
|
|
KI_len = 20;
|
|
} else if (strncmp(buf, "[PRF=HMAC_SHA224]", 17) == 0) {
|
|
prf_mech = CKM_SHA224_HMAC;
|
|
KI_len = 28;
|
|
} else if (strncmp(buf, "[PRF=HMAC_SHA256]", 17) == 0) {
|
|
prf_mech = CKM_SHA256_HMAC;
|
|
KI_len = 32;
|
|
} else if (strncmp(buf, "[PRF=HMAC_SHA384]", 17) == 0) {
|
|
prf_mech = CKM_SHA384_HMAC;
|
|
KI_len = 48;
|
|
} else if (strncmp(buf, "[PRF=HMAC_SHA512]", 17) == 0) {
|
|
prf_mech = CKM_SHA512_HMAC;
|
|
KI_len = 64;
|
|
} else if (strncmp(buf, "[PRF=", 5) == 0) {
|
|
fprintf(stderr, "Invalid or unsupported PRF mechanism: %s\n", buf);
|
|
goto done;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "IV = ", 5) == 0) {
|
|
buf_offset = 5;
|
|
|
|
for (offset = 0; offset < IV_len; offset++, buf_offset += 2) {
|
|
hex_to_byteval(buf + buf_offset, IV + offset);
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
|
|
/* We might have DataBeforeCtr and DataAfterCtr if present. */
|
|
if (strncmp(buf, "DataBeforeCtrLen = ", 19) == 0) {
|
|
if (sscanf(buf, "DataBeforeCtrLen = %u", &BeforeFixedInputData_len) != 1) {
|
|
goto done;
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "DataBeforeCtrData = ", 20) == 0) {
|
|
buf_offset = 20;
|
|
|
|
for (offset = 0; offset < BeforeFixedInputData_len; offset++, buf_offset += 2) {
|
|
hex_to_byteval(buf + buf_offset, BeforeFixedInputData + offset);
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "DataAfterCtrLen = ", 18) == 0) {
|
|
if (sscanf(buf, "DataAfterCtrLen = %u", &AfterFixedInputData_len) != 1) {
|
|
goto done;
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "DataAfterCtrData = ", 19) == 0) {
|
|
buf_offset = 19;
|
|
|
|
for (offset = 0; offset < AfterFixedInputData_len; offset++, buf_offset += 2) {
|
|
hex_to_byteval(buf + buf_offset, AfterFixedInputData + offset);
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
|
|
/* Otherwise, we might have FixedInputData, if present. */
|
|
if (strncmp(buf, "FixedInputDataByteLen = ", 24) == 0) {
|
|
if (sscanf(buf, "FixedInputDataByteLen = %u", &FixedInputData_len) != 1) {
|
|
goto done;
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
if (strncmp(buf, "FixedInputData = ", 17) == 0) {
|
|
buf_offset = 17;
|
|
|
|
for (offset = 0; offset < FixedInputData_len; offset++, buf_offset += 2) {
|
|
hex_to_byteval(buf + buf_offset, FixedInputData + offset);
|
|
}
|
|
|
|
fputs(buf, kbkdf_resp);
|
|
continue;
|
|
}
|
|
|
|
/* 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", (unsigned int)crv);
|
|
goto done;
|
|
}
|
|
|
|
/* Create the PRF key object. */
|
|
prf_template[0].ulValueLen = KI_len;
|
|
crv = NSC_CreateObject(session, prf_template, prf_template_count, &prf_key);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_CreateObject (prf_key) failed crv=0x%x\n", (unsigned int)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;
|
|
|
|
if (ctr_location == 0 || ctr_location > 3) {
|
|
fprintf(stderr, "Expected ctr_location != 0 for Counter Mode KDF but got 0.\n");
|
|
goto done;
|
|
} else if (ctr_location == 1) {
|
|
/* Counter before */
|
|
dataParams[0].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[0].pValue = &iterator;
|
|
dataParams[0].ulValueLen = sizeof(iterator);
|
|
|
|
dataParams[1].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[1].pValue = FixedInputData;
|
|
dataParams[1].ulValueLen = FixedInputData_len;
|
|
|
|
dataParams_len = 2;
|
|
} else if (ctr_location == 2) {
|
|
/* Counter between */
|
|
dataParams[0].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[0].pValue = BeforeFixedInputData;
|
|
dataParams[0].ulValueLen = BeforeFixedInputData_len;
|
|
|
|
dataParams[1].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[1].pValue = &iterator;
|
|
dataParams[1].ulValueLen = sizeof(iterator);
|
|
|
|
dataParams[2].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[2].pValue = AfterFixedInputData;
|
|
dataParams[2].ulValueLen = AfterFixedInputData_len;
|
|
|
|
dataParams_len = 3;
|
|
} else {
|
|
/* Counter after */
|
|
dataParams[0].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[0].pValue = FixedInputData;
|
|
dataParams[0].ulValueLen = FixedInputData_len;
|
|
|
|
dataParams[1].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[1].pValue = &iterator;
|
|
dataParams[1].ulValueLen = sizeof(iterator);
|
|
|
|
dataParams_len = 2;
|
|
}
|
|
} else if (kdf.mechanism == CKM_SP800_108_FEEDBACK_KDF || kdf.mechanism == CKM_SP800_108_DOUBLE_PIPELINE_KDF) {
|
|
/* When counter_bitlen != 0, we have an optional counter. */
|
|
if (counter_bitlen != 0) {
|
|
iterator.ulWidthInBits = counter_bitlen;
|
|
|
|
if (ctr_location == 0 || ctr_location > 3) {
|
|
fprintf(stderr, "Expected ctr_location != 0 for Counter Mode KDF but got 0.\n");
|
|
goto done;
|
|
} else if (ctr_location == 1) {
|
|
/* Counter before */
|
|
dataParams[0].type = CK_SP800_108_OPTIONAL_COUNTER;
|
|
dataParams[0].pValue = &iterator;
|
|
dataParams[0].ulValueLen = sizeof(iterator);
|
|
|
|
dataParams[1].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[1].pValue = NULL;
|
|
dataParams[1].ulValueLen = 0;
|
|
|
|
dataParams[2].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[2].pValue = FixedInputData;
|
|
dataParams[2].ulValueLen = FixedInputData_len;
|
|
|
|
dataParams_len = 3;
|
|
} else if (ctr_location == 2) {
|
|
/* Counter between */
|
|
dataParams[0].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[0].pValue = NULL;
|
|
dataParams[0].ulValueLen = 0;
|
|
|
|
dataParams[1].type = CK_SP800_108_OPTIONAL_COUNTER;
|
|
dataParams[1].pValue = &iterator;
|
|
dataParams[1].ulValueLen = sizeof(iterator);
|
|
|
|
dataParams[2].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[2].pValue = FixedInputData;
|
|
dataParams[2].ulValueLen = FixedInputData_len;
|
|
|
|
dataParams_len = 3;
|
|
} else {
|
|
/* Counter after */
|
|
dataParams[0].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[0].pValue = NULL;
|
|
dataParams[0].ulValueLen = 0;
|
|
|
|
dataParams[1].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[1].pValue = FixedInputData;
|
|
dataParams[1].ulValueLen = FixedInputData_len;
|
|
|
|
dataParams[2].type = CK_SP800_108_OPTIONAL_COUNTER;
|
|
dataParams[2].pValue = &iterator;
|
|
dataParams[2].ulValueLen = sizeof(iterator);
|
|
|
|
dataParams_len = 3;
|
|
}
|
|
} else {
|
|
dataParams[0].type = CK_SP800_108_ITERATION_VARIABLE;
|
|
dataParams[0].pValue = NULL;
|
|
dataParams[0].ulValueLen = 0;
|
|
|
|
dataParams[1].type = CK_SP800_108_BYTE_ARRAY;
|
|
dataParams[1].pValue = FixedInputData;
|
|
dataParams[1].ulValueLen = FixedInputData_len;
|
|
|
|
dataParams_len = 2;
|
|
}
|
|
}
|
|
|
|
if (kdf.mechanism != CKM_SP800_108_FEEDBACK_KDF) {
|
|
kdfParams.prfType = prf_mech;
|
|
kdfParams.ulNumberOfDataParams = dataParams_len;
|
|
kdfParams.pDataParams = dataParams;
|
|
|
|
kdf.pParameter = &kdfParams;
|
|
kdf.ulParameterLen = sizeof(kdfParams);
|
|
} else {
|
|
feedbackParams.prfType = prf_mech;
|
|
feedbackParams.ulNumberOfDataParams = dataParams_len;
|
|
feedbackParams.pDataParams = dataParams;
|
|
feedbackParams.ulIVLen = IV_len;
|
|
if (IV_len == 0) {
|
|
feedbackParams.pIV = NULL;
|
|
} else {
|
|
feedbackParams.pIV = IV;
|
|
}
|
|
|
|
kdf.pParameter = &feedbackParams;
|
|
kdf.ulParameterLen = sizeof(feedbackParams);
|
|
}
|
|
|
|
crv = NSC_DeriveKey(session, &kdf, prf_key, derive_template, derive_template_count, &derived_key);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_DeriveKey(derived_key) failed crv=0x%x\n", (unsigned int)crv);
|
|
goto done;
|
|
}
|
|
|
|
crv = NSC_GetAttributeValue(session, derived_key, &output_key, 1);
|
|
if (crv != CKR_OK) {
|
|
fprintf(stderr, "NSC_GetAttribute(derived_value) failed crv=0x%x\n", (unsigned int)crv);
|
|
goto done;
|
|
}
|
|
|
|
fputs("KO = ", kbkdf_resp);
|
|
to_hex_str(buf, KO, output_key.ulValueLen);
|
|
fputs(buf, kbkdf_resp);
|
|
fputs("\r\n", kbkdf_resp);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (kbkdf_req != NULL) {
|
|
fclose(kbkdf_req);
|
|
}
|
|
if (kbkdf_resp != stdout && kbkdf_resp != NULL) {
|
|
fclose(kbkdf_resp);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
exit(-1);
|
|
|
|
RNG_RNGInit();
|
|
SECOID_Init();
|
|
|
|
/*************/
|
|
/* TDEA */
|
|
/*************/
|
|
if (strcmp(argv[1], "tdea") == 0) {
|
|
/* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
|
|
if (strcmp(argv[2], "kat") == 0) {
|
|
/* Known Answer Test (KAT) */
|
|
tdea_kat_mmt(argv[4]);
|
|
} else if (strcmp(argv[2], "mmt") == 0) {
|
|
/* Multi-block Message Test (MMT) */
|
|
tdea_kat_mmt(argv[4]);
|
|
} else if (strcmp(argv[2], "mct") == 0) {
|
|
/* Monte Carlo Test (MCT) */
|
|
if (strcmp(argv[3], "ecb") == 0) {
|
|
/* ECB mode */
|
|
tdea_mct(NSS_DES_EDE3, argv[4]);
|
|
} else if (strcmp(argv[3], "cbc") == 0) {
|
|
/* CBC mode */
|
|
tdea_mct(NSS_DES_EDE3_CBC, argv[4]);
|
|
}
|
|
}
|
|
/*************/
|
|
/* AES */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "aes") == 0) {
|
|
/* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */
|
|
if (strcmp(argv[2], "kat") == 0) {
|
|
/* Known Answer Test (KAT) */
|
|
aes_kat_mmt(argv[4]);
|
|
} else if (strcmp(argv[2], "mmt") == 0) {
|
|
/* Multi-block Message Test (MMT) */
|
|
aes_kat_mmt(argv[4]);
|
|
} else if (strcmp(argv[2], "gcm") == 0) {
|
|
if (strcmp(argv[3], "decrypt") == 0) {
|
|
aes_gcm(argv[4], 0);
|
|
} else if (strcmp(argv[3], "encrypt_extiv") == 0) {
|
|
aes_gcm(argv[4], 1);
|
|
} else if (strcmp(argv[3], "encrypt_intiv") == 0) {
|
|
aes_gcm(argv[4], 2);
|
|
}
|
|
} else if (strcmp(argv[2], "mct") == 0) {
|
|
/* Monte Carlo Test (MCT) */
|
|
if (strcmp(argv[3], "ecb") == 0) {
|
|
/* ECB mode */
|
|
aes_ecb_mct(argv[4]);
|
|
} else if (strcmp(argv[3], "cbc") == 0) {
|
|
/* CBC mode */
|
|
aes_cbc_mct(argv[4]);
|
|
}
|
|
}
|
|
/*************/
|
|
/* SHA */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "sha") == 0) {
|
|
sha_test(argv[2]);
|
|
/*************/
|
|
/* RSA */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "rsa") == 0) {
|
|
/* argv[2]=siggen|sigver */
|
|
/* argv[3]=<test name>.req */
|
|
if (strcmp(argv[2], "siggen") == 0) {
|
|
/* Signature Generation Test */
|
|
rsa_siggen_test(argv[3]);
|
|
} else if (strcmp(argv[2], "sigver") == 0) {
|
|
/* Signature Verification Test */
|
|
rsa_sigver_test(argv[3]);
|
|
} else if (strcmp(argv[2], "keypair") == 0) {
|
|
/* Key Pair Generation Test */
|
|
rsa_keypair_test(argv[3]);
|
|
}
|
|
/*************/
|
|
/* HMAC */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "hmac") == 0) {
|
|
hmac_test(argv[2]);
|
|
/*************/
|
|
/* DSA */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "dsa") == 0) {
|
|
/* argv[2]=keypair|pqggen|pqgver|siggen|sigver */
|
|
/* argv[3]=<test name>.req */
|
|
if (strcmp(argv[2], "keypair") == 0) {
|
|
/* Key Pair Generation Test */
|
|
dsa_keypair_test(argv[3]);
|
|
} else if (strcmp(argv[2], "pqggen") == 0) {
|
|
/* Domain Parameter Generation Test */
|
|
dsa_pqggen_test(argv[3]);
|
|
} else if (strcmp(argv[2], "pqgver") == 0) {
|
|
/* Domain Parameter Validation Test */
|
|
dsa_pqgver_test(argv[3]);
|
|
} else if (strcmp(argv[2], "siggen") == 0) {
|
|
/* Signature Generation Test */
|
|
dsa_siggen_test(argv[3]);
|
|
} else if (strcmp(argv[2], "sigver") == 0) {
|
|
/* Signature Verification Test */
|
|
dsa_sigver_test(argv[3]);
|
|
}
|
|
/*************/
|
|
/* ECDSA */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "ecdsa") == 0) {
|
|
/* argv[2]=keypair|pkv|siggen|sigver argv[3]=<test name>.req */
|
|
if (strcmp(argv[2], "keypair") == 0) {
|
|
/* Key Pair Generation Test */
|
|
ecdsa_keypair_test(argv[3]);
|
|
} else if (strcmp(argv[2], "pkv") == 0) {
|
|
/* Public Key Validation Test */
|
|
ecdsa_pkv_test(argv[3]);
|
|
} else if (strcmp(argv[2], "siggen") == 0) {
|
|
/* Signature Generation Test */
|
|
ecdsa_siggen_test(argv[3]);
|
|
} else if (strcmp(argv[2], "sigver") == 0) {
|
|
/* Signature Verification Test */
|
|
ecdsa_sigver_test(argv[3]);
|
|
}
|
|
/*************/
|
|
/* ECDH */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "ecdh") == 0) {
|
|
/* argv[2]={init|resp}-{func|verify} argv[3]=<test name>.req */
|
|
if (strcmp(argv[2], "init-func") == 0) {
|
|
ecdh_functional(argv[3], 0);
|
|
} else if (strcmp(argv[2], "resp-func") == 0) {
|
|
ecdh_functional(argv[3], 1);
|
|
} else if (strcmp(argv[2], "init-verify") == 0) {
|
|
ecdh_verify(argv[3], 0);
|
|
} else if (strcmp(argv[2], "resp-verify") == 0) {
|
|
ecdh_verify(argv[3], 1);
|
|
}
|
|
/*************/
|
|
/* DH */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "dh") == 0) {
|
|
/* argv[2]={init|resp}-{func|verify} argv[3]=<test name>.req */
|
|
if (strcmp(argv[2], "init-func") == 0) {
|
|
dh_functional(argv[3], 0);
|
|
} else if (strcmp(argv[2], "resp-func") == 0) {
|
|
dh_functional(argv[3], 1);
|
|
} else if (strcmp(argv[2], "init-verify") == 0) {
|
|
dh_verify(argv[3], 0);
|
|
} else if (strcmp(argv[2], "resp-verify") == 0) {
|
|
dh_verify(argv[3], 1);
|
|
}
|
|
/*************/
|
|
/* RNG */
|
|
/*************/
|
|
} else if (strcmp(argv[1], "rng") == 0) {
|
|
/* argv[2]=vst|mct argv[3]=<test name>.req */
|
|
if (strcmp(argv[2], "vst") == 0) {
|
|
/* Variable Seed Test */
|
|
rng_vst(argv[3]);
|
|
} else if (strcmp(argv[2], "mct") == 0) {
|
|
/* Monte Carlo Test */
|
|
rng_mct(argv[3]);
|
|
}
|
|
} else if (strcmp(argv[1], "drbg") == 0) {
|
|
/* Variable Seed Test */
|
|
drbg(argv[2]);
|
|
} else if (strcmp(argv[1], "ddrbg") == 0) {
|
|
debug = 1;
|
|
drbg(argv[2]);
|
|
} else if (strcmp(argv[1], "tls") == 0) {
|
|
tls(argv[2]);
|
|
} else if (strcmp(argv[1], "ikev1") == 0) {
|
|
ikev1(argv[2]);
|
|
} else if (strcmp(argv[1], "ikev1-psk") == 0) {
|
|
ikev1_psk(argv[2]);
|
|
} else if (strcmp(argv[1], "ikev2") == 0) {
|
|
ikev2(argv[2]);
|
|
} else if (strcmp(argv[1], "kbkdf") == 0) {
|
|
kbkdf(argv[2]);
|
|
}
|
|
return 0;
|
|
}
|