X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/cspxutils/asymTest/asymTest.c diff --git a/SecurityTests/cspxutils/asymTest/asymTest.c b/SecurityTests/cspxutils/asymTest/asymTest.c new file mode 100644 index 00000000..4d122d84 --- /dev/null +++ b/SecurityTests/cspxutils/asymTest/asymTest.c @@ -0,0 +1,870 @@ +/* Copyright (c) 1998,2003-2006,2008 Apple Inc. + * + * asymTest.c - test CSP asymmetric encrypt/decrypt. + * + * Revision History + * ---------------- + * 10 May 2000 Doug Mitchell + * Ported to X/CDSA2. + * 14 May 1998 Doug Mitchell at Apple + * Created. + */ + +#include +#include +#include +#include +#include +#include "cspwrap.h" +#include "common.h" +#include "cspdlTesting.h" + +#define USAGE_NAME "noUsage" +#define USAGE_NAME_LEN (strlen(USAGE_NAME)) +#define USAGE2_NAME "noUsage2" +#define USAGE2_NAME_LEN (strlen(USAGE2_NAME)) +#define LOOPS_DEF 10 +#define MIN_EXP 2 /* for data size 10**exp */ +#define DEFAULT_MAX_EXP 2 +#define MAX_EXP 4 + +/* + * Enumerate algs our own way to allow iteration. + */ +#define ALG_RSA 1 +#define ALG_FEED 2 +#define ALG_FEEDEXP 3 +#define ALG_FEE_CFILE 4 +#define ALG_FIRST ALG_RSA +#define ALG_LAST ALG_FEEDEXP +#define MAX_DATA_SIZE (10000 + 100) /* bytes */ +#define FEE_PASSWD_LEN 32 /* private data length in bytes, FEE only */ + +#define DUMP_KEY_DATA 0 + +/* + * RSA encryption now allows arbitrary plaintext size. BSAFE was limited to + * primeSize - 11. + */ +#define RSA_PLAINTEXT_LIMIT 0 + +static void usage(char **argv) +{ + printf("usage: %s [options]\n", argv[0]); + printf(" Options:\n"); + printf(" a=algorithm (f=FEED; x=FEEDExp; c=FEE_Cfile; r=RSA; default=all)\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(" k=keySize\n"); + printf(" P=primeType (m=Mersenne, f=FEE, g=general; FEE only)\n"); + printf(" C=curveType (m=Montgomery, w=Weierstrass, g=general; FEE only)\n"); + printf(" e(xport)\n"); + printf(" r(eference keys only)\n"); + printf(" K (skip decrypt)\n"); + printf(" N(o padding, RSA only)\n"); + printf(" S (no staging)\n"); + printf(" D (CSP/DL; default = bare CSP)\n"); + printf(" p (pause on each loop)\n"); + printf(" u (quick; small keys)\n"); + printf(" t=plainTextSize; default=random\n"); + printf(" z(ero data)\n"); + printf(" v(erbose)\n"); + printf(" q(uiet)\n"); + printf(" h(elp)\n"); + exit(1); +} + +static int doTest(CSSM_CSP_HANDLE cspHand, + CSSM_ALGORITHMS alg, // CSSM_ALGID_xxx + CSSM_PADDING padding, + CSSM_DATA_PTR ptext, + CSSM_BOOL verbose, + CSSM_BOOL quiet, + uint32 keySizeInBits, // may be 0, i.e., default per alg + uint32 primeType, // FEE only + uint32 curveType, // ditto + CSSM_BOOL pubIsRef, + CSSM_KEYBLOB_FORMAT rawPubForm, + CSSM_BOOL privIsRef, + CSSM_KEYBLOB_FORMAT rawPrivForm, + CSSM_BOOL secondPubIsRaw, // FEED via CSPDL: 2nd key must be raw + CSSM_BOOL stagedEncr, + CSSM_BOOL stagedDecr, + CSSM_BOOL mallocPtext, // only meaningful if !stagedDecr + CSSM_BOOL mallocCtext, // only meaningful if !stagedEncr + CSSM_BOOL skipDecrypt, + CSSM_BOOL genSeed) // FEE keys only +{ + // these two are always generated + CSSM_KEY recvPubKey; + CSSM_KEY recvPrivKey; + // these two are for two-key FEE algorithms only + CSSM_KEY sendPubKey; + CSSM_KEY sendPrivKey; + // these two are optionally created by cspRefKeyToRaw if (FEED && secondPubIsRaw) + CSSM_KEY sendPubKeyRaw; + CSSM_KEY recvPubKeyRaw; + CSSM_BOOL rawPubKeysCreated = CSSM_FALSE; + + /* two-key FEE, CSP : &{send,recv}PubKey + * two-key FEE, CSPDL: &{send,recv}PubKeyRaw + * else : NULL, &recvPubKey + */ + CSSM_KEY_PTR sendPubKeyPtr = NULL; + CSSM_KEY_PTR recvPubKeyPtr = NULL; + + CSSM_DATA ctext = {0, NULL}; + CSSM_DATA rptext = {0, NULL}; + CSSM_RETURN crtn; + int rtn = 0; + uint32 keyGenAlg; + uint32 mode = CSSM_ALGMODE_NONE; // FIXME - does this need testing? + CSSM_BOOL twoKeys = CSSM_FALSE; + + switch(alg) { + case CSSM_ALGID_FEED: + case CSSM_ALGID_FEECFILE: + twoKeys = CSSM_TRUE; + /* drop thru */ + case CSSM_ALGID_FEEDEXP: + keyGenAlg = CSSM_ALGID_FEE; + break; + case CSSM_ALGID_RSA: + keyGenAlg = CSSM_ALGID_RSA; + break; + default: + printf("bogus algorithm\n"); + return 1; + } + + /* one key pair for all algs except CFILE and FEED, which need two */ + if(keyGenAlg == CSSM_ALGID_FEE) { + uint8 passwd[FEE_PASSWD_LEN]; + CSSM_DATA pwdData = {FEE_PASSWD_LEN, passwd}; + CSSM_DATA_PTR pwdDataPtr; + if(genSeed) { + simpleGenData(&pwdData, FEE_PASSWD_LEN, FEE_PASSWD_LEN); + pwdDataPtr = &pwdData; + } + else { + pwdDataPtr = NULL; + } + /* + * Note we always generate public keys per the pubIsRef argument, even if + * secondPubIsRaw is true, 'cause the CSPDL can't generate raw keys. + */ + rtn = cspGenFEEKeyPair(cspHand, + USAGE_NAME, + USAGE_NAME_LEN, + keySizeInBits, + primeType, + curveType, + &recvPubKey, + pubIsRef, + CSSM_KEYUSE_ANY, + CSSM_KEYBLOB_RAW_FORMAT_NONE, + &recvPrivKey, + privIsRef, + CSSM_KEYUSE_ANY, + CSSM_KEYBLOB_RAW_FORMAT_NONE, + pwdDataPtr); + if(rtn) { + /* leak */ + return testError(quiet); + } + if(twoKeys) { + rtn = cspGenFEEKeyPair(cspHand, + USAGE2_NAME, + USAGE2_NAME_LEN, + keySizeInBits, + primeType, + curveType, + &sendPubKey, + pubIsRef, + CSSM_KEYUSE_ANY, + CSSM_KEYBLOB_RAW_FORMAT_NONE, + &sendPrivKey, + privIsRef, + CSSM_KEYUSE_ANY, + CSSM_KEYBLOB_RAW_FORMAT_NONE, + pwdDataPtr); + if(rtn) { + /* leak recv*Key */ + return testError(quiet); + } + } + if(twoKeys) { + if(secondPubIsRaw && pubIsRef) { + /* + * Convert ref public keys to raw - they're going into a Context; the + * SecurityServer doesn't deal with ref keys there. + * Leak all sorts of stuff on any error here. + */ + crtn = cspRefKeyToRaw(cspHand, &sendPubKey, &sendPubKeyRaw); + if(crtn) { + return testError(quiet); + } + crtn = cspRefKeyToRaw(cspHand, &recvPubKey, &recvPubKeyRaw); + if(crtn) { + return testError(quiet); + } + /* two keys, CSPDL */ + sendPubKeyPtr = &sendPubKeyRaw; + recvPubKeyPtr = &recvPubKeyRaw; + rawPubKeysCreated = CSSM_TRUE; + } + else { + /* two keys, CSP */ + sendPubKeyPtr = &sendPubKey; + recvPubKeyPtr = &recvPubKey; + } + } + else { + /* one key pair, standard config */ + sendPubKeyPtr = NULL; + recvPubKeyPtr = &recvPubKey; + } + } + else { + CSSM_KEYBLOB_FORMAT expectPubForm = rawPubForm; + CSSM_KEYBLOB_FORMAT expectPrivForm = rawPrivForm; + + rtn = cspGenKeyPair(cspHand, + keyGenAlg, + USAGE_NAME, + USAGE_NAME_LEN, + keySizeInBits, + &recvPubKey, + pubIsRef, + twoKeys ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_ENCRYPT, + rawPubForm, + &recvPrivKey, + privIsRef, + twoKeys ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_DECRYPT, + rawPrivForm, + genSeed); + if(rtn) { + return testError(quiet); + } + /* one key pair, standard config */ + sendPubKeyPtr = NULL; + recvPubKeyPtr = &recvPubKey; + + /* verify defaults - only for RSA */ + if(!pubIsRef) { + if(rawPubForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) { + expectPubForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; + } + if(recvPubKey.KeyHeader.Format != expectPubForm) { + printf("***Bad raw RSA pub key format - exp %u got %u\n", + (unsigned)expectPubForm, + (unsigned)recvPubKey.KeyHeader.Format); + if(testError(quiet)) { + return 1; + } + } + } + if(!privIsRef) { + if(rawPrivForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) { + expectPrivForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; + } + if(recvPrivKey.KeyHeader.Format != expectPrivForm) { + printf("***Bad raw RSA priv key format - exp %u got %u\n", + (unsigned)expectPrivForm, + (unsigned)recvPrivKey.KeyHeader.Format); + if(testError(quiet)) { + return 1; + } + } + } + } + #if DUMP_KEY_DATA + dumpBuffer("Pub Key Data", recvPubKey.KeyData.Data, recvPubKey.KeyData.Length); + dumpBuffer("Priv Key Data", recvPrivKey.KeyData.Data, recvPrivKey.KeyData.Length); + #endif + if(stagedEncr) { + crtn = cspStagedEncrypt(cspHand, + alg, + mode, + padding, + /* Two keys: second must be pub */ + twoKeys ? &sendPrivKey : &recvPubKey, + twoKeys ? recvPubKeyPtr : NULL, + 0, // effectiveKeySize + 0, // cipherBlockSize + 0, // rounds + NULL, // initVector + ptext, + &ctext, + CSSM_TRUE); // multi + } + else { + crtn = cspEncrypt(cspHand, + alg, + mode, + padding, + /* Two keys: second must be pub */ + twoKeys ? &sendPrivKey : &recvPubKey, + twoKeys ? recvPubKeyPtr : NULL, + 0, // effectiveKeySize + 0, // rounds + NULL, // initVector + ptext, + &ctext, + mallocCtext); + } + if(crtn) { + rtn = testError(quiet); + goto abort; + } + if(verbose) { + printf(" ..ptext size %lu ctext size %lu\n", + (unsigned long)ptext->Length, (unsigned long)ctext.Length); + } + if(skipDecrypt) { + goto abort; + } + if(stagedDecr) { + crtn = cspStagedDecrypt(cspHand, + alg, + mode, + padding, + /* Two keys: second must be pub */ + &recvPrivKey, + sendPubKeyPtr, + 0, // effectiveKeySize + 0, // cipherBlockSize + 0, // rounds + NULL, // initVector + &ctext, + &rptext, + CSSM_TRUE); // multi + } + else { + crtn = cspDecrypt(cspHand, + alg, + mode, + padding, + &recvPrivKey, + sendPubKeyPtr, + 0, // effectiveKeySize + 0, // rounds + NULL, // initVector + &ctext, + &rptext, + mallocPtext); + } + if(crtn) { + rtn = testError(quiet); + goto abort; + } + /* compare ptext, rptext */ + if(ptext->Length != rptext.Length) { + printf("Ptext length mismatch: expect %lu, got %lu\n", + (unsigned long)ptext->Length, (unsigned long)rptext.Length); + rtn = testError(quiet); + if(rtn) { + goto abort; + } + } + if(memcmp(ptext->Data, rptext.Data, ptext->Length)) { + printf("***data miscompare\n"); + rtn = testError(quiet); + } +abort: + /* free keys */ + if(cspFreeKey(cspHand, &recvPubKey)) { + printf("Error freeing recvPubKey\n"); + rtn = 1; + } + if(cspFreeKey(cspHand, &recvPrivKey)) { + printf("Error freeing recvPrivKey\n"); + rtn = 1; + } + if(twoKeys) { + if(cspFreeKey(cspHand, &sendPubKey)) { + printf("Error freeing sendPubKey\n"); + rtn = 1; + } + if(cspFreeKey(cspHand, &sendPrivKey)) { + printf("Error freeing sendPrivKey\n"); + rtn = 1; + } + if(rawPubKeysCreated) { + if(cspFreeKey(cspHand, &sendPubKeyRaw)) { + printf("Error freeing sendPubKeyRaw\n"); + rtn = 1; + } + if(cspFreeKey(cspHand, &recvPubKeyRaw)) { + printf("Error freeing recvPubKeyRaw\n"); + rtn = 1; + } + } + } + /* free rptext, ctext */ + appFreeCssmData(&rptext, CSSM_FALSE); + appFreeCssmData(&ctext, CSSM_FALSE); + return rtn; +} + +static const char *formStr( + CSSM_KEYBLOB_FORMAT form) +{ + switch(form) { + case CSSM_KEYBLOB_RAW_FORMAT_NONE: return "NONE"; + case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return "PKCS1"; + case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return "PKCS8"; + case CSSM_KEYBLOB_RAW_FORMAT_X509: return "X509"; + case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return "SSH1"; + case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: return "SSH2"; + default: + printf("***BRRRZAP! formStr needs work\n"); + exit(1); + } +} + +int main(int argc, char **argv) +{ + int arg; + char *argp; + unsigned loop; + CSSM_DATA ptext; + CSSM_CSP_HANDLE cspHand; + CSSM_BOOL pubIsRef = CSSM_TRUE; + CSSM_BOOL privIsRef = CSSM_TRUE; + CSSM_BOOL stagedEncr; + CSSM_BOOL stagedDecr; + const char *algStr; + uint32 encAlg; // CSSM_ALGID_xxx + unsigned currAlg; // ALG_xxx + int i; + CSSM_BOOL mallocCtext; + CSSM_BOOL mallocPtext; + int rtn = 0; + CSSM_BOOL genSeed; // for FEE key gen + CSSM_PADDING padding; + CSSM_KEYBLOB_FORMAT rawPubFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE; + CSSM_KEYBLOB_FORMAT rawPrivFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE; + + /* + * User-spec'd params + */ + unsigned loops = LOOPS_DEF; + CSSM_BOOL verbose = CSSM_FALSE; + unsigned minExp = MIN_EXP; + unsigned maxExp = DEFAULT_MAX_EXP; + CSSM_BOOL quiet = CSSM_FALSE; + uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT; + CSSM_BOOL keySizeSpec = CSSM_FALSE; + unsigned minAlg = ALG_FIRST; + uint32 maxAlg = ALG_LAST; + CSSM_BOOL skipDecrypt = CSSM_FALSE; + CSSM_BOOL bareCsp = CSSM_TRUE; + CSSM_BOOL doPause = CSSM_FALSE; + CSSM_BOOL smallKeys = CSSM_FALSE; + uint32 primeType = CSSM_FEE_PRIME_TYPE_DEFAULT; // FEE only + uint32 curveType = CSSM_FEE_CURVE_TYPE_DEFAULT; // FEE only + uint32 ptextSize = 0; // 0 means random + dataType dtype = DT_Random; + CSSM_BOOL refKeysOnly = CSSM_FALSE; + CSSM_BOOL noPadding = CSSM_FALSE; + CSSM_BOOL stagingEnabled = CSSM_TRUE; + + for(arg=1; arg MAX_EXP) { + usage(argv); + } + break; + case 'k': + keySizeInBits = atoi(&argv[arg][2]); + keySizeSpec = CSSM_TRUE; + break; + case 'K': + skipDecrypt = CSSM_TRUE; + break; + case 't': + ptextSize = atoi(&argp[2]); + break; + case 'D': + bareCsp = CSSM_FALSE; + #if CSPDL_ALL_KEYS_ARE_REF + refKeysOnly = CSSM_TRUE; + #endif + break; + case 'u': + smallKeys = CSSM_TRUE; + break; + case 'N': + noPadding = CSSM_TRUE; + break; + case 'z': + dtype = DT_Zero; + break; + case 'v': + verbose = CSSM_TRUE; + break; + case 'r': + refKeysOnly = CSSM_TRUE; + break; + case 'S': + stagingEnabled = CSSM_FALSE; + break; + case 'p': + doPause = CSSM_TRUE; + break; + case 'q': + quiet = CSSM_TRUE; + break; + case 'C': + switch(argp[2]) { + case 'm': + curveType = CSSM_FEE_CURVE_TYPE_MONTGOMERY; + break; + case 'w': + curveType = CSSM_FEE_CURVE_TYPE_WEIERSTRASS; + break; + default: + usage(argv); + } + break; + case 'P': + switch(argp[2]) { + case 'm': + primeType = CSSM_FEE_PRIME_TYPE_MERSENNE; + break; + case 'f': + primeType = CSSM_FEE_PRIME_TYPE_FEE; + break; + case 'g': + primeType = CSSM_FEE_PRIME_TYPE_GENERAL; + break; + default: + usage(argv); + } + break; + case 'h': + default: + usage(argv); + } + } + ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE); + + /* length set in test loop */ + if(ptext.Data == NULL) { + printf("Insufficient heap\n"); + exit(1); + } + if(noPadding) { + if(ptextSize == 0) { + printf("**WARNING NoPad mode will fail with random plaintext size\n"); + } + if(!keySizeSpec) { + printf("**WARNING NoPad mode will fail with random key size\n"); + } + else { + uint32 keyBytes = keySizeInBits / 8; + if(ptextSize != keyBytes) { + /* + * FIXME: I actually do not understand why this fails, but + * doing raw RSA encryption with ptextSize != keySize results + * in random-looking failures, probably based on the plaintext + * itself (it doesn't fail with zero data). + */ + printf("***WARNING NoPad mode requires plaintext size = key size\n"); + } + } + } + printf("Starting asymTest; args: "); + for(i=1; i