OSStatus sslReadAnchor(
	const char 			*anchorFile,
	SecCertificateRef 	*certRef)
{
	OSStatus ortn;
	SecCertificateRef secCert;
	unsigned char *certData;
	unsigned certLen;
	CSSM_DATA cert;
	
	if(readFile(anchorFile, &certData, &certLen)) {
		return -1;
	}
	cert.Data = certData;
	cert.Length = certLen;
	ortn = SecCertificateCreateFromData(&cert,
			CSSM_CERT_X_509v3,
			CSSM_CERT_ENCODING_DER,
			&secCert);
	free(certData);
	if(ortn) {
		printf("***SecCertificateCreateFromData returned %d\n", (int)ortn);
		return ortn;
	}
	*certRef = secCert;
	return errSecSuccess;
}
Exemplo n.º 2
0
// Find a certificate in the database by a DER encoded certificate
// "derCert" is the DER encoded certificate
SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const SECItem *derCert)
{
    // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess.
    SecCertificateRef cert = NULL;
    OSStatus rv;

    rv = SecCertificateCreateFromData(derCert, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
    if (rv && cert)
    {
	PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
	CFRelease(cert);
	cert = NULL;
    }

    return cert;
}
Exemplo n.º 3
0
// Generate a certificate key from the issuer and serialnumber, then look it up in the database.
// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, 
    CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN)
{
    SecCertificateRef certificate;
    int numRawCerts = SecCmsArrayCount((void **)rawCerts);
    int dex;
    OSStatus ortn;
    
    /* 
     * First search the rawCerts array.
     */
    for(dex=0; dex<numRawCerts; dex++) {
	ortn = SecCertificateCreateFromData(rawCerts[dex], 
	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
	    &certificate);
	if(ortn) {
	    continue;
	}
	SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, certificate);
	if(isn == NULL) {
	    CFRelease(certificate);
	    continue;
	}
	if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
	    CFRelease(certificate);
	    continue;
	}
	if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
	    CFRelease(certificate);
	    continue;
	}
	/* got it */
	dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate);
	return certificate;
    }
    
    /* now search keychain(s) */
    OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer,
	&issuerAndSN->serialNumber, &certificate);
    if (status)
    {
	PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
	certificate = NULL;
    }

    return certificate;
}
Exemplo n.º 4
0
/*
 * Cook up a SecCertificateRef from a krb5_data.
 */
static OSStatus pkiKrb5DataToSecCert(
    const krb5_data *rawCert,
    SecCertificateRef *secCert)     /* RETURNED */
{
    CSSM_DATA certData;
    OSStatus ortn;
    
    assert((rawCert != NULL) && (secCert != NULL));
    
    certData.Data = (uint8 *)rawCert->data;
    certData.Length = rawCert->length;
    ortn = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, 
	CSSM_CERT_ENCODING_DER, secCert);
    if(ortn) {
	pkiCssmErr("SecCertificateCreateFromData", ortn);
    }
    return ortn;
}
Exemplo n.º 5
0
SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray, 
    CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID)
{
    SecCertificateRef certificate;
    int numRawCerts = SecCmsArrayCount((void **)rawCerts);
    int dex;
    OSStatus ortn;
    SECItem skid;
    
    /* 
     * First search the rawCerts array.
     */
    for(dex=0; dex<numRawCerts; dex++) {
	int match;
	ortn = SecCertificateCreateFromData(rawCerts[dex], 
	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
	    &certificate);
	if(ortn) {
	    continue;
	}
	if(CERT_FindSubjectKeyIDExtension(certificate, &skid)) {
	    CFRelease(certificate);
	    /* not present */
	    continue;
	}
	match = compareCssmData(subjKeyID, &skid);
	SECITEM_FreeItem(&skid, PR_FALSE);
	if(match) {
	    /* got it */
	    return certificate;
	}
	CFRelease(certificate);
    }

    /* now search keychain(s) */
    OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate);
    if (status)
    {
	PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
	certificate = NULL;
    }

    return certificate;
}
/*
 * Add a certificate to an open Keychain.
 */
