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;
}
/* verify a cert using specified key and/or signerCert */
static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand,
	CSSM_CSP_HANDLE	cspHand,
	CSSM_DATA_PTR	cert,
	CSSM_DATA_PTR	signerCert,		// optional
	CSSM_KEY_PTR	key,			// ditto, to work spec one, other, or both
	CSSM_ALGORITHMS	sigAlg,			// CSSM_ALGID_SHA1WithRSA, etc. 
	CSSM_RETURN		expectResult,
	const char 		*opString)
{
	CSSM_RETURN		crtn;
	CSSM_CC_HANDLE	signContext = CSSM_INVALID_HANDLE;

	if(key) {
		crtn = CSSM_CSP_CreateSignatureContext(cspHand,
				sigAlg,
				NULL,				// AccessCred
				key,
				&signContext);
		if(crtn) {
			printf("Failure during %s\n", opString);
			printError("CSSM_CSP_CreateSignatureContext", crtn);
			return crtn;
		}
	}
	crtn = CSSM_CL_CertVerify(clHand,
		signContext,
		cert,					// CertToBeVerified
		signerCert,				// SignerCert
		NULL,					// VerifyScope 
		0);						// ScopeSize
	if(crtn != expectResult) {
		printf("Failure during %s\n", opString);
		if(crtn == CSSM_OK) {
			printf("Unexpected CSSM_CL_CertVerify success\n");
		}
		else if(expectResult == CSSM_OK) {
			printError("CSSM_CL_CertVerify", crtn);
		}
		else {
			printError("CSSM_CL_CertVerify: expected", expectResult);
			printError("CSSM_CL_CertVerify: got     ", crtn);
		}
		return CSSMERR_CL_VERIFICATION_FAILURE;
	}
	if(signContext != CSSM_INVALID_HANDLE) {
		crtn = CSSM_DeleteContext(signContext);
		if(crtn) {
			printf("Failure during %s\n", opString);
			printError("CSSM_DeleteContext", crtn);
			return crtn;
		}
	}
	return CSSM_OK;
}
Example #3
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 doVerify(
	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};
	uint8 sigData[PTEXT_SIZE];
	CSSM_DATA sig = {PTEXT_SIZE, sigData};
	
	simpleGenData(&ptext, PTEXT_SIZE, PTEXT_SIZE);
	memset(sigData, 0, 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 (2)", crtn);
		return testError(quiet);
	}
	int irtn = 0;
	crtn = CSSM_VerifyData(cryptHand,
		&ptext,
		1,
		CSSM_ALGID_NONE,
		&sig);
	if(crtn != expRtn) {
		if(expRtn == CSSM_OK) {
			printError("CSSM_VerifyData", crtn);
			printf("Unexpected error verifying with %s\n", algStr);
		}
		else {
			printf("***Verify with %s: expected %s, got %s.\n",
				algStr, cssmErrToStr(expRtn),
				cssmErrToStr(crtn));
		}
		irtn = testError(quiet);
	}
	CSSM_DeleteContext(cryptHand);
	return irtn;
}
static CSSM_RETURN sigVerify(CSSM_CSP_HANDLE cspHand,
	uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
	CSSM_KEY_PTR key,					// public key
	const CSSM_DATA *text,
	const CSSM_DATA *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_VerifyData(sigHand,
		text,
		1,
		digestAlg,
		sig);
	if(crtn) {
		printError("CSSM_VerifyData", crtn);
	}
	CSSM_DeleteContext(sigHand);
	return crtn;
}
int main(int argc, char **argv)
{
	CSSM_CL_HANDLE	clHand;			// CL handle
	CSSM_X509_NAME	*subjName;
	CSSM_X509_NAME	*rootName;
	CSSM_X509_TIME	*notBefore;		// UTC-style "not before" time
	CSSM_X509_TIME	*notAfter;		// UTC-style "not after" time
	CSSM_DATA_PTR	rawCert;		// from CSSM_CL_CertCreateTemplate
	CSSM_DATA		signedRootCert;	// from CSSM_CL_CertSign
	CSSM_DATA		signedSubjCert;	// from CSSM_CL_CertSign
	CSSM_CSP_HANDLE	cspHand;		// CSP handle
	CSSM_KEY		subjPubKey;		// subject's RSA public key blob
	CSSM_KEY		subjPrivKey;	// subject's RSA private key - ref format
	CSSM_KEY		rootPubKey;		// root's RSA public key blob
	CSSM_KEY		rootPrivKey;	// root's RSA private key - ref format
	CSSM_RETURN		crtn;
	CSSM_KEY_PTR	extractRootKey;	// from CSSM_CL_CertGetKeyInfo()
	CSSM_KEY_PTR	extractSubjKey;	// ditto
	CSSM_CC_HANDLE	signContext;	// for signing/verifying the cert
	unsigned		badByte;
	int				arg;
	unsigned		errorCount = 0;
	
	/* user-spec'd variables */
	CSSM_BOOL		writeBlobs = CSSM_FALSE;
	CSSM_ALGORITHMS	keyAlg = KEY_ALG_DEFAULT;
	CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT;
	uint32			keySizeInBits = CSP_KEY_SIZE_DEFAULT;
	
	/* 
	 * Two extensions. Subject has one (KeyUsage); root has KeyUsage and 
	 * BasicConstraints.
	 */
	CSSM_X509_EXTENSION 	exts[2];
	CE_KeyUsage				keyUsage;
	CE_BasicConstraints		bc;
	
	for(arg=1; arg<argc; arg++) {
		switch(argv[arg][0]) {
			case 'w':
				writeBlobs = CSSM_TRUE;
				break;
			case 'a':
				if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) {
					usage(argv);
				}
				switch(argv[arg][2]) {
					case 's':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA1WithRSA;
						break;
					case 'm':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_MD5WithRSA;
						break;
					case 'f':
						keyAlg = CSSM_ALGID_FEE;
						sigAlg = CSSM_ALGID_FEE_MD5;
						break;
					case 'F':
						keyAlg = CSSM_ALGID_FEE;
						sigAlg = CSSM_ALGID_FEE_SHA1;
						break;
					case 'e':
						keyAlg = CSSM_ALGID_FEE;
						sigAlg = CSSM_ALGID_SHA1WithECDSA;
						break;
					case 'E':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA1WithECDSA;
						break;
					case '7':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA256WithECDSA;
						break;
					case '8':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA384WithECDSA;
						break;
					case '9':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA512WithECDSA;
						break;
					case '2':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA224WithRSA;
						break;
					case '6':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA256WithRSA;
						break;
					case '3':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA384WithRSA;
						break;
					case '5':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA512WithRSA;
						break;
					default:
						usage(argv);
				}
				break;
		    case 'k':
				keySizeInBits = atoi(&argv[arg][2]);
				break;
			default:
				usage(argv);
		}
	}
	
	/* connect to CL and CSP */
	clHand = clStartup();
	if(clHand == 0) {
		return 0;
	}
	cspHand = cspStartup();
	if(cspHand == 0) {
		return 0;
	}

	/* subsequent errors to abort: to detach */
	
	/* cook up an RSA key pair for the subject */
	crtn = cspGenKeyPair(cspHand,
		keyAlg,
		SUBJ_KEY_LABEL,
		strlen(SUBJ_KEY_LABEL),
		keySizeInBits,
		&subjPubKey,
		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
		CSSM_KEYUSE_VERIFY,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		&subjPrivKey,
		CSSM_FALSE,			// privIsRef
		CSSM_KEYUSE_SIGN,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		CSSM_FALSE);
	if(crtn) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(SUBJ_PRIV_KEY_FILE, subjPrivKey.KeyData.Data,
			subjPrivKey.KeyData.Length);
		printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length,
			SUBJ_PRIV_KEY_FILE);
	}

	/* and the root */
	crtn = cspGenKeyPair(cspHand,
		keyAlg,
		ROOT_KEY_LABEL,
		strlen(ROOT_KEY_LABEL),
		keySizeInBits,
		&rootPubKey,
		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
		CSSM_KEYUSE_VERIFY,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		&rootPrivKey,
		CSSM_FALSE,			// privIsRef
		CSSM_KEYUSE_SIGN,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		CSSM_FALSE);
	if(crtn) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(ROOT_PRIV_KEY_FILE, rootPrivKey.KeyData.Data,
			rootPrivKey.KeyData.Length);
		printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length,
			ROOT_PRIV_KEY_FILE);
	}

	if(compareKeyData(&rootPubKey, &subjPubKey)) {
	 	printf("**WARNING: Identical root and subj keys!\n");
	}

	/*
	 * Cook up various cert fields.
	 * First, the RDNs for subject and issuer. 
	 */
	rootName = CB_BuildX509Name(rootRdn, NUM_ROOT_NAMES);
	subjName = CB_BuildX509Name(subjRdn, NUM_SUBJ_NAMES);
	if((rootName == NULL) || (subjName == NULL)) {
		printf("CB_BuildX509Name failure");
		errorCount++;
		goto abort;
	}
	
	/* not before/after in generalized time format */
	notBefore = CB_BuildX509Time(0);
	notAfter  = CB_BuildX509Time(10000);

	/* A KeyUsage extension for both certs */
	exts[0].extnId = CSSMOID_KeyUsage;
	exts[0].critical = CSSM_FALSE;
	exts[0].format = CSSM_X509_DATAFORMAT_PARSED;
	keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign |
			   CE_KU_KeyEncipherment | CE_KU_DataEncipherment;
	exts[0].value.parsedValue = &keyUsage;
	exts[0].BERvalue.Data = NULL;
	exts[0].BERvalue.Length = 0;

	/* BasicConstraints for root only */
	exts[1].extnId = CSSMOID_BasicConstraints;
	exts[1].critical = CSSM_TRUE;
	exts[1].format = CSSM_X509_DATAFORMAT_PARSED;
	bc.cA = CSSM_TRUE;
	bc.pathLenConstraintPresent = CSSM_TRUE;
	bc.pathLenConstraint = 2;
	exts[1].value.parsedValue = &bc;
	exts[1].BERvalue.Data = NULL;
	exts[1].BERvalue.Length = 0;
	
	/* cook up root cert */
	printf("Creating root cert...\n");
	rawCert = CB_MakeCertTemplate(clHand,
		0x12345678,			// serial number
		rootName,
		rootName,
		notBefore,
		notAfter,
		&rootPubKey,
		sigAlg,
		NULL,				// subjUniqueId
		NULL,				// issuerUniqueId
		exts,				// extensions
		2);					// numExtensions

	if(rawCert == NULL) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(ROOT_TBS_FILE_NAME, rawCert->Data, rawCert->Length);
		printf("...wrote %lu bytes to %s\n", rawCert->Length, ROOT_TBS_FILE_NAME);
	}
	
	/* Self-sign; this is a root cert */
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
			sigAlg,
			NULL,			// AccessCred
			&rootPrivKey,
			&signContext);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext", crtn);
		errorCount++;
		goto abort;
	}
	signedRootCert.Data = NULL;
	signedRootCert.Length = 0;
	crtn = CSSM_CL_CertSign(clHand,
		signContext,
		rawCert,			// CertToBeSigned
		NULL,				// SignScope
		0,					// ScopeSize,
		&signedRootCert);
	if(crtn) {
		printError("CSSM_CL_CertSign", crtn);
		errorCount++;
		goto abort;
	}
	crtn = CSSM_DeleteContext(signContext);
	if(crtn) {
		printError("CSSM_DeleteContext", crtn);
		errorCount++;
		goto abort;
	}
	appFreeCssmData(rawCert, CSSM_TRUE);
	if(writeBlobs) {
		writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length);
		printf("...wrote %lu bytes to %s\n", signedRootCert.Length, 
			ROOT_CERT_FILE_NAME);
	}

	/* now a subject cert signed by the root cert */
	printf("Creating subject cert...\n");
	rawCert = CB_MakeCertTemplate(clHand,
		0x8765,				// serial number
		rootName,
		subjName,
		notBefore,
		notAfter,
		&subjPubKey,
		sigAlg,
		NULL,				// subjUniqueId
		NULL,				// issuerUniqueId
		exts,				// extensions
		1);					// numExtensions
	if(rawCert == NULL) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(SUBJ_TBS_FILE_NAME, rawCert->Data, rawCert->Length);
		printf("...wrote %lu bytes to %s\n", rawCert->Length, SUBJ_TBS_FILE_NAME);
	}

	/* sign by root */
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
			sigAlg,
			NULL,			// AccessCred
			&rootPrivKey,
			&signContext);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext", crtn);
		errorCount++;
		goto abort;
	}
	signedSubjCert.Data = NULL;
	signedSubjCert.Length = 0;
	crtn = CSSM_CL_CertSign(clHand,
		signContext,
		rawCert,			// CertToBeSigned
		NULL,				// SignScope
		0,					// ScopeSize,
		&signedSubjCert);
	if(crtn) {
		printError("CSSM_CL_CertSign", crtn);
		errorCount++;
		goto abort;
	}
	crtn = CSSM_DeleteContext(signContext);
	if(crtn) {
		printError("CSSM_DeleteContext", crtn);
		errorCount++;
		goto abort;
	}
	appFreeCssmData(rawCert, CSSM_TRUE);
	if(writeBlobs) {
		writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length);
		printf("...wrote %lu bytes to %s\n", signedSubjCert.Length, 
			SUBJ_CERT_FILE_NAME);
	}

	/* Free the stuff we allocd to get here */
	CB_FreeX509Name(rootName);
	CB_FreeX509Name(subjName);
	CB_FreeX509Time(notBefore);
	CB_FreeX509Time(notAfter);

	/*
	 * Extract public keys from the two certs, verify.
	 */
	crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey);
	if(crtn) {
		printError("CSSM_CL_CertGetKeyInfo", crtn);
	}
	else {
		/* compare key data - header is different.
		 * Known header differences:
		 *  -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for
		 *     this field
		 * --  Format. rootPubKey      : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE)
		 *             extractRootKey  : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1)
		 * --  KeyAttr. rootPubKey     : 0x20 (CSSM_KEYATTR_EXTRACTABLE)
		 *              extractRootKey : 0x0
		 */
		if(!compareKeyData(extractSubjKey, &subjPubKey)) {
			printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n");
		}
		if(extractSubjKey->KeyHeader.LogicalKeySizeInBits !=
				subjPubKey.KeyHeader.LogicalKeySizeInBits) {
			printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n",
				(unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits,
				(unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits);
		}
	}
	crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey);
	if(crtn) {
		printError("CSSM_CL_CertGetKeyInfo", crtn);
	}
	else {
		if(!compareKeyData(extractRootKey, &rootPubKey)) {
			printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n");
		}
	}

	/*
	 * Verify:
	 */
	printf("Verifying certificates...\n");
	
	/*
	 *  Verify root cert by root pub key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedRootCert,
			NULL,
			&rootPubKey,
			sigAlg,
			CSSM_OK,
			"Verify(root by root key)")) {
		errorCount++;
		/* continue */
	}
	
	/*
	 *  Verify root cert by root cert, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedRootCert,
			&signedRootCert,
			NULL,
			CSSM_ALGID_NONE,			// sigAlg not used here
			CSSM_OK,
			"Verify(root by root cert)")) {
		errorCount++;
		/* continue */
	}


	/*
	 *  Verify subject cert by root pub key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			&rootPubKey,
			sigAlg,
			CSSM_OK,
			"Verify(subj by root key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by root cert, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			&signedRootCert,
			NULL,
			CSSM_ALGID_NONE,			// sigAlg not used here
			CSSM_OK,
			"Verify(subj by root cert)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by root cert AND key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			&signedRootCert,
			&rootPubKey,
			sigAlg,
			CSSM_OK,
			"Verify(subj by root cert and key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by extracted root pub key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			extractRootKey,
			sigAlg,
			CSSM_OK,
			"Verify(subj by extracted root key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by subject pub key, should fail.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			&subjPubKey,
			sigAlg,
			CSSMERR_CL_VERIFICATION_FAILURE,
			"Verify(subj by subj key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by subject cert, should fail.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			&signedSubjCert,
			NULL,
			CSSM_ALGID_NONE,			// sigAlg not used here
			CSSMERR_CL_VERIFICATION_FAILURE,
			"Verify(subj by subj cert)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify erroneous subject cert by root pub key, should fail.
	 */
	badByte = genRand(1, signedSubjCert.Length - 1);
	signedSubjCert.Data[badByte] ^= 0x55;
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			&rootPubKey,
			sigAlg,
			CSSMERR_CL_VERIFICATION_FAILURE,
			"Verify(bad subj by root key)")) {
		errorCount++;
		/* continue */
	}


	/* free/delete certs and keys */
	appFreeCssmData(&signedSubjCert, CSSM_FALSE);
	appFreeCssmData(&signedRootCert, CSSM_FALSE);

	cspFreeKey(cspHand, &rootPubKey);
	cspFreeKey(cspHand, &subjPubKey);

	/* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with
	 * a bogus GUID. This may be a problem with the Apple CSP...
	 *
	cspFreeKey(cspHand, extractRootKey);
	cspFreeKey(cspHand, extractSubjKey);
	 *
	 * do it this way instead...*/
	CSSM_FREE(extractRootKey->KeyData.Data);
	CSSM_FREE(extractSubjKey->KeyData.Data);

	/* need to do this regardless...*/
	CSSM_FREE(extractRootKey);
	CSSM_FREE(extractSubjKey);

