#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <Security/cssm.h>
#include "cspwrap.h"
#include "common.h"
#include "cspdlTesting.h"
#define USAGE_NAME "noUsage"
#define USAGE_NAME_LEN (strlen(USAGE_NAME))
#define HMACSHA_MULTI_UPDATES 1
#define LOOPS_DEF 10
#define MIN_EXP 2
#define DEFAULT_MAX_EXP 2
#define MAX_EXP 5
#define INCR_DEFAULT 0
#define ALG_SHA1HMAC 1
#define ALG_MD5HMAC 2
#define ALG_FIRST ALG_SHA1HMAC
#define ALG_LAST ALG_MD5HMAC
#define MAX_DATA_SIZE (100000 + 100)
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf(" Options:\n");
printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
printf(" n=minExp (default=%d)\n", MIN_EXP);
printf(" x=maxExp (default=%d, max=%d)\n", DEFAULT_MAX_EXP, MAX_EXP);
printf(" i=increment (default=%d)\n", INCR_DEFAULT);
printf(" r(eference keys only)\n");
printf(" m (CSM mallocs MAC)\n");
printf(" p=pauseInterval (default=0, no pause)\n");
printf(" D (CSP/DL; default = bare CSP)\n");
printf(" v(erbose)\n");
printf(" q(uiet)\n");
printf(" h(elp)\n");
exit(1);
}
#define LOG_FREQ 20
static int doTest(CSSM_CSP_HANDLE cspHand,
uint32 macAlg, CSSM_DATA_PTR ptext,
CSSM_BOOL verbose,
CSSM_BOOL quiet,
unsigned keySize,
unsigned incr,
CSSM_BOOL stagedGen,
CSSM_BOOL stagedVerify,
CSSM_BOOL mallocMac,
CSSM_BOOL refKey)
{
CSSM_KEY_PTR symmKey;
CSSM_DATA mac = {0, NULL};
unsigned length;
unsigned byte;
unsigned char *data;
unsigned char origData;
unsigned char bits;
int rtn = 0;
CSSM_RETURN crtn;
uint32 keyGenAlg;
unsigned loop = 0;
switch(macAlg) {
case CSSM_ALGID_SHA1HMAC:
keyGenAlg = CSSM_ALGID_SHA1HMAC;
break;
case CSSM_ALGID_MD5HMAC:
keyGenAlg = CSSM_ALGID_MD5HMAC;
break;
default:
printf("bogus algorithm\n");
return 1;
}
symmKey = cspGenSymKey(cspHand,
keyGenAlg,
"noLabel",
7,
CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY,
keySize,
refKey);
if(symmKey == NULL) {
rtn = testError(quiet);
goto abort;
}
if(stagedGen) {
crtn = cspStagedGenMac(cspHand,
macAlg,
symmKey,
ptext,
mallocMac,
CSSM_TRUE, &mac);
}
else {
crtn = cspGenMac(cspHand,
macAlg,
symmKey,
ptext,
&mac);
}
if(crtn) {
rtn = 1;
goto abort;
}
if(stagedVerify) {
crtn = cspStagedMacVerify(cspHand,
macAlg,
symmKey,
ptext,
&mac,
CSSM_TRUE, CSSM_OK); }
else {
crtn = cspMacVerify(cspHand,
macAlg,
symmKey,
ptext,
&mac,
CSSM_OK);
}
if(crtn) {
printf("**Unexpected BAD MAC\n");
return testError(quiet);
}
data = (unsigned char *)ptext->Data;
length = ptext->Length;
for(byte=0; byte<length; byte += incr) {
if(verbose && ((loop++ % LOG_FREQ) == 0)) {
printf(" ..byte %d\n", byte);
}
origData = data[byte];
do {
bits = genRand(1, 0xff) & 0xff;
} while(bits == 0);
data[byte] ^= bits;
if(stagedVerify) {
crtn = cspStagedMacVerify(cspHand,
macAlg,
symmKey,
ptext,
&mac,
CSSM_TRUE, CSSMERR_CSP_VERIFY_FAILED); }
else {
crtn = cspMacVerify(cspHand,
macAlg,
symmKey,
ptext,
&mac,
CSSMERR_CSP_VERIFY_FAILED);
}
if(crtn) {
return testError(quiet);
}
data[byte] = origData;
}
abort:
if(cspFreeKey(cspHand, symmKey)) {
printf("Error freeing symmKey\n");
rtn = 1;
}
CSSM_FREE(mac.Data);
return rtn;
}
int main(int argc, char **argv)
{
int arg;
char *argp;
unsigned loop;
CSSM_DATA ptext;
CSSM_CSP_HANDLE CSPHandle;
CSSM_BOOL stagedSign;
CSSM_BOOL stagedVfy;
CSSM_BOOL mallocMac;
CSSM_BOOL refKey;
const char *algStr;
unsigned actualIncr;
uint32 macAlg; unsigned currAlg; int i;
int rtn = 0;
unsigned loops = LOOPS_DEF;
CSSM_BOOL verbose = CSSM_FALSE;
unsigned minExp = MIN_EXP;
unsigned maxExp = DEFAULT_MAX_EXP;
CSSM_BOOL quiet = CSSM_FALSE;
unsigned keySizeInBits = CSP_KEY_SIZE_DEFAULT;
unsigned incr = INCR_DEFAULT;
unsigned minAlg = ALG_FIRST;
uint32 maxAlg = ALG_LAST;
unsigned pauseInterval = 0;
CSSM_BOOL bareCsp = CSSM_TRUE;
CSSM_BOOL refKeysOnly = CSSM_FALSE;
CSSM_BOOL cspMallocs = CSSM_FALSE;
#if macintosh
argc = ccommand(&argv);
#endif
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'l':
loops = atoi(&argp[2]);
break;
case 'n':
minExp = atoi(&argp[2]);
break;
case 'x':
maxExp = atoi(&argp[2]);
if(maxExp > MAX_EXP) {
usage(argv);
}
break;
case 'i':
incr = atoi(&argp[2]);
break;
case 'p':
pauseInterval = atoi(&argp[2]);
break;
case 'D':
bareCsp = CSSM_FALSE;
#if CSPDL_ALL_KEYS_ARE_REF
refKeysOnly = CSSM_TRUE;
#endif
break;
case 'r':
refKeysOnly = CSSM_TRUE;
break;
case 'm':
cspMallocs = CSSM_TRUE;
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'q':
quiet = CSSM_TRUE;
break;
case 'h':
default:
usage(argv);
}
}
ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE);
if(ptext.Data == NULL) {
printf("Insufficient heap\n");
exit(1);
}
printf("Starting badmac; args: ");
for(i=1; i<argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
CSPHandle = cspDlDbStartup(bareCsp, NULL);
if(CSPHandle == 0) {
exit(1);
}
for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
switch(currAlg) {
case ALG_SHA1HMAC:
macAlg = CSSM_ALGID_SHA1HMAC;
algStr = "SHA1HMAC";
break;
case ALG_MD5HMAC:
macAlg = CSSM_ALGID_MD5HMAC;
algStr = "MD5HMAC";
break;
}
if(!quiet) {
printf("Testing alg %s\n", algStr);
}
for(loop=1; ; loop++) {
ptext.Length = genData(ptext.Data, minExp, maxExp, DT_Random);
if(!quiet) {
printf("..loop %d text size %lu\n", loop, ptext.Length);
}
if(incr == 0) {
actualIncr = (ptext.Length / 50) + 1;
}
else {
actualIncr = incr;
}
stagedSign = (loop & 1) ? CSSM_TRUE : CSSM_FALSE;
stagedVfy = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
if(refKeysOnly) {
refKey = CSSM_TRUE;
}
else {
refKey = (loop & 4) ? CSSM_TRUE : CSSM_FALSE;
}
if(cspMallocs) {
mallocMac = CSSM_FALSE;
}
else {
mallocMac = (loop & 8) ? CSSM_TRUE : CSSM_FALSE;
}
#if !HMACSHA_MULTI_UPDATES
if(macAlg == CSSM_ALGID_SHA1HMAC) {
stagedSign = stagedVfy = CSSM_FALSE;
}
#endif
if(!quiet) {
printf(" stagedSign %d stagedVfy %d refKey %d mallocMac %d\n",
(int)stagedSign, (int)stagedVfy, (int)refKey, (int)mallocMac);
}
if(doTest(CSPHandle,
macAlg,
&ptext,
verbose,
quiet,
keySizeInBits,
actualIncr,
stagedSign,
stagedVfy,
mallocMac,
refKey)) {
rtn = 1;
goto testDone;
}
if(loops && (loop == loops)) {
break;
}
if(pauseInterval && ((loop % pauseInterval) == 0)) {
fpurge(stdin);
printf("Hit CR to proceed: ");
getchar();
}
}
}
testDone:
CSSM_ModuleDetach(CSPHandle);
if((rtn == 0) && !quiet) {
printf("%s test complete\n", argv[0]);
}
return rtn;
}