Example #1
0
/* 
 * Sign/verify wrappers.  
 */
static CSSM_RETURN sigSign(CSSM_CSP_HANDLE cspHandle,
	uint32 algorithm,					// CSSM_ALGID_SHA1WithRSA, etc.
	CSSM_KEY_PTR key,					// private key
	const CSSM_DATA *text,
	CSSM_DATA_PTR sig)
{
	CSSM_CC_HANDLE	sigHand;
	CSSM_RETURN		crtn;
	
	crtn = CSSM_CSP_CreateSignatureContext(cspHandle,
		algorithm,
		NULL,				// passPhrase
		key,
		&sigHand);
	if(crtn) {
		return crtn;
	}
	crtn = CSSM_SignData(sigHand,
		text,
		1,
		CSSM_ALGID_NONE,
		sig);
	CSSM_DeleteContext(sigHand);
	return crtn;
}
Example #2
0
static int
kc_rsa_private_encrypt(int flen,
		       const unsigned char *from,
		       unsigned char *to,
		       RSA *rsa,
		       int padding)
{
    struct kc_rsa *kc = RSA_get_app_data(rsa);

    CSSM_RETURN cret;
    OSStatus ret;
    const CSSM_ACCESS_CREDENTIALS *creds;
    SecKeyRef privKeyRef = (SecKeyRef)kc->item;
    CSSM_CSP_HANDLE cspHandle;
    const CSSM_KEY *cssmKey;
    CSSM_CC_HANDLE sigHandle = 0;
    CSSM_DATA sig, in;
    int fret = 0;

    if (padding != RSA_PKCS1_PADDING)
	return -1;

    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
    if(cret) abort();

    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
    if(cret) abort();

    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
			       kSecCredentialTypeDefault, &creds);
    if(ret) abort();

    ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
					  creds, cssmKey, &sigHandle);
    if(ret) abort();

    in.Data = (uint8 *)from;
    in.Length = flen;

    sig.Data = (uint8 *)to;
    sig.Length = kc->keysize;

    cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
    if(cret) {
	/* cssmErrorString(cret); */
	fret = -1;
    } else
	fret = sig.Length;

    if(sigHandle)
	CSSM_DeleteContext(sigHandle);

    return fret;
}
static int doSign(
	CSSM_CSP_HANDLE	cspHand,
	const char *algStr,
	CSSM_KEY_PTR key,			// private
	CSSM_ALGORITHMS sigAlg,
	CSSM_RETURN expRtn,			// expected result
	CSSM_BOOL quiet)
{
	uint8 ptextData[PTEXT_SIZE];
	CSSM_DATA ptext = {PTEXT_SIZE, ptextData};
	CSSM_DATA sig = {0, NULL};
	
	simpleGenData(&ptext, PTEXT_SIZE, PTEXT_SIZE);
	
	CSSM_CC_HANDLE cryptHand = 0;
	CSSM_RETURN crtn;
	
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
		sigAlg,
		NULL,				// passPhrase
		key,
		&cryptHand);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
		return testError(quiet);
	}
	int irtn = 0;
	crtn = CSSM_SignData(cryptHand,
		&ptext,
		1,
		CSSM_ALGID_NONE,
		&sig);
	if(crtn != expRtn) {
		if(expRtn == CSSM_OK) {
			printError("CSSM_SignData", crtn);
			printf("Unexpected error signing with %s\n", algStr);
		}
		else {
			printf("***Sign with %s: expected %s, got %s.\n",
				algStr, cssmErrToStr(expRtn),
				cssmErrToStr(crtn));
		}
		irtn = testError(quiet);
	}
	appFreeCssmData(&sig, CSSM_FALSE);
	CSSM_DeleteContext(cryptHand);
	return irtn;
}
/* 
 * Sign/verify optional "no padding" context attr 
 */