abort:
	if(cspHand != 0) {
		CSSM_ModuleDetach(cspHand);
	}

	if(errorCount) {
		printf("Signer/Subject test failed with %d errors\n", errorCount);
	}
	else {
		printf("Signer/Subject test succeeded\n");
	}
	return 0;
}
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;
}
Example #10
0
CryptoX_Result
CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData,
                          CryptoX_PublicKey* aPublicKey,
                          const unsigned char* aSignature,
                          unsigned int aSignatureLen)
{
  if (!aInputData || !*aInputData || !aPublicKey || !*aPublicKey ||
      !aSignature || aSignatureLen == 0) {
    return CryptoX_Error;
  }

  if (!OnLionOrLater()) {
    if (!sCspHandle) {
      return CryptoX_Error;
    }

    CSSM_KEY* publicKey;
    OSStatus status = SecKeyGetCSSMKey((SecKeyRef)*aPublicKey,
                                       (const CSSM_KEY**)&publicKey);
    if (status) {
      return CryptoX_Error;
    }

    CSSM_CC_HANDLE ccHandle;
    if (CSSM_CSP_CreateSignatureContext(sCspHandle,
                                        CSSM_ALGID_SHA1WithRSA,
                                        NULL,
                                        publicKey,
                                        &ccHandle) != CSSM_OK) {
      return CryptoX_Error;
    }

    CryptoX_Result result = CryptoX_Error;
    CSSM_DATA signatureData;
    signatureData.Data = (uint8*)aSignature;
    signatureData.Length = aSignatureLen;
    CSSM_DATA inputData;
    inputData.Data =
      CFDataGetMutableBytePtr((CFMutableDataRef)
                                (((CSSM_DATA_PTR)*aInputData)->Data));
    inputData.Length = ((CSSM_DATA_PTR)*aInputData)->Length;
    if (CSSM_VerifyData(ccHandle,
                        &inputData,
                        1,
                        CSSM_ALGID_NONE,
                        &signatureData) == CSSM_OK) {
      result = CryptoX_Success;
    }
    return result;
  }

  CFDataRef signatureData = CFDataCreate(kCFAllocatorDefault,
                                         aSignature, aSignatureLen);
  if (!signatureData) {
    return CryptoX_Error;
  }

  CFErrorRef error;
  SecTransformRef verifier =
    SecVerifyTransformCreatePtr((SecKeyRef)*aPublicKey,
                                signatureData,
                                &error);
  if (!verifier || error) {
    CFRelease(signatureData);
    return CryptoX_Error;
  }

  SecTransformSetAttributePtr(verifier,
                              kSecTransformInputAttributeName,
                              (CFDataRef)*aInputData,
                              &error);
  if (error) {
    CFRelease(signatureData);
    CFRelease(verifier);
    return CryptoX_Error;
  }

  CryptoX_Result result = CryptoX_Error;
  CFTypeRef rv = SecTransformExecutePtr(verifier, &error);
  if (error) {
    CFRelease(signatureData);
    CFRelease(verifier);
    return CryptoX_Error;
  }

  if (CFGetTypeID(rv) == CFBooleanGetTypeID() &&
      CFBooleanGetValue((CFBooleanRef)rv) == true) {
    result = CryptoX_Success;
  }

  CFRelease(signatureData);
  CFRelease(verifier);

  return result;
}
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;
}
/* 
 * Core test routine.
 * -- build a cert with issuer and subject as per specified name components
 * -- extract inferred label 
 * -- compare inferred label to expected value 
 * -- if labelIsCommonName true, verify that SecCertificateCopyCommonName() yields
 *    the same string as inferred label
 */
