#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 PKCS8_FORMAT_ENABLE 1
#define PKCS7_FORMAT_ENABLE 0
#define ENCR_USAGE_NAME "noLabel"
#define ENCR_USAGE_NAME_LEN (strlen(ENCR_USAGE_NAME))
#define WRAP_USAGE_NAME "noWrapLabel"
#define WRAP_USAGE_NAME_LEN (strlen(WRAP_USAGE_NAME))
#define LOOPS_DEF 10
#define MAX_PTEXT_SIZE 1000
#define LOOP_PAUSE 10
#define RSA_WRAP_RESTRICTION 1
#define WRAP_USAGE_ANY 0
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf(" Options:\n");
printf(" f (only wrap RSA private key)\n");
printf(" d (only wrap DES key)\n");
printf(" S (do symmetric wrap only)\n");
printf(" a (do asymmetric wrap only)\n");
printf(" n (do null wrap only)\n");
printf(" m (dump malloc info)\n");
printf(" r (ref keys only)\n");
printf(" w (wrap only)\n");
printf(" e (export)\n");
printf(" q (quiet)\n");
printf(" k (force PKCS7/8)\n");
#if PKCS7_FORMAT_ENABLE || PKCS8_FORMAT_ENABLE
printf(" K (skip PKCS7/8) (pkcs normally enable)\n");
#else
printf(" K (allow PKCS7/8) (pkcs normally disabled)\n");
#endif
printf(" D (CSP/DL; default = bare CSP)\n");
printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
printf(" p(ause every %d loops)\n", LOOP_PAUSE);
printf(" h(elp)\n");
exit(1);
}
CSSM_DATA initVector = {8, (uint8 *)"someVect"};
static CSSM_RETURN wrapKey(CSSM_CSP_HANDLE cspHand,
const CSSM_KEY_PTR unwrappedKey, const CSSM_KEY_PTR wrappingKey,
CSSM_ALGORITHMS wrapAlg,
CSSM_ENCRYPT_MODE wrapMode,
CSSM_KEYBLOB_FORMAT wrapFormat, CSSM_PADDING wrapPad,
CSSM_KEY_PTR wrappedKey) {
CSSM_CC_HANDLE ccHand;
CSSM_RETURN crtn;
CSSM_RETURN crtn2;
#if WRAP_KEY_REQUIRES_CREDS
CSSM_ACCESS_CREDENTIALS creds;
#endif
#if 0
if(unwrappedKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
printf("Hey! you can only wrap a reference key!\n");
return CSSM_ERRCODE_INTERNAL_ERROR;
}
#endif
memset(wrappedKey, 0, sizeof(CSSM_KEY));
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
if((wrappingKey == NULL) ||
(wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
wrapAlg,
wrapMode,
&creds, wrappingKey,
&initVector,
wrapPad, NULL, &ccHand);
if(crtn) {
printError("cspWrapKey/CreateContext", crtn);
return CSSM_ERRCODE_INTERNAL_ERROR;
}
}
else {
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
wrapAlg,
&creds, wrappingKey,
wrapPad, &ccHand);
if(crtn) {
printError("cspWrapKey/CreateContext", crtn);
return CSSM_ERRCODE_INTERNAL_ERROR;
}
crtn = AddContextAttribute(ccHand,
CSSM_ATTRIBUTE_INIT_VECTOR,
sizeof(CSSM_DATA),
CAT_Ptr,
&initVector,
0);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
CSSM_CONTEXT_ATTRIBUTE attr;
attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
attr.AttributeLength = sizeof(uint32);
attr.Attribute.Uint32 = wrapFormat;
crtn = CSSM_UpdateContextAttributes(
ccHand,
1,
&attr);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
crtn = CSSM_WrapKey(ccHand,
#if WRAP_KEY_REQUIRES_CREDS
&creds,
#else
NULL, #endif
unwrappedKey,
NULL, wrappedKey);
if(crtn != CSSM_OK) {
printError("CSSM_WrapKey", crtn);
}
if((crtn2 = CSSM_DeleteContext(ccHand))) {
printError("CSSM_DeleteContext", crtn2);
}
return crtn;
}
static CSSM_RETURN unwrapKey(CSSM_CSP_HANDLE cspHand,
const CSSM_KEY_PTR wrappedKey,
const CSSM_KEY_PTR unwrappingKey,
CSSM_ALGORITHMS unwrapAlg,
CSSM_ENCRYPT_MODE unwrapMode,
CSSM_PADDING unwrapPad,
CSSM_KEY_PTR unwrappedKey, const unsigned char *keyLabel,
unsigned keyLabelLen)
{
CSSM_CC_HANDLE ccHand;
CSSM_RETURN crtn;
CSSM_RETURN crtn2;
CSSM_DATA labelData;
uint32 keyAttr;
CSSM_DATA descData = { 0, NULL };
CSSM_ACCESS_CREDENTIALS creds;
memset(unwrappedKey, 0, sizeof(CSSM_KEY));
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
if((unwrappingKey == NULL) ||
(unwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
unwrapAlg,
unwrapMode,
&creds, unwrappingKey,
&initVector,
unwrapPad, 0, &ccHand);
if(crtn) {
printError("cspUnwrapKey/CreateContext", crtn);
return CSSM_ERRCODE_INTERNAL_ERROR;
}
}
else {
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
unwrapAlg,
&creds, unwrappingKey,
unwrapPad, &ccHand);
if(crtn) {
printError("cspUnwrapKey/CreateContext", crtn);
return CSSM_ERRCODE_INTERNAL_ERROR;
}
crtn = AddContextAttribute(ccHand,
CSSM_ATTRIBUTE_INIT_VECTOR,
sizeof(CSSM_DATA),
CAT_Ptr,
&initVector,
0);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
labelData.Data = (uint8 *)keyLabel;
labelData.Length = keyLabelLen;
keyAttr = wrappedKey->KeyHeader.KeyAttr;
keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE);
keyAttr |= CSSM_KEYATTR_RETURN_REF;
crtn = CSSM_UnwrapKey(ccHand,
NULL, wrappedKey,
CSSM_KEYUSE_ANY, keyAttr,
&labelData,
NULL, unwrappedKey,
&descData); if(crtn != CSSM_OK) {
printError("CSSM_UnwrapKey", crtn);
}
if((crtn2 = CSSM_DeleteContext(ccHand))) {
printError("CSSM_DeleteContext", crtn2);
}
return crtn;
}
#define UNWRAPPED_LABEL "unwrapped thing"
#define NULL_TEST 0
#if NULL_TEST
static int doTest(CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR encrKey,
CSSM_KEY_PTR decrKey, CSSM_KEY_PTR wrappingKey, CSSM_KEY_PTR unwrappingKey,
CSSM_ALGORITHMS wrapAlg,
CSSM_ENCRYPT_MODE wrapMode,
CSSM_PADDING wrapPad,
CSSM_ALGORITHMS encrAlg,
CSSM_ENCRYPT_MODE encrMode,
CSSM_PADDING encrPad,
CSSM_BOOL wrapOnly,
uint32 maxPtextSize, CSSM_BOOL quiet)
{
return 0;
}
#else
#define NULL_WRAP_DECR_KEY 1
static int doTest(CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR encrKey, CSSM_KEY_PTR decrKey, CSSM_KEY_PTR wrappingKey, CSSM_KEY_PTR unwrappingKey,
CSSM_ALGORITHMS wrapAlg,
CSSM_ENCRYPT_MODE wrapMode,
CSSM_KEYBLOB_FORMAT wrapFormat, CSSM_PADDING wrapPad,
CSSM_ALGORITHMS encrAlg,
CSSM_ENCRYPT_MODE encrMode,
CSSM_PADDING encrPad,
CSSM_BOOL wrapOnly,
uint32 maxPtextSize, CSSM_BOOL quiet)
{
CSSM_DATA ptext;
CSSM_DATA ctext;
CSSM_DATA rptext;
CSSM_KEY wrappedKey;
CSSM_KEY unwrappedKey;
CSSM_RETURN crtn;
CSSM_KEY_PTR realEncrKey; CSSM_KEY_PTR realDecrKey;
if((wrappingKey == NULL) && !NULL_WRAP_DECR_KEY) {
crtn = wrapKey(cspHand,
encrKey,
wrappingKey,
wrapAlg,
wrapMode,
wrapFormat,
wrapPad,
&wrappedKey);
realEncrKey = &unwrappedKey;
realDecrKey = decrKey;
}
else {
crtn = wrapKey(cspHand,
decrKey,
wrappingKey,
wrapAlg,
wrapMode,
wrapFormat,
wrapPad,
&wrappedKey);
realEncrKey = encrKey;
realDecrKey = &unwrappedKey;
}
if(crtn) {
return testError(quiet);
}
if((wrappingKey != NULL) && (wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE)) {
if(wrappedKey.KeyHeader.Format != wrapFormat) {
printf("wrapped key format mismatch: expect %u; got %u\n",
(unsigned)wrapFormat, (unsigned)wrappedKey.KeyHeader.Format);
if(testError(quiet)) {
return 1;
}
}
}
if(wrapOnly) {
cspFreeKey(cspHand, &wrappedKey);
goto done;
}
crtn = unwrapKey(cspHand,
&wrappedKey,
unwrappingKey,
wrapAlg,
wrapMode,
wrapPad,
&unwrappedKey,
(uint8 *)UNWRAPPED_LABEL,
15);
if(crtn) {
return testError(quiet);
}
ptext.Data = (uint8 *)CSSM_MALLOC(maxPtextSize);
simpleGenData(&ptext, 1, maxPtextSize);
ctext.Data = NULL;
ctext.Length = 0;
crtn = cspEncrypt(cspHand,
encrAlg,
encrMode,
encrPad,
realEncrKey,
NULL, 0, 0, &initVector,
&ptext,
&ctext,
CSSM_TRUE); if(crtn) {
return testError(quiet);
}
rptext.Data = NULL;
rptext.Length = 0;
crtn = cspDecrypt(cspHand,
encrAlg,
encrMode,
encrPad,
realDecrKey,
NULL, 0, 0, &initVector,
&ctext,
&rptext,
CSSM_TRUE);
if(crtn) {
return testError(quiet);
}
if(ptext.Length != rptext.Length) {
printf("ptext length mismatch\n");
return testError(quiet);
}
if(memcmp(ptext.Data, rptext.Data, ptext.Length)) {
printf("***data miscompare\n");
return testError(quiet);
}
cspFreeKey(cspHand, &wrappedKey);
cspFreeKey(cspHand, &unwrappedKey);
CSSM_FREE(ptext.Data);
CSSM_FREE(ctext.Data);
CSSM_FREE(rptext.Data);
done:
return 0;
}
#endif
int main(int argc, char **argv)
{
int arg;
char *argp;
int i;
CSSM_CSP_HANDLE cspHand;
CSSM_RETURN crtn;
CSSM_KEY origPub; CSSM_KEY origPriv;
CSSM_KEY_PTR origSess; CSSM_KEY_PTR origEncrKey; CSSM_KEY_PTR origDecrKey; CSSM_ALGORITHMS encrAlg;
CSSM_ENCRYPT_MODE encrMode;
CSSM_PADDING encrPad;
int rtn = 0;
CSSM_BOOL genRsaKey;
uint32 maxPtextSize;
CSSM_BOOL encrIsRef = CSSM_TRUE;
CSSM_BOOL decrIsRef = CSSM_TRUE;
CSSM_KEYBLOB_FORMAT wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
unsigned loop;
unsigned loops = LOOPS_DEF;
CSSM_BOOL pause = CSSM_FALSE;
CSSM_BOOL doSymmWrap = CSSM_TRUE;
CSSM_BOOL doAsymmWrap = CSSM_TRUE;
CSSM_BOOL doNullWrap = CSSM_TRUE;
CSSM_BOOL doSymmEncrOnly = CSSM_FALSE;
CSSM_BOOL doAsymmEncrOnly = CSSM_FALSE;
CSSM_BOOL wrapOnly = CSSM_FALSE;
CSSM_BOOL quiet = CSSM_FALSE;
CSSM_BOOL bareCsp = CSSM_TRUE;
CSSM_BOOL forcePkcs = CSSM_FALSE;
CSSM_BOOL refKeysOnly = CSSM_FALSE;
#if PKCS_FORMAT_ENABLE
CSSM_BOOL skipPkcs = CSSM_FALSE;
#else
CSSM_BOOL skipPkcs = CSSM_TRUE;
#endif
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'S':
doAsymmWrap = CSSM_FALSE;
doNullWrap = CSSM_FALSE;
break;
case 'a':
doSymmWrap = CSSM_FALSE;
doNullWrap = CSSM_FALSE;
break;
case 'n':
doSymmWrap = CSSM_FALSE;
doAsymmWrap = CSSM_FALSE;
break;
case 'f':
doAsymmEncrOnly = CSSM_TRUE;
break;
case 'd': case 'e': doSymmEncrOnly = CSSM_TRUE;
break;
case 'l':
loops = atoi(&argp[2]);
break;
case 'w':
wrapOnly = CSSM_TRUE;
break;
case 'p':
pause = CSSM_TRUE;
break;
case 'D':
bareCsp = CSSM_FALSE;
#if CSPDL_ALL_KEYS_ARE_REF
refKeysOnly = CSSM_TRUE;
#endif
break;
case 'k':
forcePkcs = CSSM_TRUE;
break;
case 'K':
#if PKCS7_FORMAT_ENABLE || PKCS8_FORMAT_ENABLE
skipPkcs = CSSM_TRUE;
#else
skipPkcs = CSSM_FALSE;
#endif
break;
case 'r':
refKeysOnly = CSSM_TRUE;
break;
case 'q':
quiet = CSSM_TRUE;
break;
default:
usage(argv);
}
}
#if 0
#if !PKCS_FORMAT_ENABLE
if(skipPkcs) {
if(doAsymmEncrOnly) {
printf("Asymmetric keys can only be wrapped via PKCS; aborting\n");
usage(argv);
}
else if(!doSymmWrap) {
printf("AsymmetricWrapping can only be done via PKCS; aborting\n");
usage(argv);
}
doSymmEncrOnly = CSSM_TRUE;
doSymmWrap = CSSM_TRUE;
doAsymmWrap = CSSM_FALSE;
}
#endif
#endif
cspHand = cspDlDbStartup(bareCsp, NULL);
if(cspHand == 0) {
exit(1);
}
printf("Starting miniWrap; args: ");
for(i=1; i<argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
for(loop=1; ; loop++) {
if((loop % LOOP_PAUSE) == 0) {
if(!quiet) {
printf("...loop %d\n", loop);
}
if(pause) {
fpurge(stdin);
printf("Hit CR to proceed: ");
getchar();
}
}
if(!refKeysOnly) {
encrIsRef = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
decrIsRef = (loop & 4) ? CSSM_TRUE : CSSM_FALSE;
}
if(!doAsymmEncrOnly && (doSymmEncrOnly || ((loop & 1) == 0))) {
if(!quiet) {
printf("...wrapping DES key (%s)\n",
encrIsRef ? "ref" : "raw");
}
origSess = cspGenSymKey(cspHand,
CSSM_ALGID_DES,
ENCR_USAGE_NAME,
ENCR_USAGE_NAME_LEN,
CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
CSP_KEY_SIZE_DEFAULT,
encrIsRef);
if(origSess == NULL) {
rtn = 1;
goto testDone;
}
origDecrKey = origEncrKey = origSess;
encrAlg = CSSM_ALGID_DES;
encrMode = CSSM_ALGMODE_CBCPadIV8;
encrPad = CSSM_PADDING_PKCS5;
maxPtextSize = MAX_PTEXT_SIZE; }
else {
origSess = NULL;
}
if(!doSymmEncrOnly && (doAsymmEncrOnly || ((loop & 1) == 1))) {
if(!quiet) {
printf("...wrapping RSA key (pub %s priv %s)\n",
(encrIsRef ? "ref" : "raw"),
(decrIsRef ? "ref" : "raw"));
}
crtn = cspGenKeyPair(cspHand,
CSSM_ALGID_RSA,
ENCR_USAGE_NAME,
ENCR_USAGE_NAME_LEN,
CSP_KEY_SIZE_DEFAULT,
&origPub,
encrIsRef, CSSM_KEYUSE_ENCRYPT,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&origPriv,
decrIsRef, CSSM_KEYUSE_DECRYPT,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE); if(crtn) {
rtn = 1;
goto testDone;
}
origDecrKey = &origPriv;
origEncrKey = &origPub;
encrAlg = CSSM_ALGID_RSA;
encrMode = CSSM_ALGMODE_NONE;
encrPad = CSSM_PADDING_PKCS1;
genRsaKey = CSSM_TRUE;
maxPtextSize = origPriv.KeyHeader.LogicalKeySizeInBits / 8;
maxPtextSize -= 11;
}
else {
genRsaKey = CSSM_FALSE;
}
if(doSymmWrap) {
CSSM_KEY_PTR wrapKey;
if(!quiet) {
printf(" ...Doing symmetric wrap\n");
}
wrapKey = cspGenSymKey(cspHand,
CSSM_ALGID_DES,
WRAP_USAGE_NAME,
WRAP_USAGE_NAME_LEN,
WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY :
CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
CSP_KEY_SIZE_DEFAULT,
CSSM_TRUE); if(wrapKey == NULL) {
rtn = 1;
goto testDone;
}
if(forcePkcs) {
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
}
else {
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
}
if(doTest(cspHand,
origEncrKey,
origDecrKey,
wrapKey,
wrapKey,
CSSM_ALGID_DES, CSSM_ALGMODE_CBCPadIV8, wrapFormat,
CSSM_PADDING_PKCS5, encrAlg,
encrMode,
encrPad,
wrapOnly,
maxPtextSize,
quiet)) {
rtn = 1;
goto testDone;
}
cspFreeKey(cspHand, wrapKey);
CSSM_FREE(wrapKey); wrapKey = NULL;
}
if(doAsymmWrap &&
!(RSA_WRAP_RESTRICTION && (origEncrKey != origDecrKey))) {
CSSM_KEY wrapPrivKey;
CSSM_KEY wrapPubKey;
if(!quiet) {
printf(" ...Doing asymmetric wrap\n");
}
crtn = cspGenKeyPair(cspHand,
CSSM_ALGID_RSA,
WRAP_USAGE_NAME,
WRAP_USAGE_NAME_LEN,
CSP_RSA_KEY_SIZE_DEFAULT,
&wrapPubKey,
CSSM_TRUE, WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_WRAP,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
&wrapPrivKey,
CSSM_TRUE, WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_UNWRAP,
CSSM_KEYBLOB_RAW_FORMAT_NONE,
CSSM_FALSE); if(crtn) {
rtn = 1;
goto testDone;
}
if(forcePkcs) {
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
}
else {
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
}
if(doTest(cspHand,
origEncrKey,
origDecrKey,
&wrapPubKey,
&wrapPrivKey,
CSSM_ALGID_RSA, CSSM_ALGMODE_NONE, wrapFormat,
CSSM_PADDING_PKCS1, encrAlg,
encrMode,
encrPad,
wrapOnly,
maxPtextSize,
quiet)) {
rtn = 1;
goto testDone;
}
cspFreeKey(cspHand, &wrapPubKey);
cspFreeKey(cspHand, &wrapPrivKey);
}
if(doNullWrap) {
if(!quiet) {
printf(" ...Doing NULL wrap\n");
}
if(doTest(cspHand,
origEncrKey,
origDecrKey,
NULL,
NULL,
CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, CSSM_KEYBLOB_WRAPPED_FORMAT_NONE,
CSSM_PADDING_NONE, encrAlg,
encrMode,
encrPad,
wrapOnly,
maxPtextSize,
quiet)) {
rtn = 1;
goto testDone;
}
}
if(origSess != NULL) {
cspFreeKey(cspHand, origSess);
CSSM_FREE(origSess);
}
if(genRsaKey) {
cspFreeKey(cspHand, &origPub);
cspFreeKey(cspHand, &origPriv);
}
if(loops && (loop == loops)) {
break;
}
}
testDone:
CSSM_ModuleDetach(cspHand);
if((rtn == 0) && !quiet) {
printf("%s test complete\n", argv[0]);
}
return rtn;
}