static CSSM_RETURN sigSign(CSSM_CSP_HANDLE cspHand,
	uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
	CSSM_KEY_PTR key,					// private key
	const CSSM_DATA *text,
	CSSM_DATA_PTR sig,
	uint32 digestAlg,					// optional for raw signing
	CSSM_BOOL noPad)					// true --> add PADDING_NONE to context
{
	CSSM_CC_HANDLE	sigHand;
	CSSM_RETURN		crtn;
	
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
		algorithm,
		NULL,				// passPhrase
		key,
		&sigHand);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext", crtn);
		return crtn;
	}
	if(noPad) {
		crtn = AddContextAttribute(sigHand,
			CSSM_ATTRIBUTE_PADDING,
			sizeof(uint32),
			CAT_Uint32,
			NULL,
			CSSM_PADDING_NONE);
		if(crtn) {
			return crtn;
		}
	}
	crtn = CSSM_SignData(sigHand,
		text,
		1,
		digestAlg,
		sig);
	if(crtn) {
		printError("CSSM_SignData", crtn);
	}
	CSSM_DeleteContext(sigHand);
	return crtn;
}
SECStatus
ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
                        PRBool isTLS, KeyType keyType)
{
    SECStatus       rv                  = SECFailure;
    PRBool          doDerEncode         = PR_FALSE;
    unsigned int    signatureLen;
    OSStatus        status              = noErr;
    CSSM_CSP_HANDLE cspHandle           = 0;
    const CSSM_KEY *cssmKey             = NULL;
    CSSM_ALGORITHMS sigAlg;
    CSSM_ALGORITHMS digestAlg;
    const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL;
    CSSM_RETURN     cssmRv;
    CSSM_DATA       hashData;
    CSSM_DATA       signatureData;
    CSSM_CC_HANDLE  cssmSignature       = 0;
    const SSL3Opaque* prefix;
    unsigned int    prefixLen;
    SSL3Opaque      prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX];

    buf->data = NULL;

    status = SecKeyGetCSPHandle(key, &cspHandle);
    if (status != noErr) {
        PORT_SetError(SEC_ERROR_INVALID_KEY);
        goto done;
    }

    status = SecKeyGetCSSMKey(key, &cssmKey);
    if (status != noErr || !cssmKey) {
        PORT_SetError(SEC_ERROR_NO_KEY);
        goto done;
    }

    /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
     * needed information is readily available on the key itself.
     */
    signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;

    if (signatureLen == 0) {
        PORT_SetError(SEC_ERROR_INVALID_KEY);
        goto done;
    }

    buf->data = (unsigned char *)PORT_Alloc(signatureLen);
    if (!buf->data)
        goto done;    /* error code was set. */

    sigAlg = cssmKey->KeyHeader.AlgorithmId;
    digestAlg = CSSM_ALGID_NONE;

    switch (keyType) {
        case rsaKey:
            PORT_Assert(sigAlg == CSSM_ALGID_RSA);
            if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) !=
                SECSuccess) {
                goto done;
            }
            if (prefixLen + hash->len > sizeof(prefixAndHash)) {
                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
                goto done;
            }
            memcpy(prefixAndHash, prefix, prefixLen);
            memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len);
            hashData.Data   = prefixAndHash;
            hashData.Length = prefixLen + hash->len;
            break;
        case dsaKey:
        case ecKey:
            if (keyType == ecKey) {
                PORT_Assert(sigAlg == CSSM_ALGID_ECDSA);
                doDerEncode = PR_TRUE;
            } else {
                PORT_Assert(sigAlg == CSSM_ALGID_DSA);
                doDerEncode = isTLS;
            }
            if (hash->hashAlg == SEC_OID_UNKNOWN) {
                hashData.Data   = hash->u.s.sha;
                hashData.Length = sizeof(hash->u.s.sha);
            } else {
                hashData.Data   = hash->u.raw;
                hashData.Length = hash->len;
            }
            break;
        default:
            PORT_SetError(SEC_ERROR_INVALID_KEY);
            goto done;
    }
    PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length));

    /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
     * you can prevent the UI by setting the provider handle on the
     * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
     */
    status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN,
                                  kSecCredentialTypeDefault, &cssmCreds);
    if (status != noErr) {
        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status);
        goto done;
    }

    signatureData.Length = signatureLen;
    signatureData.Data   = (uint8*)buf->data;

    cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds,
                                             cssmKey, &cssmSignature);
    if (cssmRv) {
        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
        goto done;
    }

    /* See "Apple Cryptographic Service Provider Functional Specification" */
    if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
        /* To set RSA blinding for RSA keys */
        CSSM_CONTEXT_ATTRIBUTE blindingAttr;
        blindingAttr.AttributeType   = CSSM_ATTRIBUTE_RSA_BLINDING;
        blindingAttr.AttributeLength = sizeof(uint32);
        blindingAttr.Attribute.Uint32 = 1;
        cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr);
        if (cssmRv) {
            PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
            goto done;
        }
    }

    cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg,
                           &signatureData);
    if (cssmRv) {
        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
        goto done;
    }
    buf->len = signatureData.Length;

    if (doDerEncode) {
        SECItem derSig = {siBuffer, NULL, 0};

        /* This also works for an ECDSA signature */
        rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
        if (rv == SECSuccess) {
            PORT_Free(buf->data);     /* discard unencoded signature. */
            *buf = derSig;            /* give caller encoded signature. */
        } else if (derSig.data) {
            PORT_Free(derSig.data);
        }
    } else {
        rv = SECSuccess;
    }

    PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