static int doTest(
	const char			*testName,
	bool				quiet,
	CSSM_CSP_HANDLE		cspHand,
	CSSM_CL_HANDLE		clHand,
	CSSM_KEY_PTR		privKey,
	CSSM_KEY_PTR		pubKey,
	
	/* input names - one or two */
	const void			*name1Val,
	CSSM_SIZE			name1Len,
	CSSM_BER_TAG		berTag1,
	const CSSM_OID		*name1Oid,
	const void			*name2Val,		// optional 
	CSSM_SIZE			name2Len,
	CSSM_BER_TAG		berTag2,
	const CSSM_OID		*name2Oid,
	
	/* expected label */
	CFStringRef			expectedLabel,
	bool				labelIsCommonName)
{
	if(!quiet) {
		printf("...%s\n", testName);
	}
	
	/* build the subject/issuer name */
	NameOid nameArray[2] = { {name1Val, name1Len, name1Oid, berTag1 },
							 {name2Val, name2Len, name2Oid, berTag2 } };
	unsigned numNames = name2Val ? 2 : 1;
	
	CSSM_X509_NAME *name = buildX509Name(nameArray, numNames);
	if(name == NULL) {
		printf("***buildX509Name screwup\n");
		return -1;
	}
	
	/* build the cert template */
	CSSM_DATA_PTR certTemp = CB_MakeCertTemplate(
		clHand, 0x123456,
		name, name,
		notBefore, notAfter,
		pubKey, SIG_ALG,
		NULL, NULL,		// subject/issuer UniqueID
		NULL, 0);		// extensions 
	if(certTemp == NULL) {
		printf("***CB_MakeCertTemplate screwup\n");
		return -1;
	}
	
	/* sign the cert */
	CSSM_DATA signedCert = {0, NULL};
	CSSM_CC_HANDLE sigHand;
	CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
			SIG_ALG,
			NULL,			// no passphrase for now
			privKey,
			&sigHand);
	if(crtn) {
		/* should never happen */
		cssmPerror("CSSM_CSP_CreateSignatureContext", crtn);
		return 1;
	}
	crtn = CSSM_CL_CertSign(clHand,
		sigHand,
		certTemp,			// CertToBeSigned
		NULL,				// SignScope per spec
		0,					// ScopeSize per spec
		&signedCert);
	if(crtn) {
		cssmPerror("CSSM_CL_CertSign", crtn);
		return 1;
	}
	CSSM_DeleteContext(sigHand);
	CSSM_FREE(certTemp->Data);
	CSSM_FREE(certTemp);

	/* 
	 * OK, we have a signed cert. 
	 * Turn it into a SecCertificateRef and get the inferred label.
	 */
	OSStatus ortn;
	SecCertificateRef certRef;
	ortn = SecCertificateCreateFromData(&signedCert, 
		CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
		&certRef);
	if(ortn) {
		cssmPerror("SecCertificateCreateFromData", ortn);
		return -1;
	}
	CFStringRef inferredLabel;
	ortn = SecCertificateInferLabel(certRef, &inferredLabel);
	if(ortn) {
		cssmPerror("SecCertificateCreateFromData", ortn);
		return -1;
	}
	CFComparisonResult res = CFStringCompare(inferredLabel, expectedLabel, 0);
	if(res != kCFCompareEqualTo) {
		fprintf(stderr, "*** label miscompare in test '%s' ***\n", testName);
		fprintf(stderr, "expected label : ");
		CFShow(expectedLabel);
		fprintf(stderr, "inferred label : ");
		CFShow(inferredLabel);
		if(writeFile(CERT_FILE_OUT, signedCert.Data, signedCert.Length)) {
			fprintf(stderr, "***Error writing cert to %s\n", CERT_FILE_OUT);
		}
		else {
			fprintf(stderr, "...write %lu bytes to %s\n", (unsigned long)signedCert.Length, 
			CERT_FILE_OUT);
		}
		return -1;
	}
	
	if(labelIsCommonName) {
		CFStringRef commonName = NULL;
		ortn = SecCertificateCopyCommonName(certRef, &commonName);
		if(ortn) {
			cssmPerror("SecCertificateCopyCommonName", ortn);
			return -1;
		}
		res = CFStringCompare(inferredLabel, commonName, 0);
		if(res != kCFCompareEqualTo) {
			printf("*** CommonName miscompare in test '%s' ***\n", testName);
			printf("Common Name    : '");
			CFShow(commonName);
			printf("'\n");
			printf("inferred label : '");
			CFShow(inferredLabel);
			printf("'\n");
			if(writeFile(CERT_FILE_OUT, signedCert.Data, signedCert.Length)) {
				printf("***Error writing cert to %s\n", CERT_FILE_OUT);
			}
			else {
				printf("...write %lu bytes to %s\n", (unsigned long)signedCert.Length, 
				CERT_FILE_OUT);
			}
			return -1;
		}
		CFRelease(commonName);
	}
	CFRelease(certRef);
	CSSM_FREE(signedCert.Data);
	CB_FreeX509Name(name);
	CFRelease(inferredLabel);
	return 0;
}
/*
 * Submit cred (cert) request. Currently the only form of request we
 * handle is the basis "sign this cert with key right now", with policy OI
 * CSSMOID_APPLE_TP_LOCAL_CERT_GEN.
 */