CSSM_RETURN cuAddCertToKC(
	SecKeychainRef		keychain,
	const CSSM_DATA		*cert,
	CSSM_CERT_TYPE		certType,
	CSSM_CERT_ENCODING	certEncoding,
	const char			*printName,		// C string
	const CSSM_DATA		*keyLabel)		// ??
{
	SecCertificateRef certificate;
	
	OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
	if (!rslt)
	{
		rslt = SecCertificateAddToKeychain(certificate, keychain);
		CFRelease(certificate);
	}

	return rslt;
}
/*
 * Obtain an array of all of the certificates in a message. Elements of the
 * returned array are SecCertificateRefs. The caller must CFRelease the returned
 * array.
 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
 */
OSStatus CMSDecoderCopyAllCerts(
                                CMSDecoderRef		cmsDecoder,
                                CFArrayRef			*certs)					/* RETURNED */
{
	if((cmsDecoder == NULL) || (certs == NULL)) {
		return errSecParam;
	}
	if(cmsDecoder->decState != DS_Final) {
		return errSecParam;
	}
	if(cmsDecoder->signedData == NULL) {
		/* message wasn't signed */
		*certs = NULL;
		return errSecSuccess;
	}
	
	/* NULL_terminated array of CSSM_DATA ptrs */
	CSSM_DATA_PTR *cssmCerts = SecCmsSignedDataGetCertificateList(cmsDecoder->signedData);
	if((cssmCerts == NULL) || (*cssmCerts == NULL)) {
		*certs = NULL;
		return errSecSuccess;
	}
	
	CFMutableArrayRef allCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	CSSM_DATA_PTR *cssmCert;
	for(cssmCert=cssmCerts; *cssmCert!=NULL; cssmCert++) {
		OSStatus ortn;
		SecCertificateRef cfCert;
		ortn = SecCertificateCreateFromData(*cssmCert,
                                            CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
                                            &cfCert);
		if(ortn) {
			CFRelease(allCerts);
			return ortn;
		}
		CFArrayAppendValue(allCerts, cfCert);
		/* the array holds the only needed refcount */
		CFRelease(cfCert);
	}
	*certs = allCerts;
	return errSecSuccess;
}
Exemplo n.º 8
0
// import a collection of certs into the temporary or permanent cert database
SECStatus CERT_ImportCerts(SecKeychainRef keychain, SECCertUsage usage, unsigned int ncerts,
    SECItem **derCerts, SecCertificateRef **retCerts, Boolean keepCerts, Boolean caOnly, char *nickname)
{
    OSStatus rv = SECFailure;
    SecCertificateRef cert;
    unsigned int ci;

    // @@@ Do something with caOnly and nickname
    if (caOnly || nickname)
	abort();

    for (ci = 0; ci < ncerts; ++ci)
    {
	rv = SecCertificateCreateFromData(derCerts[ci], CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
	if (rv)
	    break;
	if (keepCerts)
	{
	    rv = SecCertificateAddToKeychain(cert, keychain);
	    if (rv)
	    {
		if (rv == errKCDuplicateItem)
		    rv = noErr;
		else
		{
		    CFRelease(cert);
		    break;
		}
	    }
	}

	if (retCerts)
	{
	    // @@@ not yet
	    abort();
	}
	else
	    CFRelease(cert);
    }

    return rv;
}
Exemplo n.º 9
0
int readCertFile(
    const char *fileName,
    SecCertificateRef *certRef)
{
    unsigned char *cp = NULL;
    unsigned len = 0;
    CSSM_DATA certData;
    OSStatus ortn;
    unsigned char *decoded = NULL;
    unsigned decodedLen = 0;

    if(readFile(fileName, &cp, &len)) {
        printf("***Error reading file %s\n", fileName);
        return -1;
    }
    if(isPem(cp, len)) {
        if(pemDecode(cp, len, &decoded, &decodedLen)) {
            fprintf(stderr, "Error decoding cert file %s\n", fileName);
            return -1;
        }
        certData.Length = decodedLen;
        certData.Data = decoded;
    }
    else {
        certData.Length = len;
        certData.Data = cp;
    }
    ortn = SecCertificateCreateFromData(&certData,
                                        CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, certRef);
    free(cp);
    if(decoded) {
        free(decoded);
    }
    if(ortn) {
        cssmPerror("SecCertificateCreateFromData", ortn);
        return -1;
    }
    return 0;
}
int main(int argc, char **argv)
{   
    OSStatus            err;
	int					arg;
	char				fullFileBase[100];
	SSLProtocol			negVersion;
	SSLCipherSuite		negCipher;
	Boolean				sessionWasResumed;
	unsigned char		sessionID[MAX_SESSION_ID_LENGTH];
	size_t				sessionIDLength;
	CFArrayRef			peerCerts = NULL;		
	char				*argp;
	otSocket			listenSock;
	CFArrayRef			serverCerts = nil;		// required
	CFArrayRef			encryptCerts = nil;		// optional
	SecKeychainRef		serverKc = nil;
	SecKeychainRef		encryptKc = nil;
	int 				loopNum;
	int					errCount = 0;
	SSLClientCertificateState certState;		// obtained from sslServe

	/* user-spec'd parameters */
	unsigned short		portNum = DEFAULT_PORT;
	bool			allowExpired = false;
	bool			allowAnyRoot = false;
	char				*fileBase = NULL;
	bool			displayCerts = false;
	char				cipherRestrict = '\0';
	SSLProtocol			attemptProt = kTLSProtocol1;
	bool			protXOnly = false;	// kSSLProtocol3Only, 
												//    kTLSProtocol1Only
	char				*acceptedProts = NULL;	// "23t" ==> SSLSetProtocolVersionEnabled
	bool			quiet = false;
	bool			resumableEnable = true;
	bool			pause = false;
	char				*keyChainName = NULL;
	char				*encryptKeyChainName = NULL;
	int					loops = 1;
	SSLAuthenticate		authenticate = kNeverAuthenticate;
	bool			nonBlocking = false;
	bool			allowExpiredRoot = false;
	bool			disableCertVerify = false;
	char				*anchorFile = NULL;
	bool			replaceAnchors = false;
	bool			vfyCertState = false;
	SSLClientCertificateState expectCertState = kSSLClientCertNone;
	char				*password = NULL;
	char				*dhParamsFile = NULL;
	unsigned char		*dhParams = NULL;
	unsigned			dhParamsLen = 0;
	bool			doIdSearch = false;
	bool			completeCertChain = false;
	uint32_t				sessionCacheTimeout = 0;
	bool			disableAnonCiphers = false;
	CFMutableArrayRef	acceptableDNList = NULL;

	for(arg=1; arg<argc; arg++) {
		argp = argv[arg];
		switch(argp[0]) {
			case 'P':
				portNum = atoi(&argp[2]);
				break;
			case 'k':
				keyChainName = &argp[2];
				break;
			case 'y':
				encryptKeyChainName = &argp[2];
				break;
			case 'e':
				allowExpired = true;
				break;
			case 'E':
				allowExpiredRoot = true;
				break;
			case 'x':
				disableCertVerify = true;
				break;
			case 'a':
				if(++arg == argc)  {
					/* requires another arg */
					usage(argv);
				}
				anchorFile = argv[arg];
				break;
			case 'A':
				if(++arg == argc)  {
					/* requires another arg */
					usage(argv);
				}
				anchorFile = argv[arg];
				replaceAnchors = true;
				break;
			case 'T':
				if(argp[1] != '=') {
					usage(argv);
				}
				vfyCertState = true;
				switch(argp[2]) {
					case 'n':
						expectCertState = kSSLClientCertNone;
						break;
					case 'r':
						expectCertState = kSSLClientCertRequested;
						break;
					case 's':
						expectCertState = kSSLClientCertSent;
						break;
					case 'j':
						expectCertState = kSSLClientCertRejected;
						break;
					default:
						usage(argv);
				}
				break;
			case 'r':
				allowAnyRoot = true;
				break;
			case 'd':
				break;
			case 'c':
				displayCerts = true;
				break;
			case 'f':
				fileBase = &argp[2];
				break;
			case 'C':
				cipherRestrict = argp[2];
				break;
			case '2':
				attemptProt = kSSLProtocol2;
				break;
			case '3':
				attemptProt = kSSLProtocol3;
				break;
			case 't':
				attemptProt = kTLSProtocol1;
				break;
			case 'o':
				protXOnly = true;
				break;
			case 'g':
				if(argp[1] != '=') {
					usage(argv);
				}
				acceptedProts = &argp[2];
				break;
			case 'R':
				resumableEnable = false;
				break;
			case 'b':
				nonBlocking = true;
				break;
			case 'u':
				if(argp[1] != '=') {
					usage(argv);
				}
				switch(argp[2]) {
					case 'a': authenticate = kAlwaysAuthenticate; break;
					case 'n': authenticate = kNeverAuthenticate; break;
					case 't': authenticate = kTryAuthenticate; break;
					default: usage(argv);
				}
				break;
			case 'D':
				if(++arg == argc)  {
					/* requires another arg */
					usage(argv);
				}
				dhParamsFile = argv[arg];
				break;
			case 'z':
				password = &argp[2];
				break;
			case 'H':
				doIdSearch = true;
				break;
			case 'M':
				completeCertChain = true;
				break;
			case 'i':
				sessionCacheTimeout = atoi(&argp[2]);
				break;
			case '4':
				disableAnonCiphers = true;
				break;
			case 'p':
				pause = true;
				break;
			case 'q':
				quiet = true;
				break;
#if 0
			case 'U':
				if(++arg == argc)  {
					/* requires another arg */
					usage(argv);
				}
				if(cspReadFile(argv[arg], &caCert, &caCertLen)) {
					printf("***Error reading file %s. Aborting.\n", argv[arg]);
					exit(1);
				}
				if(acceptableDNList == NULL) {
					acceptableDNList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
				}
				certData.Data = caCert;
				certData.Length = caCertLen;
				ortn = SecCertificateCreateFromData(&certData,
													CSSM_CERT_X_509v3,
													CSSM_CERT_ENCODING_DER,
													&secCert);
				if(ortn) {
					cssmPerror("SecCertificateCreateFromData", ortn);
					exit(1);
				}
				CFArrayAppendValue(acceptableDNList, secCert);
				CFRelease(secCert);
				break;
#endif
			case 'l':
				if(argp[1] == '\0') {
					/* no loop count --> loop forever */
					loops = 0;
					break;
				}
				else if(argp[1] != '=') {
					usage(argv);
				}
				loops = atoi(&argp[2]);
				break;
			default:
				usage(argv);
		}
	}

#if NO_SERVER
# if DEBUG
    securityd_init(NULL);
# endif
#endif

	/* get server cert and optional encryption cert as CFArrayRef */
	if(keyChainName) {
		serverCerts = getSslCerts(keyChainName, false, completeCertChain, 
			anchorFile, &serverKc);
		if(serverCerts == nil) {
			exit(1);
		}
	}
	else 
#if 0
    if(doIdSearch) {
		OSStatus ortn = sslIdentityPicker(NULL, anchorFile, true, NULL, &serverCerts);
		if(ortn) {
			printf("***IdentitySearch failure; aborting.\n");
			exit(1);
		}
	}
	if(password) {
		OSStatus ortn = SecKeychainUnlock(serverKc, strlen(password), password, true);
		if(ortn) {
			printf("SecKeychainUnlock returned %d\n", (int)ortn);
			/* oh well */
		}
	}
	if(encryptKeyChainName) {
		encryptCerts = getSslCerts(encryptKeyChainName, true, completeCertChain,
			anchorFile, &encryptKc);
		if(encryptCerts == nil) {
			exit(1);
		}
	}
#else
    (void) doIdSearch;
    (void) encryptKeyChainName;
#endif
	if(protXOnly) {
		switch(attemptProt) {
			case kTLSProtocol1:
				attemptProt = kTLSProtocol1Only;
				break;
			case kSSLProtocol3:
				attemptProt = kSSLProtocol3Only;
				break;
			default:
				break;
		}
	}
#if 0
	if(dhParamsFile) {
		int r = cspReadFile(dhParamsFile, &dhParams, &dhParamsLen);
		if(r) {
			printf("***Error reading diffie-hellman params from %s; aborting\n",
				dhParamsFile);
		}
	}
#else
    (void) dhParamsFile;
#endif

	/* one-time only server port setup */
	err = ListenForClients(portNum, nonBlocking, &listenSock);
	if(err) {
    	printf("ListenForClients returned %d; aborting\n", (int)err);
		exit(1);
	}

	for(loopNum=1; ; loopNum++) {
		err = sslServe(listenSock,
			portNum,
			attemptProt,
			acceptedProts,
			serverCerts,
			password,
			encryptCerts,
			allowExpired,
			allowAnyRoot,
			allowExpiredRoot,
			disableCertVerify,
			anchorFile,
			replaceAnchors,
			cipherRestrict,
			authenticate,
			dhParams,
			dhParamsLen,
			acceptableDNList,
			resumableEnable,
			sessionCacheTimeout,
			disableAnonCiphers,
			quiet,
			pause,
			&negVersion,
			&negCipher,
			&certState,
			&sessionWasResumed,
			sessionID,
			&sessionIDLength,
			&peerCerts,
			argv);
		if(err) {
			errCount++;
		}
		if(!quiet) {
			SSLProtocol tryProt = attemptProt;
			showSSLResult(tryProt,
				acceptedProts,
				err, 
				negVersion, 
				negCipher, 
				sessionWasResumed,
				sessionID,
				sessionIDLength,
				peerCerts,
				displayCerts,
				certState,
				fileBase ? fullFileBase : NULL);
		}
		errCount += verifyClientCertState(vfyCertState, expectCertState, 
			certState);
		freePeerCerts(peerCerts);
		if(loops && (loopNum == loops)) {
			break;
		}
	};
	
	endpointShutdown(listenSock);

	if(serverKc) {
		CFRelease(serverKc);
	}
	if(encryptKc) {
		CFRelease(encryptKc);
	}
    return errCount;

}
Exemplo n.º 11
0
/*
** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
** verify a certificate by checking validity times against a certain time,
** that we trust the issuer, and that the signature on the certificate is
** valid.
**	"cert" the certificate to verify
**	"checkSig" only check signatures if true
*/
SECStatus
CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
		const CSSM_DATA_PTR *otherCerts,    /* intermediates */
		CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
{
    CFMutableArrayRef certificates = NULL;
    SecTrustRef trust = NULL;
    OSStatus rv;
    int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
    int dex;
    
    /* 
     * Certs to evaluate: first the leaf - our cert - then all the rest we know
     * about. It's OK for otherCerts to contain a copy of the leaf. 
     */
    certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
    CFArrayAppendValue(certificates, cert);
    for(dex=0; dex<numOtherCerts; dex++) {
	SecCertificateRef intCert;
	
	rv = SecCertificateCreateFromData(otherCerts[dex], 
	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
	    &intCert);
	if(rv) {
	    goto loser;
	}
	CFArrayAppendValue(certificates, intCert);
	CFRelease(intCert);
    }
    rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
    CFRelease(certificates);
    certificates = NULL;
    if (rv)
	goto loser;

    rv = SecTrustSetKeychains(trust, keychainOrArray);
    if (rv)
	goto loser;

    CFDateRef verifyDate = CFDateCreate(NULL, stime);
    rv = SecTrustSetVerifyDate(trust, verifyDate);
    CFRelease(verifyDate);
    if (rv)
	goto loser;

    if (trustRef)
    {
	*trustRef = trust;
    }
    else
    {
	SecTrustResultType result;
	/* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
	rv = SecTrustEvaluate(trust, &result);
	if (rv)
	    goto loser;

	switch (result)
	{
	case kSecTrustResultProceed:
	case kSecTrustResultUnspecified:
	    /* TP Verification succeeded and there was either a UserTurst entry
	       telling us to procceed, or no user trust setting was specified. */
	    CFRelease(trust);
	    break;
	default:
	    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
	    rv = SECFailure;
	    goto loser;
	    break;
	}
    }

    return SECSuccess;
loser:
    if (trust)
	CFRelease(trust);
    if(certificates) 
	CFRelease(certificates);
    return rv;
}
Exemplo n.º 12
0
OSStatus createPair(CFStringRef hostName,CFStringRef userName,SecKeychainRef keychainRef, uint32 keySizeInBits, CFDataRef *cert)
{
	SecCertificateRef	certRef = NULL;
	CSSM_DL_DB_HANDLE 	dlDbHand = {0, 0};
	CSSM_CSP_HANDLE		cspHand = 0;
	CSSM_TP_HANDLE		tpHand = 0;
	CSSM_CL_HANDLE		clHand = 0;
	CSSM_KEY_PTR		pubKey = NULL;
	CSSM_KEY_PTR		privKey = NULL;
	CSSM_DATA			certData = {0, NULL};
	char 				*hostStr = NULL;
	char				*userStr = NULL;
	OSStatus			ortn;
	CSSM_OID 			algOid = SR_CERT_SIGNATURE_ALG_OID;

	hostStr = secCopyCString(hostName);
	userStr = secCopyCString(userName);
	if (!hostStr || !userStr)	// could not convert to UTF-8
	{
    	ortn = paramErr;
        goto xit;
    }

	// open keychain, connect to all the CDSA modules we'll need

	ortn = SecKeychainGetCSPHandle(keychainRef, &cspHand);
	if (ortn)
        goto xit;

	ortn = SecKeychainGetDLDBHandle(keychainRef, &dlDbHand);
	if (ortn)
        goto xit;

	tpHand = srTpStartup();
	if (tpHand == 0)
	{
    	ortn = ioErr;
        goto xit;
    }

	clHand = srClStartup();
	if (clHand == 0)
	{
    	ortn = ioErr;
        goto xit;
    }

	// generate key pair, private key stored in keychain
	ortn = generateKeyPair(cspHand, dlDbHand, SR_KEY_ALGORITHM, keySizeInBits,
		"FileVault Master Password Key", &pubKey, &privKey);
	if (ortn)
        goto xit;

	// generate the cert
	ortn = createRootCert(tpHand,clHand,cspHand,pubKey,privKey,hostStr,userStr,
		SR_CERT_SIGNATURE_ALGORITHM,&algOid,&certData);
	if (ortn)
        goto xit;

	// store the cert in the same DL/DB as the key pair [see SecCertificateCreateFromData]
	ortn = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &certRef);
	if (ortn)
        goto xit;

	ortn = SecCertificateAddToKeychain(certRef, keychainRef);
	if (ortn)
        goto xit;

	// return the cert to caller
    *cert = CFDataCreate(NULL, certData.Data, certData.Length);

    // cleanup
