/* 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
0 x10001
#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)) &
0 x0f;
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((
unsigned char )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((
unsigned char )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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
0 ; isxdigit((
unsigned char )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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
0 ; isxdigit((
unsigned char )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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
8 ; isxdigit((
unsigned char )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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
16 ; isxdigit((
unsigned char )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((
unsigned char )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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
0 ; isxdigit((
unsigned char )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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
0 ; isxdigit((
unsigned char )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 */
snprintf(buf,
sizeof (buf),
"COUNT = %d\n" , i);
fputs(buf, resp);
/* Output KEY1[i] */
fputs(
"KEY1 = " , resp);
to_hex_str(buf, key,
8 );
fputs(buf, resp);
fputc(
'\n' , resp);
/* Output KEY2[i] */
fputs(
"KEY2 = " , resp);
to_hex_str(buf, &key[
8 ],
8 );
fputs(buf, resp);
fputc(
'\n' , resp);
/* Output KEY3[i] */
fputs(
"KEY3 = " , resp);
to_hex_str(buf, &key[
16 ],
8 );
fputs(buf, resp);
fputc(
'\n' , resp);
if (mode == NSS_DES_EDE3_CBC) {
/* Output CV[i] */
fputs(
"IV = " , resp);
to_hex_str(buf, iv,
8 );
fputs(buf, resp);
fputc(
'\n' , resp);
}
if (crypt == ENCRYPT) {
/* Output PT[0] */
fputs(
"PLAINTEXT = " , resp);
}
else {
/* Output CT[0] */
fputs(
"CIPHERTEXT = " , resp);
}
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((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
numKeys = atoi(&buf[i]);
continue ;
}
/* KEY1 = ... */
if (strncmp(buf,
"KEY1" ,
4 ) ==
0 ) {
i =
4 ;
while (isspace((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
0 ; isxdigit((
unsigned char )buf[i]); i +=
2 , j++) {
hex_to_byteval(&buf[i], &key[j]);
}
continue ;
}
/* KEY2 = ... */
if (strncmp(buf,
"KEY2" ,
4 ) ==
0 ) {
i =
4 ;
while (isspace((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
8 ; isxdigit((
unsigned char )buf[i]); i +=
2 , j++) {
hex_to_byteval(&buf[i], &key[j]);
}
continue ;
}
/* KEY3 = ... */
if (strncmp(buf,
"KEY3" ,
4 ) ==
0 ) {
i =
4 ;
while (isspace((
unsigned char )buf[i]) || buf[i] ==
'=' ) {
i++;
}
for (j =
16 ; isxdigit((
unsigned char )buf[i]); i +=
2 , j++) {
hex_to_byteval(&buf[i], &key[j]);
}
continue ;
}
/* IV = ... */
if (strncmp(buf,
"IV" ,
2 ) ==
0 ) {
i =
2 ;
while (isspace((
unsigned char )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((
unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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++) {
snprintf(buf, sizeof (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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )buf[i]); i += 2 , j++) {
hex_to_byteval(&buf[i], &ciphertext[j]);
}
for (i = 0 ; i < 100 ; i++) {
snprintf(buf, sizeof (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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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((unsigned char )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++) {
snprintf(buf, sizeof (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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )buf[i]); i += 2 , j++) {
hex_to_byteval(&buf[i], &ciphertext[j]);
}
for (i = 0 ; i < 100 ; i++) {
snprintf(buf, sizeof (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 0 x06 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((unsigned char )*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((unsigned char )*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((unsigned char )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((unsigned char )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((unsigned char )*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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )*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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )*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((unsigned char )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((unsigned char )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((unsigned char )*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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < pqg.prime.len; i += 2 , j++) {
if (!isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < pqg.subPrime.len; i += 2 , j++) {
if (!isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < pqg.base.len; i += 2 , j++) {
if (!isxdigit((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < pqg.prime.len; i += 2 , j++) {
if (!isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < pqg.subPrime.len; i += 2 , j++) {
if (!isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < pqg.base.len; i += 2 , j++) {
if (!isxdigit((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )*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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; j < b / 8 ; i += 2 , j++) {
hex_to_byteval(&buf[i], &XSeed[j]);
fputs(, rngresp);
k <10000 ;k++){
rv =FIPS186Change_GenerateX(XKey,XSeed, GENX);
if (rv !!= SECSuccess) {
oser;
}
}
if (!cx {
goto loser;
=FIPS186Change_ReduceModQForDSAGENX,Q, ;
if ( =S {
oto ;
}
,sizeof DSAX;
} else
ENX sizeof GENX;
}
fputs(buf (! java.lang.StringIndexOutOfBoundsException: Range [31, 32) out of bounds for length 31
putc(\', 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);
snprintf(buf, sizeof (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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
memset(expectedHMAC, 0 , HASH_LENGTH_MAX);
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = vfy.seed.len; isxdigit((unsigned char )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((unsigned char )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((unsigned char )buf[i]) || buf[i] == '=' ) {
i++;
}
for (j = 0 ; isxdigit((unsigned char )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 & 0 xffff;
/*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((unsigned char)buf[i ]) || buf[i ] == '=' ) {
i ++;
}
for (j = 0 ; isxdigit((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)buf[i ]) || buf[i ] == '=' ) {
i ++;
}
for (j = 0 ; isxdigit((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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[] = { 0 x1, 0 x0, 0 x1 };
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)
{B FH KLM OP STU java.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 55
char buf[2 * RSA_MAX_TEST_MODULUS_BYTES + 1 ];
/* buf holds one line from the input REQUEST file
* or to the output RESPONSE file.
* 2 x 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)0 xff000000L >> (i *
8 )))) {
pubEx[peCount] =
(unsigned char)((publicExponent >> (3 - i ) * 8 ) & 0 xff);
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((unsigned char)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((unsigned char)buf[i ]) || buf[i ] == '=' ) {
i ++;
}
for (j = 0 ; isxdigit((unsigned char)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 = 2 x 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((unsigned char)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((unsigned char)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((unsigned char)buf[i ]) || buf[i ] == '=' ) {
i ++;
}
/* skip leading zero's */
while (isxdigit((unsigned char)buf[i ])) {
hex_to_byteval(&buf[i ], &t);
if (t == 0 ) {
i += 2 ;
} else
break;
}
/* get the exponent */
for (j = 0 ; isxdigit((unsigned char)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((unsigned char)buf[i ]) || buf[i ] == '=' ) {
i ++;
}
for (j = 0 ; isxdigit((unsigned char)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((unsigned char)buf[i ]) || buf[i ] == '=' ) {
i ++;
}
for (j = 0 ; isxdigit((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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_IKE_PRF_DERIVE, NULL, 0 };
CK_MECHANISM ike1_mech = { CKM_IKE1_PRF_DERIVE, NULL, 0 };
CK_IKE_PRF_DERIVE_PARAMS ike_prf;
CK_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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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_IKE_PRF_DERIVE, NULL, 0 };
CK_MECHANISM ike1_mech = { CKM_IKE1_PRF_DERIVE, NULL, 0 };
CK_IKE_PRF_DERIVE_PARAMS ike_prf;
CK_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;
java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 26
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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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_IKE_PRF_DERIVE, NULL, 0 };
CK_MECHANISM ike2_mech = { CKM_IKE2_PRF_PLUS_DERIVE, NULL, 0 };
CK_MECHANISM subset_mech = { CKM_EXTRACT_KEY_FROM_KEY, NULL, 0 };
CK_IKE_PRF_DERIVE_PARAMS ike_prf;
CK_IKE2_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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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((unsigned char)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 ;
}
Messung V0.5 in Prozent C=95 H=83 G=88
¤ Dauer der Verarbeitung: 0.543 Sekunden
¤
*© Formatika GbR, Deutschland