void AppleTPSession::SubmitCredRequest(
	const CSSM_TP_AUTHORITY_ID *PreferredAuthority,
	CSSM_TP_AUTHORITY_REQUEST_TYPE RequestType,
	const CSSM_TP_REQUEST_SET &RequestInput,
	const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext,
	sint32 &EstimatedTime,
	CssmData &ReferenceIdentifier)
{
	/* free all of these on return if non-NULL */
	CSSM_DATA_PTR certTemplate = NULL;
	CSSM_X509_TIME_PTR notBeforeX509 = NULL;
	CSSM_X509_TIME_PTR notAfterX509 = NULL;
	CSSM_X509_NAME_PTR subjectX509 = NULL;
	CSSM_X509_NAME_PTR issuerX509 = NULL;
	CSSM_X509_EXTENSION_PTR extens509 = NULL;
	CSSM_CC_HANDLE sigContext = 0;
	
	/* this gets saved on success */
	CSSM_DATA_PTR signedCert = NULL;
	
	/* validate rather limited set of input args */
	if(PreferredAuthority != NULL) {
		CssmError::throwMe(CSSMERR_TP_INVALID_AUTHORITY);
	}
	if(RequestType != CSSM_TP_AUTHORITY_REQUEST_CERTISSUE) {
		CssmError::throwMe(CSSMERR_TP_UNSUPPORTED_SERVICE);
	}
	if(CallerAuthContext == NULL) {
		CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
	}
	if((RequestInput.NumberOfRequests != 1) ||
	   (RequestInput.Requests == NULL)) {
		CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
	}
	
	/* Apple-specific args */
	const CSSM_TP_POLICYINFO *tpPolicy = &CallerAuthContext->Policy;
	if((tpPolicy->NumberOfPolicyIds != 1) ||
	   (tpPolicy->PolicyIds == NULL)) {
		CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
	}
	if(tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid,
		&CSSMOID_APPLE_TP_CSR_GEN)) {
		/* break out to CSR-specific code */
		SubmitCsrRequest(RequestInput, CallerAuthContext, EstimatedTime, ReferenceIdentifier);
		return;
	}
	else if(!tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid,
		&CSSMOID_APPLE_TP_LOCAL_CERT_GEN)) {
		CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
	}

	CSSM_APPLE_TP_CERT_REQUEST *certReq =
		(CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests;
	if((certReq->cspHand == 0) || 
	   (certReq->clHand == 0) ||
	   (certReq->certPublicKey == NULL) ||
	   (certReq->issuerPrivateKey == NULL)) {
		CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
	}
	if((certReq->numExtensions != 0) & (certReq->extensions == NULL)) {
		CssmError::throwMe(CSSMERR_TP_INVALID_POINTER);
	}
	
	CSSM_RETURN ourRtn = CSSM_OK;
	
	try {
		/* convert caller's friendly names and times to CDSA style */
		subjectX509 = buildX509Name(certReq->subjectNames, certReq->numSubjectNames);
		if(certReq->issuerNames != NULL) {
			issuerX509 = buildX509Name(certReq->issuerNames, certReq->numIssuerNames);
		}
		else if(certReq->issuerNameX509) {
			/* caller obtained this from an existing signer's cert */
			issuerX509 = certReq->issuerNameX509;
		}
		else {
			/* self-signed */
			issuerX509 = subjectX509;
		}
		notBeforeX509 = buildX509Time(certReq->notBefore);
		notAfterX509 = buildX509Time(certReq->notAfter);
		
		if(certReq->numExtensions != 0) { 
			/* convert extensions array from CE_DataAndType to CSSM_X509_EXTENSION */
			extens509 = (CSSM_X509_EXTENSION *)malloc(sizeof(CSSM_X509_EXTENSION) * 
					certReq->numExtensions);
			memset(extens509, 0, sizeof(CSSM_X509_EXTENSION) * 
					certReq->numExtensions);
			for(unsigned dex=0; dex<certReq->numExtensions; dex++) {
				CSSM_X509_EXTENSION *extn = &extens509[dex];
				CE_DataAndType *cdt = &certReq->extensions[dex];
				void *parsedValue;
				CSSM_OID extnId;
				
				switch(cdt->type) {
					case DT_AuthorityKeyID:	
						parsedValue = &cdt->extension.authorityKeyID;
						extnId = CSSMOID_AuthorityKeyIdentifier;
						break;
					case DT_SubjectKeyID:		
						parsedValue = &cdt->extension.subjectKeyID;
						extnId = CSSMOID_SubjectKeyIdentifier;
						break;
					case DT_KeyUsage:				 
						parsedValue = &cdt->extension.keyUsage;
						extnId = CSSMOID_KeyUsage;
						break;
					case DT_SubjectAltName:			
						parsedValue = &cdt->extension.subjectAltName;
						extnId = CSSMOID_SubjectAltName;
						break;
					case DT_IssuerAltName:			
						parsedValue = &cdt->extension.issuerAltName;
						extnId = CSSMOID_IssuerAltName;
						break;
					case DT_ExtendedKeyUsage:		
						parsedValue = &cdt->extension.extendedKeyUsage;
						extnId = CSSMOID_ExtendedKeyUsage;
						break;
					case DT_BasicConstraints:		
						parsedValue = &cdt->extension.basicConstraints;
						extnId = CSSMOID_BasicConstraints;
						break;
					case DT_CertPolicies:			
						parsedValue = &cdt->extension.certPolicies;
						extnId = CSSMOID_CertificatePolicies;
						break;
					case DT_NetscapeCertType:		
						parsedValue = &cdt->extension.netscapeCertType;
						extnId = CSSMOID_NetscapeCertType;
						break;
					case DT_CrlDistributionPoints:		
						parsedValue = &cdt->extension.crlDistPoints;
						extnId = CSSMOID_CrlDistributionPoints;
						break;
					case DT_AuthorityInfoAccess:		
						parsedValue = &cdt->extension.authorityInfoAccess;
						extnId = CSSMOID_AuthorityInfoAccess;
						break;
					case DT_Other:		
					default:
						tpCredDebug("SubmitCredRequest: DT_Other not supported");
						CssmError::throwMe(CSSMERR_TP_UNKNOWN_TAG);
						// NOT REACHED
				}
				extn->extnId   			= extnId;
				extn->critical 			= cdt->critical;
				extn->format   			= CSSM_X509_DATAFORMAT_PARSED;
				extn->value.parsedValue 	= parsedValue;
				extn->BERvalue.Data = NULL;
				extn->BERvalue.Length = 0;
			}	/* for each extension */
		} 		/* converting extensions */
			
		/* cook up the unsigned template */
		makeCertTemplate(certReq->clHand,
			certReq->cspHand,
			certReq->serialNumber,
			issuerX509,
			subjectX509,
			notBeforeX509,
			notAfterX509,
			certReq->certPublicKey,
			certReq->signatureOid,
			NULL,				// subjectUniqueID, not used here (yet)
			NULL,				// issuerUniqueId
			extens509,
			certReq->numExtensions,
			certTemplate);
			
		/* create signature context */		
		ourRtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand,
				certReq->signatureAlg,
				(CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL),
				certReq->issuerPrivateKey,
				&sigContext);
		if(ourRtn) {
			tpCredDebug("CSSM_CSP_CreateSignatureContext returned %ld", (long)ourRtn);
			CssmError::throwMe(ourRtn);
		}
		
		signedCert = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
		signedCert->Data = NULL;
		signedCert->Length = 0;
		ourRtn = CSSM_CL_CertSign(certReq->clHand,
			sigContext,
			certTemplate,		// CertToBeSigned
			NULL,				// SignScope
			0,					// ScopeSize,
			signedCert);
		if(ourRtn) {
			tpCredDebug("CSSM_CL_CertSign returned %ld", (long)ourRtn);
			CssmError::throwMe(ourRtn);
		}
		
		/* save it for retrieval by RetrieveCredResult */
		addCertToMap(signedCert, &ReferenceIdentifier);
		EstimatedTime = 0;
	}
	catch (const CssmError &cerr) {
		tpCredDebug("SubmitCredRequest: CSSM error %ld", (long)cerr.error);
		ourRtn = cerr.error;
	}
	catch(...) {
		tpCredDebug("SubmitCredRequest: unknown exception");
		ourRtn = CSSMERR_TP_INTERNAL_ERROR;	// ??
	}
	
	/* free reources */
	tpFreeCssmData(*this, certTemplate, CSSM_TRUE);
	freeX509Name(subjectX509);
	if(certReq->issuerNames) {
		freeX509Name(issuerX509);
	}
	/* else same as subject */
	freeX509Time(notBeforeX509);
	freeX509Time(notAfterX509);
	if(extens509) {
		free(extens509);
	}
	if(sigContext != 0) {
		CSSM_DeleteContext(sigContext);
	}
	if(ourRtn) {
		CssmError::throwMe(ourRtn);
	}
}
/*
 * SubmitCredRequest, CSR form.
 */