xit:
    if (certRef)
        CFRelease(certRef);
    if (certData.Data)
        free(certData.Data);
	if (hostStr)
		free(hostStr);
	if (userStr)
		free(userStr);
	if (tpHand)
		CSSM_ModuleDetach(tpHand);
	if (clHand)
		CSSM_ModuleDetach(clHand);
	if (pubKey)
    {
		CSSM_FreeKey(cspHand,
			NULL,			// access cred
			pubKey,
			CSSM_FALSE);	// delete
		APP_FREE(pubKey);
	}
	if (privKey)
    {
		CSSM_FreeKey(cspHand,
			NULL,			// access cred
			privKey,
			CSSM_FALSE);	// delete
		APP_FREE(privKey);
	}

	return ortn;
}
int main(int argc, char **argv)
{
	if(argc < 2) {
		usage(argv);
	}
	
	bool print_cert = false;
	bool allCerts = false;
	const char *emailAddress = NULL;
	bool addToKC = false;
	
	extern int optind;
	optind = 1;

	if(argv[1][0] != '-') {
		/* normal case, email address specified */
		emailAddress = argv[1];
		optind++;
	}
	
	extern char *optarg;
	int arg;
	while ((arg = getopt(argc, argv, "aphA")) != -1) {
		switch (arg) {
			case 'p':
				print_cert = true;
				break;
			case 'a':
				allCerts = true;
				break;
			case 'A':
				addToKC = true;
				break;
			case 'h':
			default:
				usage(argv);
		}
	}
	if(optind != argc) {
		usage(argv);
	}
	if(!allCerts && (emailAddress == NULL)) {
		printf("***You must specify either an email address or the -a option.\n");
		exit(1);
	}
	
	OSStatus					ortn;
	SecKeychainSearchRef		srch;
	SecKeychainAttributeList	attrList;
	SecKeychainAttribute		attr;
	unsigned					numCerts = 0;
	
	if(emailAddress) {
		attr.tag = kSecAlias;			// i.e., email address
		attr.length = strlen(emailAddress);
		attr.data = (void *)emailAddress;
		attrList.count = 1;
		attrList.attr = &attr;
	}
	else {
		attrList.count = 0;
		attrList.attr = NULL;
	}
	ortn = SecKeychainSearchCreateFromAttributes(NULL,	// default search list
		kSecCertificateItemClass,
		&attrList,
		&srch);
	if(ortn) {
		cssmPerror("SecKeychainSearchCreateFromAttributes", ortn);
		exit(1);
	}
	
	do {
		SecCertificateRef certRef = NULL;
		CSSM_DATA certData;
		
		ortn = SecKeychainSearchCopyNext(srch, (SecKeychainItemRef *)&certRef);
		if(ortn) {
			break;
		}
		ortn = SecCertificateGetData(certRef, &certData);
		if(ortn) {
			cssmPerror("SecCertificateGetData", ortn);
			continue;
		}
		
		printf("=== Cert %u ===\n", numCerts);
		printCertName(certData.Data, certData.Length, NameBoth);
		if(print_cert) {
			printCert(certData.Data, certData.Length, CSSM_FALSE);
		}
		if(addToKC) {
			/* 
			 * Can't call SecCertificateAddToKeychain directly since this 
			 * cert already has a keychain. 
			 */
			SecCertificateRef newCertRef = NULL;
			ortn = SecCertificateCreateFromData(&certData,	
				CSSM_CERT_X_509v3,	CSSM_CERT_ENCODING_DER, 
				&newCertRef);
			if(ortn) {
				cssmPerror("SecCertificateCreateFromData", ortn);
				printf("***Error adding this cert to default keychain.\n");
			}
			else {
				ortn = SecCertificateAddToKeychain(newCertRef, NULL);
				if(ortn) {
					cssmPerror("SecCertificateAddToKeychain", ortn);
					printf("***Error adding this cert to default keychain.\n");
				}
				else {
					printf("...cert added to default keychain.\n");
				}
				CFRelease(newCertRef);
			}
		}
		CFRelease(certRef);
		numCerts++;
	} while(ortn == noErr);
	printf("...%u certs found matching email address \'%s\'\n", numCerts, 
		emailAddress ? emailAddress : "<any>");
	CFRelease(srch);
	return 0;
}
/* 
 * 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;
}