#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.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 LOOPS_DEF 10
#define KEY_SIZE_DEF 1024
#define KEY_SIZE_SMALL 512
#define PTEXT_LEN 32
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(" k=keySizeInBits; default=%d\n", KEY_SIZE_DEF);
printf(" D (CSP/DL; default = bare CSP)\n");
printf(" p (pause on each loop)\n");
printf(" u (quick; small keys)\n");
printf(" v(erbose)\n");
printf(" q(uiet)\n");
printf(" h(elp)\n");
exit(1);
}
static int genRsaCryptContext(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR key,
CSSM_PADDING padding,
CSSM_BOOL quiet,
CSSM_CC_HANDLE &ccHand) {
CSSM_RETURN crtn;
CSSM_ACCESS_CREDENTIALS creds;
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
CSSM_ALGID_RSA,
&creds, key,
padding,
&ccHand);
if(crtn) {
cssmPerror("CSSM_CSP_CreateAsymmetricContext", crtn);
return testError(quiet);
}
return 0;
}
static int doRsaEncrypt(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR key,
CSSM_PADDING padding,
CSSM_BOOL quiet,
CSSM_DATA *ptext,
CSSM_DATA *ctext)
{
CSSM_CC_HANDLE ccHand;
int rtn;
CSSM_RETURN crtn;
CSSM_SIZE bytesMoved;
CSSM_DATA remData = {0, NULL};
rtn = genRsaCryptContext(cspHand, key, padding, quiet, ccHand);
if(rtn) {
return rtn;
}
crtn = CSSM_EncryptData(ccHand,
ptext,
1,
ctext,
1,
&bytesMoved,
&remData);
CSSM_DeleteContext(ccHand);
if(crtn == CSSM_OK) {
if(remData.Length != 0) {
uint8 *newCdata = (uint8 *)appMalloc(bytesMoved, NULL);
memmove(newCdata, ctext->Data, ctext->Length);
memmove(newCdata+ctext->Length, remData.Data, remData.Length);
CSSM_FREE(ctext->Data);
ctext->Data = newCdata;
}
ctext->Length = bytesMoved;
return 0;
}
else {
cssmPerror("CSSM_EncryptData", crtn);
return testError(quiet);
}
}
static int doRsaDecrypt(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR key,
CSSM_PADDING padding,
CSSM_BOOL quiet,
CSSM_RETURN expectRtn,
CSSM_DATA *ctext,
CSSM_DATA *rptext)
{
CSSM_CC_HANDLE ccHand;
int rtn;
CSSM_RETURN crtn;
CSSM_SIZE bytesMoved;
CSSM_DATA remData = {0, NULL};
rtn = genRsaCryptContext(cspHand, key, padding, quiet, ccHand);
if(rtn) {
return rtn;
}
crtn = CSSM_DecryptData(ccHand,
ctext,
1,
rptext,
1,
&bytesMoved,
&remData);
CSSM_DeleteContext(ccHand);
if(crtn != expectRtn) {
printf(" CSSM_DecryptData: expect %s\n", cssmErrToStr(expectRtn));
printf(" CSSM_DecryptData: got %s\n", cssmErrToStr(crtn));
return testError(quiet);
}
if(crtn) {
return 0;
}
if(crtn == CSSM_OK) {
if(remData.Length != 0) {
uint8 *newRpdata = (uint8 *)appMalloc(bytesMoved, NULL);
memmove(newRpdata, rptext->Data, rptext->Length);
memmove(newRpdata+rptext->Length, remData.Data, remData.Length);
CSSM_FREE(rptext->Data);
rptext->Data = newRpdata;
}
rptext->Length = bytesMoved;
return 0;
}
else {
cssmPerror("CSSM_DecryptData", crtn);
return testError(quiet);
}
}
static int doTest(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR pubKey,
CSSM_KEY_PTR privKey,
CSSM_PADDING encrPad,
CSSM_PADDING decrPad,
CSSM_BOOL quiet,
CSSM_RETURN expectResult)
{
int rtn;
uint8 ptext[PTEXT_LEN];
CSSM_DATA ptextData = {PTEXT_LEN, ptext};
CSSM_DATA ctext = {0, NULL};
CSSM_DATA rptext = {0, NULL};
simpleGenData(&ptextData, PTEXT_LEN, PTEXT_LEN);
rtn = doRsaEncrypt(cspHand, pubKey, encrPad, quiet, &ptextData, &ctext);
if(rtn) {
goto errOut;
}
rtn = doRsaDecrypt(cspHand, privKey, decrPad, quiet, expectResult, &ctext, &rptext);
if(rtn) {
goto errOut;
}
if(expectResult == CSSM_OK) {
if(memcmp(rptext.Data, ptextData.Data, PTEXT_LEN)) {
printf("***Data miscomapare after decrypt\n");
rtn = testError(quiet);
}
}
errOut:
if(ctext.Data) {
CSSM_FREE(ctext.Data);
}
if(rptext.Data) {
CSSM_FREE(rptext.Data);
}
return rtn;
}
int main(int argc, char **argv)
{
int arg;
char *argp;
unsigned loop;
CSSM_CSP_HANDLE cspHand;
int rtn = 0;
unsigned loops = LOOPS_DEF;
CSSM_BOOL verbose = CSSM_FALSE;
CSSM_BOOL quiet = CSSM_FALSE;
uint32 keySizeInBits = KEY_SIZE_DEF;
CSSM_BOOL bareCsp = CSSM_TRUE;
CSSM_BOOL doPause = CSSM_FALSE;
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'l':
loops = atoi(&argp[2]);
break;
case 'k':
keySizeInBits = atoi(&argv[arg][2]);
break;
case 'D':
bareCsp = CSSM_FALSE;
break;
case 'u':
keySizeInBits = KEY_SIZE_SMALL;
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'p':
doPause = CSSM_TRUE;
break;
case 'q':
quiet = CSSM_TRUE;
break;
case 'h':
default:
usage(argv);
}
}
testStartBanner("ssl2Padding", argc, argv);
cspHand = cspDlDbStartup(bareCsp, NULL);
if(cspHand == 0) {
exit(1);
}
CSSM_KEY pubKey;
CSSM_KEY privKey;
CSSM_RETURN crtn = cspGenKeyPair(cspHand, CSSM_ALGID_RSA,
USAGE_NAME, USAGE_NAME_LEN,
keySizeInBits,
&pubKey, CSSM_TRUE , CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE,
&privKey, CSSM_TRUE , CSSM_KEYUSE_ANY, CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE);
if(crtn) {
printf("***Error generating key pair. Aborting.\n");
exit(1);
}
for(loop=1; ; loop++) {
if(doPause) {
fpurge(stdin);
printf("Top of loop; hit CR to proceed: ");
getchar();
}
if(!quiet) {
printf("...loop %u\n", loop);
printf(" encrPad PKCS1 decrPad PKCS1\n");
}
rtn = doTest(cspHand, &pubKey, &privKey,
CSSM_PADDING_PKCS1, CSSM_PADDING_PKCS1,
quiet, CSSM_OK);
if(rtn) {
break;
}
if(!quiet) {
printf(" encrPad PKCS1 decrPad SSLv2\n");
}
rtn = doTest(cspHand, &pubKey, &privKey,
CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2,
quiet, CSSM_OK);
if(rtn) {
break;
}
if(!quiet) {
printf(" encrPad SSLv2 decrPad PKCS1\n");
}
rtn = doTest(cspHand, &pubKey, &privKey,
CSSM_PADDING_APPLE_SSLv2, CSSM_PADDING_PKCS1,
quiet, CSSM_OK);
if(rtn) {
break;
}
if(!quiet) {
printf(" encrPad SSLv2 decrPad SSLv2, expect failure\n");
}
rtn = doTest(cspHand, &pubKey, &privKey,
CSSM_PADDING_APPLE_SSLv2, CSSM_PADDING_APPLE_SSLv2,
quiet, CSSMERR_CSP_APPLE_SSLv2_ROLLBACK);
if(rtn) {
break;
}
if(loops && (loop == loops)) {
break;
}
}
CSSM_ModuleDetach(cspHand);
if((rtn == 0) && !quiet) {
printf("%s test complete\n", argv[0]);
}
return rtn;
}