void AppleTPSession::SubmitCsrRequest(
	const CSSM_TP_REQUEST_SET &RequestInput,
	const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext,
	sint32 &EstimatedTime,						// RETURNED
	CssmData &ReferenceIdentifier)				// RETURNED
{
	CSSM_DATA_PTR	csrPtr = NULL;
	CSSM_CC_HANDLE 	sigHand = 0;
	CSSM_APPLE_CL_CSR_REQUEST csrReq;
	
	memset(&csrReq, 0, sizeof(csrReq));

	/* for now we're using the same struct for input as the the normal
	 * X509 cert request. */
	CSSM_APPLE_TP_CERT_REQUEST *certReq =
		(CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests;
	if((certReq->cspHand == 0) || 
	   (certReq->clHand == 0) ||
	   (certReq->certPublicKey == NULL) ||
	   (certReq->issuerPrivateKey == NULL) ||
	   (certReq->signatureOid.Data == NULL)) {
		CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
	}
	
	/* convert ref public key to raw per CL requirements */
	const CSSM_KEY *subjectPubKey = certReq->certPublicKey;
	const CSSM_KEY *actPubKey = NULL;
	CSSM_BOOL freeRawKey = CSSM_FALSE;
	CSSM_KEY rawPubKey;
	
	switch(subjectPubKey->KeyHeader.BlobType) {
		case CSSM_KEYBLOB_RAW:
			actPubKey = subjectPubKey;
			break;
		case CSSM_KEYBLOB_REFERENCE:
			refKeyToRaw(certReq->cspHand, subjectPubKey, &rawPubKey);
			actPubKey = &rawPubKey;
			freeRawKey = CSSM_TRUE;
			break;
		default:
			tpCredDebug("SubmitCsrRequest: bad key blob type (%u)",
				(unsigned)subjectPubKey->KeyHeader.BlobType);
			CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
	}

	/* cook up a CL-passthrough-specific request */
	csrReq.subjectNameX509 	 = buildX509Name(certReq->subjectNames, 
											certReq->numSubjectNames);
	csrReq.signatureAlg 	 = certReq->signatureAlg;
	csrReq.signatureOid 	 = certReq->signatureOid;
	csrReq.cspHand 			 = certReq->cspHand;
	csrReq.subjectPublicKey  = actPubKey;
	csrReq.subjectPrivateKey = certReq->issuerPrivateKey;
	csrReq.challengeString   = certReq->challengeString;
	
	/* A crypto handle to pass to the CL */
	CSSM_RETURN crtn;
	crtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand,
			certReq->signatureAlg,
			(CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL),
			certReq->issuerPrivateKey,
			&sigHand);
	if(crtn) {
		tpCredDebug("CSSM_CSP_CreateSignatureContext returned %ld", (long)crtn);
		goto abort;
	}
	
	/* down to the CL to do the actual work */
	crtn = CSSM_CL_PassThrough(certReq->clHand,
		sigHand,
		CSSM_APPLEX509CL_OBTAIN_CSR,
		&csrReq,
		(void **)&csrPtr);
	if(crtn) {
		tpCredDebug("CSSM_CL_PassThrough returned %ld", (long)crtn);
		goto abort;
	}

	/* save it for retrieval by RetrieveCredResult */
	addCertToMap(csrPtr, &ReferenceIdentifier);
	EstimatedTime = 0;

abort:
	/* free local resources */
	if(csrReq.subjectNameX509) {
		freeX509Name(csrReq.subjectNameX509);
	}
	if(sigHand) {
		CSSM_DeleteContext(sigHand);
	}
	if(freeRawKey) {
		tpFreeCssmData(*this, &rawPubKey.KeyData, CSSM_FALSE);
	}
	if(crtn) {
		CssmError::throwMe(crtn);
	}
}