#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <Security/cssm.h>
#include <Security/cssmapple.h>
#include <string.h>
#include "cspwrap.h"
#include "common.h"
#include <security_cdsa_utils/cuFileIo.h>
#include "nssAppUtils.h"
#define PARAMS_512_1 "dsaParam512_1.der"
#define PARAMS_512_2 "dsaParam512_2.der"
#define MAX_PTEXT_SIZE 512
#define KEY_ALG CSSM_ALGID_DSA
#define SIG_ALG CSSM_ALGID_SHA1WithDSA
#define LOOPS_DEF 32
#define KEY_SIZE_DEF 512
static void usage(char **argv)
{
printf("Usage: %s [options]\n", argv[0]);
printf("Options:\n");
printf(" l=loops\n");
printf(" p(ause on loop)\n");
printf(" q(uiet)\n");
printf(" v(erbose)\n");
printf(" D (CSPDL)\n");
printf(" r (all keys are raw)\n");
printf(" f (all keys are ref)\n");
exit(1);
}
static CSSM_RETURN genDsaKeyPair(
CSSM_CSP_HANDLE cspHand,
uint32 keySize, CSSM_KEY_PTR pubKey, CSSM_BOOL pubIsRef, CSSM_KEY_PTR privKey, CSSM_BOOL privIsRef, const CSSM_DATA *params)
{
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHand;
CSSM_DATA keyLabelData;
uint32 pubAttr;
uint32 privAttr;
if(params == NULL) {
return CSSMERR_CSSM_INVALID_POINTER;
}
keyLabelData.Data = (uint8 *)"foobar",
keyLabelData.Length = 6;
memset(pubKey, 0, sizeof(CSSM_KEY));
memset(privKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
CSSM_ALGID_DSA,
keySize,
NULL, NULL, NULL, NULL, params,
&ccHand);
if(crtn) {
printError("CSSM_CSP_CreateKeyGenContext", crtn);
return crtn;
}
if(pubIsRef) {
pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
}
else {
pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
}
if(privIsRef) {
privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
}
else {
privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
}
crtn = CSSM_GenerateKeyPair(ccHand,
CSSM_KEYUSE_VERIFY,
pubAttr,
&keyLabelData,
pubKey,
CSSM_KEYUSE_SIGN,
privAttr,
&keyLabelData, NULL, privKey);
if(crtn) {
printError("CSSM_GenerateKeyPair", crtn);
}
CSSM_DeleteContext(ccHand);
return crtn;
}
static CSSM_RETURN dsaMergeParams(
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY *partialKey,
const CSSM_KEY *paramKey,
CSSM_KEY &fullKey, bool fullIsRef) {
CSSM_CC_HANDLE ccHand;
CSSM_RETURN crtn;
CSSM_ACCESS_CREDENTIALS creds;
CSSM_DATA label = {10, (uint8 *)"dummyLabel"};
CSSM_DATA descrData = {0, NULL};
const CSSM_KEYHEADER &hdr = partialKey->KeyHeader;
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
&creds,
NULL, NULL, CSSM_PADDING_NONE,
0, &ccHand);
if(crtn) {
printError("CSSM_CSP_CreateSymmetricContext", crtn);
return crtn;
}
crtn = AddContextAttribute(ccHand,
CSSM_ATTRIBUTE_PARAM_KEY,
sizeof(CSSM_KEY),
CAT_Ptr,
paramKey,
0);
if(crtn) {
printError("AddContextAttribute", crtn);
return crtn;
}
CSSM_KEY targetKey;
memset(&targetKey, 0, sizeof(targetKey));
if(hdr.BlobType == CSSM_KEYBLOB_RAW) {
crtn = CSSM_UnwrapKey(ccHand,
NULL, partialKey,
hdr.KeyUsage, CSSM_KEYATTR_EXTRACTABLE |CSSM_KEYATTR_RETURN_REF,
&label,
NULL, &targetKey,
&descrData); if(crtn) {
printError("dsaMergeParams CSSM_UnwrapKey (1)", crtn);
return crtn;
}
}
else {
crtn = CSSM_WrapKey(ccHand,
&creds,
partialKey,
NULL, &targetKey);
if(crtn) {
printError("dsaMergeParams CSSM_WrapKey (1)", crtn);
return crtn;
}
}
if(targetKey.KeyHeader.KeyAttr & CSSM_KEYATTR_PARTIAL) {
printf("***merged key still has CSSM_KEYATTR_PARTIAL\n");
return CSSMERR_CSSM_INTERNAL_ERROR;
}
CSSM_KEYBLOB_TYPE targetBlob;
if(fullIsRef) {
targetBlob = CSSM_KEYBLOB_REFERENCE;
}
else {
targetBlob = CSSM_KEYBLOB_RAW;
}
if(targetKey.KeyHeader.BlobType == targetBlob) {
fullKey = targetKey;
CSSM_DeleteContext(ccHand);
return CSSM_OK;
}
CSSM_CONTEXT_ATTRIBUTE attr;
memset(&attr, 0, sizeof(attr));
attr.AttributeType = CSSM_ATTRIBUTE_PARAM_KEY;
crtn = CSSM_DeleteContextAttributes(ccHand, 1, &attr);
if(crtn) {
printError("CSSM_DeleteContextAttributes", crtn);
return crtn;
}
if(targetBlob == CSSM_KEYBLOB_REFERENCE) {
crtn = CSSM_UnwrapKey(ccHand,
NULL, &targetKey,
hdr.KeyUsage, CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF,
&label,
NULL, &fullKey,
&descrData); if(crtn) {
printError("dsaMergeParams CSSM_UnwrapKey (2)", crtn);
return crtn;
}
}
else {
crtn = CSSM_WrapKey(ccHand,
&creds,
&targetKey,
NULL, &fullKey);
if(crtn) {
printError("dsaMergeParams CSSM_WrapKey (2)", crtn);
return crtn;
}
}
CSSM_FreeKey(cspHand, NULL, &targetKey, CSSM_FALSE);
CSSM_DeleteContext(ccHand);
return CSSM_OK;
}
CSSM_RETURN sigVerify(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, CSSM_KEY_PTR paramKey, const CSSM_DATA *ptext,
const CSSM_DATA *sig,
CSSM_RETURN expectResult,
const char *op,
CSSM_BOOL verbose)
{
CSSM_CC_HANDLE sigHand;
CSSM_RETURN ocrtn = CSSM_OK;
CSSM_RETURN crtn;
if(verbose) {
printf(" ...%s\n", op);
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
algorithm,
NULL, key,
&sigHand);
if(crtn) {
printError("CSSM_CSP_CreateSignatureContext", crtn);
return crtn;
}
if(paramKey) {
crtn = AddContextAttribute(sigHand,
CSSM_ATTRIBUTE_PARAM_KEY,
sizeof(CSSM_KEY),
CAT_Ptr,
paramKey,
0);
if(crtn) {
printError("AddContextAttribute", crtn);
return crtn;
}
}
crtn = CSSM_VerifyData(sigHand,
ptext,
1,
CSSM_ALGID_NONE,
sig);
if(crtn != expectResult) {
if(!crtn) {
printf("%s: Unexpected good Sig Verify (expect %s)\n",
op, cssmErrToStr(expectResult));
ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
}
else {
printError(op, crtn);
ocrtn = crtn;
}
}
CSSM_DeleteContext(sigHand);
return ocrtn;
}
static int doTest(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR privKey_0,
CSSM_KEY_PTR pubKeyBase_0,
CSSM_KEY_PTR pubKeyPartial_0,
CSSM_KEY_PTR pubKeyParam_0, CSSM_KEY_PTR pubKeyPartial_1,
CSSM_KEY_PTR pubKeyParam_1, bool mergedIsRef,
CSSM_BOOL quiet,
CSSM_BOOL verbose)
{
uint8 ptextBuf[MAX_PTEXT_SIZE];
CSSM_DATA ptext = {0, ptextBuf};
simpleGenData(&ptext, 1, MAX_PTEXT_SIZE);
CSSM_DATA sig = {0, NULL};
CSSM_RETURN crtn;
crtn = cspSign(cspHand, SIG_ALG, privKey_0, &ptext, &sig);
if(crtn) {
return testError(quiet);
}
crtn = sigVerify(cspHand, SIG_ALG, pubKeyBase_0, NULL,
&ptext, &sig, CSSM_OK, "vfy with full key", verbose);
if(crtn) {
return testError(quiet);
}
crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_0, pubKeyParam_0,
&ptext, &sig, CSSM_OK, "vfy with partial key and params",
verbose);
if(crtn) {
if(testError(quiet)) {
return 1;
}
}
crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_0, NULL,
&ptext, &sig,
CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE,
"vfy with partial key no params", verbose);
if(crtn) {
if(testError(quiet)) {
return 1;
}
}
crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_0, pubKeyParam_1,
&ptext, &sig,
CSSMERR_CSP_VERIFY_FAILED,
"vfy with partial key wrong params", verbose);
if(crtn) {
if(testError(quiet)) {
return 1;
}
}
crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_1, pubKeyParam_0,
&ptext, &sig,
CSSMERR_CSP_VERIFY_FAILED,
"vfy with wrong partial key, good params", verbose);
if(crtn) {
if(testError(quiet)) {
return 1;
}
}
CSSM_KEY merged;
crtn = dsaMergeParams(cspHand,
pubKeyPartial_0,
pubKeyParam_0,
merged,
mergedIsRef);
if(crtn) {
return testError(quiet);
}
crtn = sigVerify(cspHand, SIG_ALG, &merged, NULL,
&ptext, &sig, CSSM_OK, "vfy with good merged key", verbose);
if(crtn) {
return testError(quiet);
}
CSSM_FreeKey(cspHand, NULL, &merged, CSSM_FALSE);
crtn = dsaMergeParams(cspHand,
pubKeyPartial_0,
pubKeyParam_1,
merged,
mergedIsRef);
if(crtn) {
return testError(quiet);
}
crtn = sigVerify(cspHand, SIG_ALG, &merged, NULL,
&ptext, &sig,
CSSMERR_CSP_VERIFY_FAILED,
"vfy with merged key wrong params", verbose);
if(crtn) {
if(testError(quiet)) {
return 1;
}
}
CSSM_FreeKey(cspHand, NULL, &merged, CSSM_FALSE);
CSSM_FREE(sig.Data);
return CSSM_OK;
}
int main(int argc, char **argv)
{
char *argp;
CSSM_CSP_HANDLE cspHand;
CSSM_RETURN crtn;
unsigned loops = LOOPS_DEF;
CSSM_BOOL doPause = CSSM_FALSE;
CSSM_BOOL quiet = CSSM_FALSE;
CSSM_BOOL rawCSP = CSSM_TRUE;
CSSM_BOOL verbose = CSSM_FALSE;
uint32 keySize = KEY_SIZE_DEF;
CSSM_BOOL allRaw = CSSM_FALSE;
CSSM_BOOL allRef = CSSM_FALSE;
for(int arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'l':
loops = atoi(&argp[2]);
break;
case 'q':
quiet = CSSM_TRUE;
break;
case 'p':
doPause = CSSM_TRUE;
break;
case 'v':
verbose = CSSM_TRUE;
break;
case 'D':
rawCSP = CSSM_FALSE;
break;
case 'r':
allRaw = CSSM_TRUE;
break;
case 'f':
allRef = CSSM_TRUE;
break;
default:
usage(argv);
}
}
if(!rawCSP && (allRaw || allRef)) {
printf("CSPDL inconsistent with allRef and allRaw\n");
usage(argv);
}
if(allRef && allRaw) {
printf("allRef and allRaw are mutually exclusive\n");
usage(argv);
}
CSSM_DATA params1;
CSSM_DATA params2;
unsigned len;
if(readFile(PARAMS_512_1, (unsigned char **)¶ms1.Data, &len)) {
printf("***Error reading %s. Aborting.\n", PARAMS_512_1);
printf("***This test must be run from the cspxutils/dsaPartial directory.\n");
exit(1);
}
params1.Length = len;
if(readFile(PARAMS_512_2, (unsigned char **)¶ms2.Data, &len)) {
printf("***Error reading %s. Aborting.\n", PARAMS_512_2);
printf("***This test must be run from the cspxutils/dsaPartial directory.\n");
exit(1);
}
params2.Length = len;
printf("Starting dsaPartial; args: ");
for(int i=1; i<argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
cspHand = cspDlDbStartup(rawCSP, NULL);
if(cspHand == 0) {
exit(1);
}
CSSM_KEY dsa1Priv;
CSSM_KEY dsa1Pub;
CSSM_KEY dsa2Priv;
CSSM_KEY dsa2Pub;
if(verbose) {
printf("...generating keys...\n");
}
CSSM_BOOL genRefKeys = CSSM_FALSE;
if(!rawCSP || allRef) {
genRefKeys = CSSM_TRUE;
}
crtn = genDsaKeyPair(cspHand, keySize,
&dsa1Pub, genRefKeys,
&dsa1Priv, genRefKeys,
¶ms1);
if(crtn) {
exit(1);
}
crtn = genDsaKeyPair(cspHand, keySize,
&dsa2Pub, genRefKeys,
&dsa2Priv, genRefKeys,
¶ms2);
if(crtn) {
exit(1);
}
CSSM_KEY dsa1PubParam;
CSSM_KEY dsa2PubParam;
if(!rawCSP) {
if(cspRefKeyToRaw(cspHand, &dsa1Pub, &dsa1PubParam) ||
cspRefKeyToRaw(cspHand, &dsa2Pub, &dsa2PubParam)) {
exit(1);
}
}
CSSM_KEY dsa1PubPartial;
CSSM_KEY dsa2PubPartial;
crtn = extractDsaPartial(cspHand, &dsa1Pub, &dsa1PubPartial);
if(crtn) {
exit(1);
}
crtn = extractDsaPartial(cspHand, &dsa2Pub, &dsa2PubPartial);
if(crtn) {
exit(1);
}
CSSM_KEY dsa1PubRef;
CSSM_KEY dsa2PubRef;
CSSM_KEY dsa1PubPartialRef;
CSSM_KEY dsa2PubPartialRef;
if(rawCSP && !allRaw && !allRef) { if(cspRawKeyToRef(cspHand, &dsa1Pub, &dsa1PubRef) ||
cspRawKeyToRef(cspHand, &dsa2Pub, &dsa2PubRef)) {
exit(1);
}
}
if(!rawCSP || !allRaw) {
if(cspRawKeyToRef(cspHand, &dsa1PubPartial,
&dsa1PubPartialRef) ||
cspRawKeyToRef(cspHand, &dsa2PubPartial,
&dsa2PubPartialRef)) {
exit(1);
}
if(!(dsa1PubPartialRef.KeyHeader.KeyAttr &
CSSM_KEYATTR_PARTIAL)) {
printf("***CSSM_KEYATTR_PARTIAL not set after null unwrap"
" of partial DSA key\n");
if(testError(quiet)) {
exit(1);
}
}
if(!(dsa2PubPartialRef.KeyHeader.KeyAttr &
CSSM_KEYATTR_PARTIAL)) {
printf("***CSSM_KEYATTR_PARTIAL not set after null unwrap"
" of partial DSA key\n");
if(testError(quiet)) {
exit(1);
}
}
}
int rtn = 0;
for(unsigned loop=0; loop<loops; loop++) {
CSSM_KEY_PTR pubKey_a;
CSSM_KEY_PTR pubKey_b;
CSSM_KEY_PTR pubKeyPartial_a;
CSSM_KEY_PTR pubKeyPartial_b;
bool mergedIsRef;
if(allRef) {
pubKey_a = &dsa1Pub;
pubKey_b = &dsa2Pub;
pubKeyPartial_a = &dsa1PubPartialRef;
pubKeyPartial_b = &dsa2PubPartialRef;
mergedIsRef = true;
}
else if(allRaw) {
pubKey_a = &dsa1Pub;
pubKey_b = &dsa2Pub;
pubKeyPartial_a = &dsa1PubPartial;
pubKeyPartial_b = &dsa2PubPartial;
mergedIsRef = false;
}
else if(!rawCSP) {
pubKey_a = &dsa1Pub;
pubKey_b = &dsa2Pub;
pubKeyPartial_a = &dsa1PubPartialRef;
pubKeyPartial_b = &dsa2PubPartialRef;
mergedIsRef = true;
}
else {
pubKey_a = (loop & 1) ? &dsa1Pub : &dsa1PubRef;
pubKey_b = (loop & 2) ? &dsa2Pub : &dsa2PubRef;
pubKeyPartial_a = (loop & 4) ?
&dsa1PubPartial : &dsa1PubPartialRef;
pubKeyPartial_b = (loop & 8) ?
&dsa2PubPartial : &dsa2PubPartialRef;
mergedIsRef = (loop & 2) ? true : false;
}
CSSM_KEY_PTR pubKeyParam_a = pubKey_a;
CSSM_KEY_PTR pubKeyParam_b = pubKey_b;
if(!rawCSP) {
pubKeyParam_a = &dsa1PubParam;
pubKeyParam_b = &dsa2PubParam;
}
if(!quiet) {
printf("...loop %u\n", loop);
}
rtn = doTest(cspHand, &dsa1Priv,
pubKey_a, pubKeyPartial_a, pubKeyParam_a,
pubKeyPartial_b, pubKeyParam_b,
mergedIsRef, quiet, verbose);
if(rtn) {
break;
}
if(doPause) {
fpurge(stdin);
printf("Hit CR to proceed, q to quit: ");
char inch = getchar();
if(inch == 'q') {
break;
}
}
}
return(rtn);
}