#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <Security/cssm.h>
#include <Security/cssmapple.h>
#include "cspwrap.h"
#include "common.h"
#include "bsafeUtils.h"
#include <string.h>
#include "cspdlTesting.h"
#define OLOOPS_DEF 10
#define SIG_LOOPS_DEF 100
#define ENC_LOOPS_DEF 100
#define MAX_TEXT_SIZE 1025
#define LOOP_NOTIFY 20
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf(" Options:\n");
printf(" a=algorithm (r=RSA; d=DSA; default=both)\n");
printf(" l=outerloops (default=%d; 0=forever)\n", OLOOPS_DEF);
printf(" s=sigLoops (default=%d)\n", SIG_LOOPS_DEF);
printf(" e=encryptLoops (default=%d)\n", ENC_LOOPS_DEF);
printf(" k=keySizeInBits; default is random\n");
printf(" S (sign/verify only)\n");
printf(" E (encrypt/decrypt only)\n");
printf(" r (generate ref keys)\n");
printf(" R (generate public ref keys)\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);
}
static const char *algToStr(CSSM_ALGORITHMS sigAlg)
{
switch(sigAlg) {
case CSSM_ALGID_RSA: return "RSA";
case CSSM_ALGID_DSA: return "DSA";
case CSSM_ALGID_SHA1WithRSA: return "SHA1WithRSA";
case CSSM_ALGID_MD5WithRSA: return "MD5WithRSA";
case CSSM_ALGID_SHA1WithDSA: return "SHA1WithDSA";
default:
printf("***Unknown sigAlg\n");
exit(1);
}
return "";
}
static CSSM_RETURN _cspDecrypt(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, uint32 mode, CSSM_PADDING padding, CSSM_BOOL blinding,
const CSSM_KEY *key, const CSSM_DATA *ctext,
CSSM_DATA_PTR ptext) {
CSSM_CC_HANDLE cryptHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
CSSM_SIZE bytesDecrypted;
CSSM_DATA remData = {0, NULL};
cryptHand = genCryptHandle(cspHand,
algorithm,
mode,
padding,
key,
NULL, NULL, 0, 0); if(cryptHand == 0) {
return CSSMERR_CSP_INTERNAL_ERROR;
}
if(blinding) {
CSSM_CONTEXT_ATTRIBUTE newAttr;
newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
newAttr.AttributeLength = sizeof(uint32);
newAttr.Attribute.Uint32 = 1;
crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &newAttr);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
crtn = CSSM_DecryptData(cryptHand,
ctext,
1,
ptext,
1,
&bytesDecrypted,
&remData);
if(crtn == CSSM_OK) {
ptext->Length = bytesDecrypted;
if(remData.Data != NULL) {
appFree(remData.Data, NULL);
}
}
else {
printError("CSSM_DecryptData", crtn);
ocrtn = crtn;
}
crtn = CSSM_DeleteContext(cryptHand);
if(crtn) {
printError("CSSM_DeleteContext", crtn);
ocrtn = crtn;
}
return ocrtn;
}
static CSSM_RETURN _cspSign(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
CSSM_BOOL rsaBlinding,
CSSM_DATA_PTR sig) {
CSSM_CC_HANDLE sigHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
const CSSM_DATA *ptext;
CSSM_DATA digest = {0, NULL};
CSSM_ALGORITHMS digestAlg = CSSM_ALGID_NONE;
switch(algorithm) {
case CSSM_ALGID_SHA1:
digestAlg = CSSM_ALGID_SHA1;
algorithm = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_MD5:
digestAlg = CSSM_ALGID_MD5;
algorithm = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_DSA:
digestAlg = CSSM_ALGID_SHA1;
algorithm = CSSM_ALGID_DSA;
break;
default:
break;
}
if(digestAlg != CSSM_ALGID_NONE) {
crtn = cspDigest(cspHand,
digestAlg,
CSSM_FALSE, text,
&digest);
if(crtn) {
return crtn;
}
ptext = &digest;
}
else {
ptext = text;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
algorithm,
NULL, key,
&sigHand);
if(crtn) {
printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
return crtn;
}
if(rsaBlinding) {
CSSM_CONTEXT_ATTRIBUTE newAttr;
newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
newAttr.AttributeLength = sizeof(uint32);
newAttr.Attribute.Uint32 = 1;
crtn = CSSM_UpdateContextAttributes(sigHand, 1, &newAttr);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
crtn = CSSM_SignData(sigHand,
ptext,
1,
digestAlg,
sig);
if(crtn) {
printError("CSSM_SignData", crtn);
ocrtn = crtn;
}
crtn = CSSM_DeleteContext(sigHand);
if(crtn) {
printError("CSSM_DeleteContext", crtn);
ocrtn = crtn;
}
if(digest.Data != NULL) {
CSSM_FREE(digest.Data);
}
return ocrtn;
}
static int sigTest(
CSSM_CSP_HANDLE cspHand,
unsigned numLoops,
BU_KEY bsafePrivKey,
CSSM_KEY_PTR cdsaPubKey,
CSSM_KEY_PTR cdsaPrivKey,
BU_KEY bsafePubKey,
CSSM_DATA_PTR ptext,
unsigned maxPtextSize,
CSSM_ALGORITHMS sigAlg,
CSSM_BOOL rsaBlinding,
CSSM_BOOL quiet,
CSSM_BOOL verbose)
{
CSSM_RETURN crtn;
CSSM_DATA sig = {0, NULL};
unsigned loop;
uint32 keySizeInBits = cdsaPrivKey->KeyHeader.LogicalKeySizeInBits;
if(!quiet) {
printf(" ...sig alg %s keySize %u\n", algToStr(sigAlg), (unsigned)keySizeInBits);
}
for(loop=0; loop<numLoops; loop++) {
simpleGenData(ptext, 1, maxPtextSize);
if(!quiet) {
if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
printf(" ...loop %d keySize %u textSize %lu\n",
loop, (unsigned)cdsaPrivKey->KeyHeader.LogicalKeySizeInBits,
(unsigned long)ptext->Length);
}
}
crtn = buSign(bsafePrivKey,
sigAlg,
ptext,
keySizeInBits,
&sig);
if(crtn) {
return testError(quiet);
}
crtn = cspSigVerify(cspHand,
sigAlg,
cdsaPubKey,
ptext,
&sig,
CSSM_OK);
if(crtn) {
printf("***ERROR: Sign with BSAFE, vfy with CDSA, alg %s\n",
algToStr(sigAlg));
if(testError(quiet)) {
return 1;
}
}
appFreeCssmData(&sig, CSSM_FALSE);
crtn = _cspSign(cspHand,
sigAlg,
cdsaPrivKey,
ptext,
rsaBlinding,
&sig);
if(crtn) {
return testError(quiet);
}
crtn = buVerify(bsafePubKey,
sigAlg,
ptext,
&sig);
if(crtn) {
printf("***ERROR: Sign with CDSA, vfy with BSAFE, alg %s\n",
algToStr(sigAlg));
if(testError(quiet)) {
return 1;
}
}
appFreeCssmData(&sig, CSSM_FALSE);
}
return CSSM_OK;
}
static int encryptTest(
CSSM_CSP_HANDLE cspHand,
unsigned numLoops,
BU_KEY bsafePrivKey,
CSSM_KEY_PTR cdsaPubKey,
CSSM_KEY_PTR cdsaPrivKey,
BU_KEY bsafePubKey,
CSSM_DATA_PTR ptext,
unsigned maxPtextSize,
CSSM_BOOL rsaBlinding,
CSSM_BOOL quiet,
CSSM_BOOL verbose)
{
CSSM_RETURN crtn;
CSSM_DATA ctext = {0, NULL};
CSSM_DATA rptext = {0, NULL};
unsigned loop;
unsigned actKeySizeBytes;
actKeySizeBytes = cdsaPrivKey->KeyHeader.LogicalKeySizeInBits / 8;
if(actKeySizeBytes < 12) {
printf("***Key with %u key bits is too small for RSA encrypt\n",
(unsigned)cdsaPrivKey->KeyHeader.LogicalKeySizeInBits);
return 1;
}
if(maxPtextSize > (actKeySizeBytes - 11)) {
maxPtextSize = actKeySizeBytes - 11;
}
if(!quiet) {
printf(" ...encr alg RSA\n");
}
for(loop=0; loop<numLoops; loop++) {
simpleGenData(ptext, 1, maxPtextSize);
if(!quiet) {
if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
printf(" ...loop %d keySize %u textSize %lu\n",
loop, (unsigned)cdsaPrivKey->KeyHeader.LogicalKeySizeInBits,
(unsigned long)ptext->Length);
}
}
crtn = buEncryptDecrypt(bsafePubKey,
CSSM_TRUE, CSSM_ALGID_RSA,
CSSM_ALGMODE_NONE,
NULL, cdsaPrivKey->KeyHeader.LogicalKeySizeInBits,
0, ptext,
&ctext);
if(crtn) {
return testError(quiet);
}
crtn = _cspDecrypt(cspHand,
CSSM_ALGID_RSA,
CSSM_ALGMODE_NONE,
CSSM_PADDING_PKCS1,
rsaBlinding,
cdsaPrivKey,
&ctext,
&rptext);
if(crtn) {
printf("***ERROR: encrypt with BSAFE, decrypt with CDSA\n");
return testError(quiet);
}
if(!appCompareCssmData(ptext, &rptext)) {
printf("***DATA MISCOMPARE: encrypt with BSAFE, decrypt with CDSA\n");
return testError(quiet);
}
appFreeCssmData(&ctext, CSSM_FALSE);
appFreeCssmData(&rptext, CSSM_FALSE);
crtn = cspEncrypt(cspHand,
CSSM_ALGID_RSA,
CSSM_ALGMODE_NONE,
CSSM_PADDING_PKCS1,
cdsaPubKey,
NULL, 0, 0, NULL, ptext,
&ctext,
CSSM_FALSE); if(crtn) {
return testError(quiet);
}
crtn = buEncryptDecrypt(bsafePrivKey,
CSSM_FALSE, CSSM_ALGID_RSA,
CSSM_ALGMODE_NONE,
NULL, cdsaPrivKey->KeyHeader.LogicalKeySizeInBits,
0, &ctext,
&rptext);
if(crtn) {
printf("***ERROR: encrypt with CDSA, decrypt with BSAFE\n");
return testError(quiet);
}
if(!appCompareCssmData(ptext, &rptext)) {
printf("***DATA MISCOMPARE: encrypt with CDSA, decrypt with BSAFE\n");
return testError(quiet);
}
appFreeCssmData(&ctext, CSSM_FALSE);
appFreeCssmData(&rptext, CSSM_FALSE);
}
return CSSM_OK;
}
static int doTest(
CSSM_CSP_HANDLE cspHand,
CSSM_ALGORITHMS keyAlg, CSSM_ALGORITHMS sigAlg,
unsigned sigLoops, unsigned encrLoops, CSSM_BOOL rsaBlinding,
CSSM_DATA_PTR ptext,
unsigned maxPtextSize,
uint32 keySizeInBits, CSSM_BOOL pubRefKeys,
CSSM_BOOL privRefKeys,
CSSM_BOOL bareCsp, CSSM_BOOL quiet,
CSSM_BOOL verbose)
{
CSSM_KEY cdsaGenPubKey;
CSSM_KEY cdsaGenPrivKey; CSSM_KEY cdsaTempKey; CSSM_KEY cdsaDerivePrivKey; BU_KEY bsafeGenPubKey;
BU_KEY bsafeGenPrivKey; BU_KEY bsafeDerivePrivKey; unsigned actKeySizeBits;
CSSM_RETURN crtn;
int rtn;
if(!keySizeInBits) {
actKeySizeBits = randKeySizeBits(keyAlg, OT_Encrypt);
}
else {
actKeySizeBits = keySizeInBits;
}
if(verbose) {
printf(" ...generating %s key pair, keySize %d bits...\n",
algToStr(keyAlg), actKeySizeBits);
}
if(keyAlg == CSSM_ALGID_DSA) {
CSSM_BOOL doGenParams;
if(bareCsp || CSPDL_DSA_GEN_PARAMS) {
doGenParams = CSSM_TRUE;
}
else {
doGenParams = CSSM_FALSE;
}
crtn = cspGenDSAKeyPair(cspHand,
"foo",
3,
actKeySizeBits,
&cdsaGenPubKey,
pubRefKeys,
CSSM_KEYUSE_ANY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&cdsaGenPrivKey,
privRefKeys,
CSSM_KEYUSE_SIGN,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
doGenParams, NULL); }
else {
crtn = cspGenKeyPair(cspHand,
keyAlg,
"foo",
3,
actKeySizeBits,
&cdsaGenPubKey,
pubRefKeys,
CSSM_KEYUSE_ANY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&cdsaGenPrivKey,
privRefKeys,
CSSM_KEYUSE_ANY,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE); }
if(crtn) {
return testError(quiet);
}
crtn = buGenKeyPair(actKeySizeBits,
keyAlg,
&bsafeGenPubKey,
&bsafeGenPrivKey);
if(crtn) {
return testError(quiet);
}
if(privRefKeys) {
crtn = buBsafePrivKeyToCdsa(keyAlg,
actKeySizeBits,
bsafeGenPrivKey,
&cdsaTempKey);
if(crtn) {
return testError(quiet);
}
crtn = cspRawKeyToRef(cspHand, &cdsaTempKey, &cdsaDerivePrivKey);
cspFreeKey(cspHand, &cdsaTempKey);
}
else {
crtn = buBsafePrivKeyToCdsa(keyAlg,
actKeySizeBits,
bsafeGenPrivKey,
&cdsaDerivePrivKey);
}
if(crtn) {
return testError(quiet);
}
if(privRefKeys) {
crtn = cspRefKeyToRaw(cspHand, &cdsaGenPrivKey, &cdsaTempKey);
if(crtn) {
return testError(quiet);
}
crtn = buCdsaPrivKeyToBsafe(&cdsaTempKey, &bsafeDerivePrivKey);
cspFreeKey(cspHand, &cdsaTempKey);
}
else {
crtn = buCdsaPrivKeyToBsafe(&cdsaGenPrivKey, &bsafeDerivePrivKey);
}
if(crtn) {
return testError(quiet);
}
if(sigLoops) {
rtn = sigTest(cspHand,
sigLoops,
bsafeDerivePrivKey,
&cdsaGenPubKey,
&cdsaDerivePrivKey,
bsafeGenPubKey,
ptext,
maxPtextSize,
sigAlg,
rsaBlinding,
quiet,
verbose);
if(rtn) {
return rtn;
}
}
if(encrLoops) {
rtn = encryptTest(cspHand,
encrLoops,
bsafeDerivePrivKey,
&cdsaGenPubKey,
&cdsaDerivePrivKey,
bsafeGenPubKey,
ptext,
maxPtextSize,
rsaBlinding,
quiet,
verbose);
if(rtn) {
return rtn;
}
}
buFreeKey(bsafeGenPubKey);
buFreeKey(bsafeGenPrivKey);
buFreeKey(bsafeDerivePrivKey);
cspFreeKey(cspHand, &cdsaGenPubKey);
cspFreeKey(cspHand, &cdsaGenPrivKey);
cspFreeKey(cspHand, &cdsaDerivePrivKey);
return 0;
}
int main(int argc, char **argv)
{
int arg;
char *argp;
unsigned loop;
CSSM_DATA ptext;
CSSM_CSP_HANDLE cspHand;
int i;
int rtn = 0;
uint32 keySizeInBits = 0;
unsigned oloops = OLOOPS_DEF;
unsigned sigLoops = SIG_LOOPS_DEF;
unsigned encrLoops = ENC_LOOPS_DEF;
CSSM_BOOL verbose = CSSM_FALSE;
CSSM_BOOL quiet = CSSM_FALSE;
unsigned pauseInterval = 0;
CSSM_BOOL bareCsp = CSSM_TRUE;
CSSM_BOOL doDSA = CSSM_TRUE;
CSSM_BOOL doRSA = CSSM_TRUE;
CSSM_BOOL pubRefKeys = CSSM_FALSE;
CSSM_BOOL privRefKeys = CSSM_FALSE;
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'a':
if(argp[1] != '=') {
usage(argv);
}
switch(argp[2]) {
case 'r':
doDSA = CSSM_FALSE;
break;
case 'd':
doRSA = CSSM_FALSE;
break;
default:
usage(argv);
}
break;
case 'l':
oloops = atoi(&argp[2]);
break;
case 's':
sigLoops = atoi(&argp[2]);
break;
case 'e':
encrLoops = atoi(&argp[2]);
break;
case 'k':
keySizeInBits = atoi(&argp[2]);
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'r':
privRefKeys = CSSM_TRUE;
break;
case 'R':
pubRefKeys = CSSM_TRUE;
break;
case 'D':
bareCsp = CSSM_FALSE;
#if CSPDL_ALL_KEYS_ARE_REF
privRefKeys = CSSM_TRUE;
pubRefKeys = CSSM_TRUE;
#endif
break;
case 'E':
sigLoops = 0;
break;
case 'S':
encrLoops = 0;
break;
case 'q':
quiet = CSSM_TRUE;
break;
case 'p':
pauseInterval = atoi(&argp[2]);;
break;
case 'h':
default:
usage(argv);
}
}
ptext.Data = (uint8 *)CSSM_MALLOC(MAX_TEXT_SIZE);
if(ptext.Data == NULL) {
printf("Insufficient heap space\n");
exit(1);
}
printf("Starting asymCompat; args: ");
for(i=1; i<argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
cspHand = cspDlDbStartup(bareCsp, NULL);
if(cspHand == 0) {
exit(1);
}
if(pauseInterval) {
fpurge(stdin);
printf("Top of test; hit CR to proceed: ");
getchar();
}
for(loop=1; ; loop++) {
if(!quiet) {
if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
printf("...oloop %d\n", loop);
}
}
if(doRSA) {
CSSM_ALGORITHMS sigAlg;
if(loop & 1) {
sigAlg = CSSM_ALGID_SHA1WithRSA;
}
else {
sigAlg = CSSM_ALGID_MD5WithRSA;
}
CSSM_BOOL rsaBlinding = CSSM_FALSE;
if(loop & 2) {
rsaBlinding = CSSM_TRUE;
}
rtn = doTest(cspHand,
CSSM_ALGID_RSA,
sigAlg,
sigLoops,
encrLoops,
rsaBlinding,
&ptext,
MAX_TEXT_SIZE,
keySizeInBits,
pubRefKeys,
privRefKeys,
bareCsp,
quiet,
verbose);
if(rtn) {
break;
}
}
if(doDSA) {
rtn = doTest(cspHand,
CSSM_ALGID_DSA,
CSSM_ALGID_SHA1WithDSA,
sigLoops,
0, CSSM_FALSE, &ptext,
MAX_TEXT_SIZE,
keySizeInBits,
pubRefKeys,
privRefKeys,
bareCsp,
quiet,
verbose);
if(rtn) {
break;
}
}
if(oloops && (loop == oloops)) {
break;
}
if(pauseInterval && (loop % pauseInterval) == 0) {
fpurge(stdin);
printf("hit CR to proceed: ");
getchar();
}
}
cspShutdown(cspHand, bareCsp);
if(pauseInterval) {
fpurge(stdin);
printf("ModuleDetach/Unload complete; hit CR to exit: ");
getchar();
}
if((rtn == 0) && !quiet) {
printf("%s test complete\n", argv[0]);
}
CSSM_FREE(ptext.Data);
return rtn;
}