done:
    /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
     * should not be freed. When the PlatformKey is freed, they will be
     * released.
     */
    if (cssmSignature)
        CSSM_DeleteContext(cssmSignature);

    if (rv != SECSuccess && buf->data) {
        PORT_Free(buf->data);
        buf->data = NULL;
    }
    return rv;
}
static int
kc_rsa_sign(int type, const unsigned char *from, unsigned int flen,
	    unsigned char *to, unsigned int *tlen, const RSA *rsa)
{
    struct kc_rsa *kc = RSA_get_app_data(rk_UNCONST(rsa));

    CSSM_RETURN cret;
    OSStatus ret;
    const CSSM_ACCESS_CREDENTIALS *creds;
    SecKeyRef privKeyRef = kc->pkey;
    CSSM_CSP_HANDLE cspHandle;
    const CSSM_KEY *cssmKey;
    CSSM_CC_HANDLE sigHandle = 0;
    CSSM_DATA sig, in;
    int fret = 0;
    CSSM_ALGORITHMS stype;

    if (type == NID_md5) {
	stype = CSSM_ALGID_MD5;
    } else if (type == NID_sha1) {
	stype = CSSM_ALGID_SHA1;
    } else if (type == NID_sha256) {
	stype = CSSM_ALGID_SHA256;
    } else if (type == NID_sha384) {
	stype = CSSM_ALGID_SHA384;
    } else if (type == NID_sha512) {
	stype = CSSM_ALGID_SHA512;
    } else
	return -1;

    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
    if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", cret);

    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
    if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", cret);

    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
			       kSecCredentialTypeNoUI, &creds);
    if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret);

    ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
					  creds, cssmKey, &sigHandle);
    if(ret) heim_abort("CSSM_CSP_CreateSignatureContext failed: %d", (int)ret);

    in.Data = (uint8 *)from;
    in.Length = flen;

    sig.Data = (uint8 *)to;
    sig.Length = kc->keysize;

    cret = CSSM_SignData(sigHandle, &in, 1, stype, &sig);
    if(cret) {
	/* cssmErrorString(cret); */
	fret = -1;
    } else {
	fret = 1;
	*tlen = (unsigned int)sig.Length;
    }

    if(sigHandle)
	CSSM_DeleteContext(sigHandle);

    return fret;
}
/* sign with RSA blinging option */
static CSSM_RETURN _cspSign(CSSM_CSP_HANDLE cspHand,
		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
		CSSM_KEY_PTR key,					// private key
		const CSSM_DATA *text,
		CSSM_BOOL rsaBlinding,
		CSSM_DATA_PTR sig)					// RETURNED
{
	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;

	/* handle special cases for raw sign */
	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,			// mallocDigest
			text,
			&digest);
		if(crtn) {
			return crtn;
		}	
		/* sign digest with raw RSA/DSA */
		ptext = &digest;
	}
	else {
		ptext = text;
	}
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
		algorithm,
		NULL,				// passPhrase
		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;
}
int main(int argc, char **argv)
{
	int					arg;
	char				*argp;
	unsigned			oloop;
	unsigned			iloop;
	CSSM_DATA			ptext = {0, NULL};
	CSSM_CSP_HANDLE 	cspHand;
	int					i;
	int					rtn = 0;
	uint32				keySizeInBits = 0;
	CSSM_KEY			pubKey;
	CSSM_KEY			privKey;
	CSSM_DATA			sig = {0, NULL};
	CSSM_DATA			digest = {0, NULL};
	CSSM_RETURN			crtn;
	const char			*digestStr;
	
	/*
	 * User-spec'd params
	 */
	CSSM_BOOL			keySizeSpec = CSSM_FALSE;
	unsigned			oloops = OLOOPS_DEF;
	unsigned			iloops = ILOOPS_DEF;
	CSSM_BOOL			verbose = CSSM_FALSE;
	CSSM_BOOL			quiet = CSSM_FALSE;
	unsigned			pauseInterval = 0;
	CSSM_BOOL			bareCsp = CSSM_TRUE;
	CSSM_ALGORITHMS		rawSigAlg = CSSM_ALGID_RSA;
	
	for(arg=1; arg<argc; arg++) {
		argp = argv[arg];
		switch(argp[0]) {
			case 'a':
				switch(argp[2]) {
					case 'r':
						rawSigAlg = CSSM_ALGID_RSA;
						break;
					case 'd':
						rawSigAlg = CSSM_ALGID_DSA;
						break;
					default:
						usage(argv);
				}
				break;
		    case 'l':
				oloops = atoi(&argp[2]);
				break;
		    case 'i':
				iloops = atoi(&argp[2]);
				break;
		    case 'k':
		    	keySizeInBits = atoi(&argp[2]);
				keySizeSpec = CSSM_TRUE;
				break;
		    case 'v':
		    	verbose = CSSM_TRUE;
				break;
			case 'D':
				bareCsp = CSSM_FALSE;
				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);
	}
	/* ptext length set in inner test loop */
	
	printf("Starting rawRsaSig; 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(oloop=0; ; oloop++) {
		
		/* key size? */
		if(!keySizeSpec) {
			/* random key size */
			keySizeInBits = randKeySizeBits(rawSigAlg, OT_Sign);
		}

		if(!quiet) {
			if(verbose || ((oloop % LOOP_NOTIFY) == 0)) {
				printf("...oloop %d   keySize %u\n", oloop, (unsigned)keySizeInBits);
			}
		}
		
		/* generate a key pair */
		crtn = cspGenKeyPair(cspHand,
			rawSigAlg,
			"foo",
			3,
			keySizeInBits,
			&pubKey,
			CSSM_TRUE,						// all keys ref for speed
			CSSM_KEYUSE_VERIFY,
			CSSM_KEYBLOB_RAW_FORMAT_NONE,
			&privKey,
			CSSM_TRUE,
			CSSM_KEYUSE_SIGN,
			CSSM_KEYBLOB_RAW_FORMAT_NONE,
			CSSM_FALSE);					// genSeed not used 
		if(crtn) {
			return testError(quiet);
		}
		
		for(iloop=0; iloop<iloops; iloop++) {
		
			CSSM_ALGORITHMS		sigAlg;
			CSSM_ALGORITHMS		digestAlg;
			CSSM_CC_HANDLE		sigHand;
			
			/* alternate digest algs for RSA */
			if(rawSigAlg == CSSM_ALGID_RSA) {
				if(iloop & 1) {
					sigAlg = CSSM_ALGID_SHA1WithRSA;
					digestAlg = CSSM_ALGID_SHA1;
					digestStr = "SHA1";
				}
				else {
					sigAlg = CSSM_ALGID_MD5WithRSA;
					digestAlg = CSSM_ALGID_MD5;
					digestStr = "MD5 ";
				}
			}
			else {
				sigAlg = CSSM_ALGID_SHA1WithDSA;
				digestAlg = CSSM_ALGID_SHA1;
				digestStr = "SHA1";
			}
			
			/* new plaintext each inner loop */
			simpleGenData(&ptext, 1, MAX_TEXT_SIZE);
			if(!quiet) {
				if(verbose || ((iloop % LOOP_NOTIFY) == 0)) {
					printf("   ...iloop %d  digest %s  text size %lu\n", 
						iloop, digestStr, ptext.Length);
				}
			}
			
			/*** phase 1 ***/
			
			/* digest+sign */
			crtn = cspStagedSign(cspHand,
				sigAlg,
				&privKey,
				&ptext,
				DO_MULTI_UPDATE,			// multiUpdates
				&sig);
			if(crtn && testError(quiet)) {
				goto abort;
			}
			
			/* digest */
			crtn = cspStagedDigest(cspHand,
				digestAlg,
				CSSM_FALSE,			// mallocDigest
				DO_MULTI_UPDATE,	// multiUpdates
				&ptext, 
				&digest);
			if(crtn && testError(quiet)) {
				goto abort;
			}
			
			/* raw RSA/DSA verify */
			crtn = CSSM_CSP_CreateSignatureContext(cspHand,
				rawSigAlg,
				NULL,				// passPhrase
				&pubKey,
				&sigHand);
			if(crtn) {
				printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
				return crtn;
			}
			crtn = CSSM_VerifyData(sigHand,
				&digest,
				1,
				digestAlg,
				&sig);
			if(crtn) {
				printError("CSSM_VerifyData(raw RSA)", crtn);
				if(testError(quiet)) {
					goto abort;
				}
			}
			
			/* free resources - reuse the digest for raw sign */
			appFreeCssmData(&sig, CSSM_FALSE);
			CSSM_DeleteContext(sigHand);
			
			/*** phase 2 ***/
			
			/* raw RSA/DSA sign */
			crtn = CSSM_CSP_CreateSignatureContext(cspHand,
				rawSigAlg,
				NULL,				// passPhrase
				&privKey,
				&sigHand);
			if(crtn) {
				printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
				return crtn;
			}
			crtn = CSSM_SignData(sigHand,
				&digest,
				1,
				digestAlg,
				&sig);
			if(crtn) {
				printError("CSSM_SignData(raw RSA)", crtn);
				if(testError(quiet)) {
					goto abort;
				}
			}

			/* all-in-one verify */
			crtn = cspStagedSigVerify(cspHand,
				sigAlg,
				&pubKey,
				&ptext,
				&sig,
				DO_MULTI_UPDATE,		// multiUpdates
				CSSM_OK);
			if(crtn && testError(quiet)) {
				goto abort;
			}
			
			/* clean up */
			appFreeCssmData(&sig, CSSM_FALSE);
			appFreeCssmData(&digest, CSSM_FALSE);
			CSSM_DeleteContext(sigHand);
		}	/* end of inner loop */

		/* free keys */
		cspFreeKey(cspHand, &pubKey);
		cspFreeKey(cspHand, &privKey);

		if(oloops && (oloop == oloops)) {
			break;
		}
		if(pauseInterval && ((oloop % pauseInterval) == 0)) {
			fpurge(stdin);
			printf("hit CR to proceed: ");
			getchar();
		}
	}
	
abort:
	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;
}