/*
 * Ensure that the policy being evaluated is accessible via 
 * SecPolicySearch*(). Not really part of the test, but a handy place
 * to catch this common error before checking in TP changes. 
 */ 
static int verifySecPolicy(
	const CSSM_OID *oid)
{
	SecPolicySearchRef srchRef = NULL;
	OSStatus ortn;
	
	ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, oid, NULL, &srchRef);
	if(ortn) {
		cssmPerror("SecPolicySearchCreate", ortn);
		return -1;
	}
	SecPolicyRef policyRef = NULL;
	ortn = SecPolicySearchCopyNext(srchRef, &policyRef);
	if(ortn) {
		cssmPerror("SecPolicySearchCopyNext", ortn);
		printf("***The TP policy used in this test is not accessible via SecPolicySearchCopyNext().\n");
		printf("   You probably forgot to add the policy to the theOidList table in PolicyCursor.cpp\n");
		printf("   in the libsecurity_keychain project.\n");
	}
	CFRelease(srchRef);
	if(policyRef) {
		CFRelease(policyRef);
	}
	return ortn;
}
CFTypeRef
CERT_PolicyForCertUsage(SECCertUsage certUsage)
{
    SecPolicySearchRef search = NULL;
    SecPolicyRef policy = NULL;
    const CSSM_OID *policyOID;
    OSStatus rv;

    switch (certUsage)
    {
    case certUsageSSLServerWithStepUp:
    case certUsageSSLCA:
    case certUsageVerifyCA:
    case certUsageAnyCA:
	goto loser;
	break;
    case certUsageSSLClient:
    case certUsageSSLServer:
	policyOID = &CSSMOID_APPLE_TP_SSL;
	break;
    case certUsageUserCertImport:
	policyOID = &CSSMOID_APPLE_TP_CSR_GEN;
	break;
    case certUsageStatusResponder:
	policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP;
	break;
    case certUsageObjectSigner:
    case certUsageProtectedObjectSigner:
	policyOID = &CSSMOID_APPLE_ISIGN;
	break;
    case certUsageEmailSigner:
    case certUsageEmailRecipient:
	policyOID = &CSSMOID_APPLE_X509_BASIC;
	break;
    default:
	goto loser;
    }
    rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search);
    if (rv)
	goto loser;

    rv = SecPolicySearchCopyNext(search, &policy);
    if (rv)
	goto loser;

loser:
    if(search) CFRelease(search);
    return policy;
}
/* new in 10.6 */
SecPolicyRef
SecPolicyCreateBasicX509(void)
{
    // return a SecPolicyRef object for the X.509 Basic policy
    SecPolicyRef policy = nil;
    SecPolicySearchRef policySearch = nil;
    OSStatus status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &policySearch);
    if (!status) {
        status = SecPolicySearchCopyNext(policySearch, &policy);
    }
	if (policySearch) {
		CFRelease(policySearch);
	}
    return policy;
}
OSStatus
SecPolicyCopy(CSSM_CERT_TYPE certificateType, const CSSM_OID *policyOID, SecPolicyRef* policy)
{
	Required(policy);
	Required(policyOID);
	
	SecPolicySearchRef srchRef = NULL;
	OSStatus ortn;
	
	ortn = SecPolicySearchCreate(certificateType, policyOID, NULL, &srchRef);
	if(ortn) {
		return ortn;
	}
	ortn = SecPolicySearchCopyNext(srchRef, policy);
	CFRelease(srchRef);
	return ortn;
}
/* new in 10.6 */
SecPolicyRef
SecPolicyCreateSSL(Boolean server, CFStringRef hostname)
{
    // return a SecPolicyRef object for the SSL policy, given hostname and client options
    SecPolicyRef policy = nil;
    SecPolicySearchRef policySearch = nil;
    OSStatus status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, NULL, &policySearch);
    if (!status) {
        status = SecPolicySearchCopyNext(policySearch, &policy);
    }
    if (!status && policy) {
        // set options for client-side or server-side policy evaluation
		char *strbuf = NULL;
		const char *hostnamestr = NULL;
		if (hostname) {
			CFIndex strbuflen = 0;
			hostnamestr = CFStringGetCStringPtr(hostname, kCFStringEncodingUTF8);
			if (hostnamestr == NULL) {
				strbuflen = CFStringGetLength(hostname)*6;
				strbuf = (char *)malloc(strbuflen+1);
				if (CFStringGetCString(hostname, strbuf, strbuflen, kCFStringEncodingUTF8)) {
					hostnamestr = strbuf;
				}
			}
		}
        uint32 hostnamelen = (hostnamestr) ? strlen(hostnamestr) : 0;
        uint32 flags = (!server) ? CSSM_APPLE_TP_SSL_CLIENT : 0;
        CSSM_APPLE_TP_SSL_OPTIONS opts = {CSSM_APPLE_TP_SSL_OPTS_VERSION, hostnamelen, hostnamestr, flags};
        CSSM_DATA data = {sizeof(opts), (uint8*)&opts};
        SecPolicySetValue(policy, &data);
		
		if (strbuf) {
			free(strbuf);
		}
    }
	if (policySearch) {
		CFRelease(policySearch);
	}
    return policy;
}
/* new in 10.7 */
SecPolicyRef
SecPolicyCreateWithOID(CFTypeRef policyOID)
{
	//%%% FIXME: allow policyOID to be a CFDataRef or a CFStringRef for an arbitrary OID
	// for now, we only accept the policy constants that are defined in SecPolicy.h
	CFStringRef oidStr = (CFStringRef)policyOID;
	CSSM_OID *oidPtr = NULL;
	SecPolicyRef policy = NULL;
	const void* oidmap[] = {
		kSecPolicyAppleX509Basic, &CSSMOID_APPLE_X509_BASIC,
		kSecPolicyAppleSSL, &CSSMOID_APPLE_TP_SSL,
		kSecPolicyAppleSMIME, &CSSMOID_APPLE_TP_SMIME,
		kSecPolicyAppleEAP, &CSSMOID_APPLE_TP_EAP,
		kSecPolicyAppleIPsec, &CSSMOID_APPLE_TP_IP_SEC,
		kSecPolicyAppleiChat, &CSSMOID_APPLE_TP_ICHAT,
		kSecPolicyApplePKINITClient, &CSSMOID_APPLE_TP_PKINIT_CLIENT,
		kSecPolicyApplePKINITServer, &CSSMOID_APPLE_TP_PKINIT_SERVER,
		kSecPolicyAppleCodeSigning, &CSSMOID_APPLE_TP_CODE_SIGNING,
		kSecPolicyMacAppStoreReceipt, &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT,
		kSecPolicyAppleIDValidation, &CSSMOID_APPLE_TP_APPLEID_SHARING
	};
	unsigned int i, oidmaplen = sizeof(oidmap) / sizeof(oidmap[0]);
	for (i=0; i<oidmaplen*2; i+=2) {
		CFStringRef str = (CFStringRef)oidmap[i];
		if (CFStringCompare(str, oidStr, 0) == kCFCompareEqualTo) {
			oidPtr = (CSSM_OID*)oidmap[i+1];
			break;
		}
	}
	if (oidPtr) {
		SecPolicySearchRef policySearch = NULL;
		OSStatus status = SecPolicySearchCreate(CSSM_CERT_X_509v3, oidPtr, NULL, &policySearch);
		if (!status && policySearch) {
			status = SecPolicySearchCopyNext(policySearch, &policy);
			CFRelease(policySearch);
		}
	}
	return policy;
}
Example #7
0
SecPolicyRef Download::GetPolicy ()
{
	SecPolicySearchRef search;
	SecPolicyRef policy;
	OSStatus result;

	// get the policy for resource signing
	result = SecPolicySearchCreate (CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_RESOURCE_SIGN, NULL, &search);
	if (result != noErr)
	{
		MacOSError::throwMe (result);
	}
	
	result = SecPolicySearchCopyNext (search, &policy);
	if (result != noErr)
	{
		MacOSError::throwMe (result);
	}

	CFRelease (search);
	
	return policy;
}
Example #8
0
/*
 * Parse a ContentInfo as best we can. All return fields are optional.
 * If signer_cert_status is NULL on entry, NO signature or cert evaluation 
 * will be performed. 
 */
krb5_error_code krb5int_pkinit_parse_cms_msg(
    const krb5_data	    *content_info,
    krb5_pkinit_cert_db_t   cert_db,		/* may be required for SignedData */
    krb5_boolean	    is_client_msg,	/* TRUE : msg is from client */
    krb5_boolean	    *is_signed,		/* RETURNED */
    krb5_boolean	    *is_encrypted,	/* RETURNED */
    krb5_data		    *raw_data,		/* RETURNED */
    krb5int_cms_content_type *inner_content_type,/* Returned, ContentType of */
						/*    EncapsulatedData */
    krb5_data		    *signer_cert,	/* RETURNED */
    krb5int_cert_sig_status *signer_cert_status,/* RETURNED */
    unsigned		    *num_all_certs,	/* size of *all_certs RETURNED */
    krb5_data		    **all_certs)	/* entire cert chain RETURNED */
{
    SecPolicySearchRef policy_search = NULL;
    SecPolicyRef policy = NULL;
    OSStatus ortn;
    krb5_error_code krtn = 0;
    CMSDecoderRef decoder = NULL;
    size_t num_signers;
    CMSSignerStatus signer_status;
    OSStatus cert_verify_status;
    CFArrayRef cf_all_certs = NULL;
    int msg_is_signed = 0;
    
    if(content_info == NULL) {
	pkiDebug("krb5int_pkinit_parse_cms_msg: no ContentInfo\n");
	return KRB5_CRYPTO_INTERNAL;
    }
    
    ortn = CMSDecoderCreate(&decoder);
    if(ortn) {
	return ENOMEM;
    }
    ortn = CMSDecoderUpdateMessage(decoder, content_info->data, content_info->length);
    if(ortn) {
	/* no verify yet, must be bad message */
	krtn = KRB5_PARSE_MALFORMED;
	goto errOut;
    }
    ortn = CMSDecoderFinalizeMessage(decoder);
    if(ortn) {
	pkiCssmErr("CMSDecoderFinalizeMessage", ortn);
	krtn = KRB5_PARSE_MALFORMED;
	goto errOut;
    }

    /* expect zero or one signers */
    ortn = CMSDecoderGetNumSigners(decoder, &num_signers);
    switch(num_signers) {
	case 0:
	    msg_is_signed = 0;
	    break;
	case 1:
	    msg_is_signed = 1;
	    break;
	default:
	    krtn = KRB5_PARSE_MALFORMED;
	    goto errOut;
    }

    /*
     * We need a cert verify policy even if we're not actually evaluating 
     * the cert due to requirements in libsecurity_smime.
     */
    ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
	is_client_msg ? &CSSMOID_APPLE_TP_PKINIT_CLIENT : &CSSMOID_APPLE_TP_PKINIT_SERVER, 
	NULL, &policy_search);
    if(ortn) {
	pkiCssmErr("SecPolicySearchCreate", ortn);
	krtn = KRB5_CRYPTO_INTERNAL;
	goto errOut;
    }
    ortn = SecPolicySearchCopyNext(policy_search, &policy);
    if(ortn) {
	pkiCssmErr("SecPolicySearchCopyNext", ortn);
	krtn = KRB5_CRYPTO_INTERNAL;
	goto errOut;
    }
    
    /* get some basic status that doesn't need heavyweight evaluation */
    if(msg_is_signed) {
	if(is_signed) {
	    *is_signed = TRUE;
	}
	if(inner_content_type) {
	    CSSM_OID ec_oid = {0, NULL};
	    CFDataRef ec_data = NULL;
	    
	    krb5int_cms_content_type ctype;
	    
	    ortn = CMSDecoderCopyEncapsulatedContentType(decoder, &ec_data);
	    if(ortn || (ec_data == NULL)) {
		pkiCssmErr("CMSDecoderCopyEncapsulatedContentType", ortn);
		krtn = KRB5_CRYPTO_INTERNAL;
		goto errOut;
	    }
	    ec_oid.Data = (uint8 *)CFDataGetBytePtr(ec_data);
	    ec_oid.Length = CFDataGetLength(ec_data);
	    if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_Data)) {
		ctype = ECT_Data;
	    }
	    else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_SignedData)) {
		ctype = ECT_SignedData;
	    }
	    else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EnvelopedData)) {
		ctype = ECT_EnvelopedData;
	    }
	    else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EncryptedData)) {
		ctype = ECT_EncryptedData;
	    }
	    else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_AUTH_DATA)) {
		ctype = ECT_PkAuthData;
	    }
	    else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_RKEY_DATA)) {
		ctype = ECT_PkReplyKeyKata;
	    }
	    else {
		ctype = ECT_Other;
	    }
	    *inner_content_type = ctype;
	    CFRelease(ec_data);
	}
	
	/* 
	 * Get SignedData's certs if the caller wants them
	 */
	if(all_certs) {	    
	    ortn = CMSDecoderCopyAllCerts(decoder, &cf_all_certs);
	    if(ortn) {
		pkiCssmErr("CMSDecoderCopyAllCerts", ortn);
		krtn = KRB5_CRYPTO_INTERNAL;
		goto errOut;
	    }
	    krtn = pkiCertArrayToKrb5Data(cf_all_certs, num_all_certs, all_certs);
	    if(krtn) {
		goto errOut;
	    }
	}
	
	/* optional signer cert */
	if(signer_cert) {
	    SecCertificateRef sec_signer_cert = NULL;
	    CSSM_DATA cert_data;

	    ortn = CMSDecoderCopySignerCert(decoder, 0, &sec_signer_cert);
	    if(ortn) {
		/* should never happen if it's signed */
		pkiCssmErr("CMSDecoderCopySignerStatus", ortn);
		krtn = KRB5_CRYPTO_INTERNAL;
		goto errOut;
	    }
	    ortn = SecCertificateGetData(sec_signer_cert, &cert_data);
	    if(ortn) {
		pkiCssmErr("SecCertificateGetData", ortn);
		CFRelease(sec_signer_cert);
		krtn = KRB5_CRYPTO_INTERNAL;
		goto errOut;
	    }
	    krtn = pkiDataToKrb5Data(cert_data.Data, cert_data.Length, signer_cert);
	    CFRelease(sec_signer_cert);
	    if(krtn) {
		goto errOut;
	    }
	}
    }
    else {
	/* not signed */
	if(is_signed) {
	    *is_signed = FALSE;
	}
	if(inner_content_type) {
	    *inner_content_type = ECT_Other;
	}
	if(signer_cert) {
	    signer_cert->data = NULL;
	    signer_cert->length = 0;
	}
	if(signer_cert_status) {
	    *signer_cert_status = pki_not_signed;
	}
	if(num_all_certs) {
	    *num_all_certs = 0;
	}
	if(all_certs) {
	    *all_certs = NULL;
	}
    }
    if(is_encrypted) {
	Boolean bencr;
	ortn = CMSDecoderIsContentEncrypted(decoder, &bencr);
	if(ortn) {
	    pkiCssmErr("CMSDecoderCopySignerStatus", ortn);
	    krtn = KRB5_CRYPTO_INTERNAL;
	    goto errOut;
	}
	*is_encrypted = bencr ? TRUE : FALSE;
    }
    
    /* 
     * Verify signature and cert. The actual verify operation is optional,
     * per our signer_cert_status argument, but we do this anyway if we need
     * to get the signer cert.
     */
    if((signer_cert_status != NULL) || (signer_cert != NULL)) {
	
	ortn = CMSDecoderCopySignerStatus(decoder, 
	    0,					    /* signerIndex */
	    policy,
	    signer_cert_status ? TRUE : FALSE,	    /* evaluateSecTrust */
	    &signer_status,
	    NULL,				    /* secTrust - not needed */
	    &cert_verify_status);
	if(ortn) {
	    /* gross error - subsequent processing impossible */
	    pkiCssmErr("CMSDecoderCopySignerStatus", ortn);
	    krtn = KRB5_PARSE_MALFORMED;
	    goto errOut;
	}
    }
    /* obtain & return status */
    if(signer_cert_status) {
	*signer_cert_status = pkiInferSigStatus(signer_status, cert_verify_status);
    }
    
    /* finally, the payload */
    if(raw_data) {
	CFDataRef cf_content = NULL;
	
	ortn = CMSDecoderCopyContent(decoder, &cf_content);
	if(ortn) {
	    pkiCssmErr("CMSDecoderCopyContent", ortn);
	    krtn = KRB5_PARSE_MALFORMED;
	    goto errOut;
	}
	krtn = pkiCfDataToKrb5Data(cf_content, raw_data);
	CFRELEASE(cf_content);
    }
errOut:
    CFRELEASE(policy_search);
    CFRELEASE(policy);
    CFRELEASE(cf_all_certs);
    CFRELEASE(decoder);
    return krtn;
}
/*
 * Given a SecIdentityRef, do our best to construct a complete, ordered, and 
 * verified cert chain, returning the result in a CFArrayRef. The result is 
 * suitable for use when calling SSLSetCertificate().
 */
OSStatus sslCompleteCertChain(
	SecIdentityRef 		identity, 
	SecCertificateRef	trustedAnchor,	// optional additional trusted anchor
	bool 				includeRoot, 	// include the root in outArray
	CFArrayRef			*outArray)		// created and RETURNED
{
	CFMutableArrayRef 			certArray;
	SecTrustRef					secTrust = NULL;
	SecPolicyRef				policy = NULL;
	SecPolicySearchRef			policySearch = NULL;
	SecTrustResultType			secTrustResult;
	CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv;			// not used
	CFArrayRef					certChain = NULL;   // constructed chain
	CFIndex 					numResCerts;
	
	certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	CFArrayAppendValue(certArray, identity);
	
	/*
	 * Case 1: identity is a root; we're done. Note that this case
	 * overrides the includeRoot argument.
	 */
	SecCertificateRef certRef;
	OSStatus ortn = SecIdentityCopyCertificate(identity, &certRef);
	if(ortn) {
		/* should never happen */
		cssmPerror("SecIdentityCopyCertificate", ortn);
		return ortn;
	}
	bool isRoot = isCertRefRoot(certRef);
	if(isRoot) {
		*outArray = certArray;
		CFRelease(certRef);
		return errSecSuccess;
	}
	
	/* 
	 * Now use SecTrust to get a complete cert chain, using all of the 
	 * user's keychains to look for intermediate certs.
	 * NOTE this does NOT handle root certs which are not in the system
	 * root cert DB. (The above case, where the identity is a root cert, does.)
	 */
	CFMutableArrayRef subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
	CFArraySetValueAtIndex(subjCerts, 0, certRef);
			
	/* the array owns the subject cert ref now */
	CFRelease(certRef);
	
	/* Get a SecPolicyRef for generic X509 cert chain verification */
	ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
		&CSSMOID_APPLE_X509_BASIC,
		NULL,				// value
		&policySearch);
	if(ortn) {
		cssmPerror("SecPolicySearchCreate", ortn);
		goto errOut;
	}
	ortn = SecPolicySearchCopyNext(policySearch, &policy);
	if(ortn) {
		cssmPerror("SecPolicySearchCopyNext", ortn);
		goto errOut;
	}

	/* build a SecTrustRef for specified policy and certs */
	ortn = SecTrustCreateWithCertificates(subjCerts,
		policy, &secTrust);
	if(ortn) {
		cssmPerror("SecTrustCreateWithCertificates", ortn);
		goto errOut;
	}
	
	if(trustedAnchor) {
		/* 
		 * Tell SecTrust to trust this one in addition to the current
		 * trusted system-wide anchors.
		 */
		CFMutableArrayRef newAnchors;
		CFArrayRef currAnchors;
		
		ortn = SecTrustCopyAnchorCertificates(&currAnchors);
		if(ortn) {
			/* should never happen */
			cssmPerror("SecTrustCopyAnchorCertificates", ortn);
			goto errOut;
		}
		newAnchors = CFArrayCreateMutableCopy(NULL,
			CFArrayGetCount(currAnchors) + 1,
			currAnchors);
		CFRelease(currAnchors);
		CFArrayAppendValue(newAnchors, trustedAnchor);
		ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
		CFRelease(newAnchors);
		if(ortn) {
			cssmPerror("SecTrustSetAnchorCertificates", ortn);
			goto errOut;
		}
	}
	/* evaluate: GO */
	ortn = SecTrustEvaluate(secTrust, &secTrustResult);
	if(ortn) {
		cssmPerror("SecTrustEvaluate", ortn);
		goto errOut;
	}
	switch(secTrustResult) {
		case kSecTrustResultUnspecified:
			/* cert chain valid, no special UserTrust assignments */
		case kSecTrustResultProceed:
			/* cert chain valid AND user explicitly trusts this */
			break;
		default:
			/*
			 * Cert chain construction failed. 
			 * Just go with the single subject cert we were given.
			 */
			printf("***Warning: could not construct completed cert chain\n");
			ortn = errSecSuccess;
			goto errOut;
	}

	/* get resulting constructed cert chain */
	ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
	if(ortn) {
		cssmPerror("SecTrustEvaluate", ortn);
		goto errOut;
	}
	
	/*
	 * Copy certs from constructed chain to our result array, skipping 
	 * the leaf (which is already there, as a SecIdentityRef) and possibly
	 * a root.
	 */
	numResCerts = CFArrayGetCount(certChain);
	if(numResCerts < 2) {
		/*
		 * Can't happen: if subject was a root, we'd already have returned. 
		 * If chain doesn't verify to a root, we'd have bailed after
		 * SecTrustEvaluate().
		 */
		printf("***sslCompleteCertChain screwup: numResCerts %d\n", 
			(int)numResCerts);
		ortn = errSecSuccess;
		goto errOut;
	}
	if(!includeRoot) {
		/* skip the last (root) cert) */
		numResCerts--;
	}
	for(CFIndex dex=1; dex<numResCerts; dex++) {
		certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
		CFArrayAppendValue(certArray, certRef);
	}
errOut:
	/* clean up */
	if(secTrust) {
		CFRelease(secTrust);
	}
	if(subjCerts) {
		CFRelease(subjCerts);
	}
	if(policy) {
		CFRelease(policy);
	}
	if(policySearch) {
		CFRelease(policySearch);
	}
	*outArray = certArray;
	return ortn;
}
Example #10
0
CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
{
    SecPolicySearchRef searchRef = NULL;
    SecPolicyRef policy = NULL;
    CFArrayRef wrappedCert = NULL;
    SecTrustRef trust = NULL;
    CFArrayRef certChain = NULL;
    CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
    CFDataRef actionData = NULL;
    OSStatus status = 0;

    if (!cert)
	goto loser;

    status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
    if (status)
	goto loser;
    status = SecPolicySearchCopyNext(searchRef, &policy);
    if (status)
	goto loser;

    wrappedCert = CERT_CertListFromCert(cert);
    status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
    if (status)
	goto loser;

    /* Tell SecTrust that we don't care if any certs in the chain have expired,
       nor do we want to stop when encountering a cert with a trust setting;
       we always want to build the full chain.
    */
    CSSM_APPLE_TP_ACTION_DATA localActionData = {
        CSSM_APPLE_TP_ACTION_VERSION,
        CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
    };
    actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull);
    if (!actionData)
        goto loser;

    status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData);
    if (status)
        goto loser;

    status = SecTrustEvaluate(trust, NULL);
    if (status)
	goto loser;

    status = SecTrustGetResult(trust, NULL, &certChain, &statusChain);
    if (status)
	goto loser;

    /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
    if (!includeRoot && CFArrayGetCount(certChain) > 1)
    {
	CFMutableArrayRef subChain =  CFArrayCreateMutableCopy(NULL, 0, certChain);
	CFRelease(certChain);
	certChain = subChain;
	if (subChain)
	    CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1);
    }

loser:
    if (searchRef)
	CFRelease(searchRef);
    if (policy)
	CFRelease(policy);
    if (wrappedCert)
	CFRelease(wrappedCert);
    if (trust)
	CFRelease(trust);
    if (actionData)
	CFRelease(actionData);
    if (certChain && status)
    {
	CFRelease(certChain);
	certChain = NULL;
    }

    return certChain;
}
/* new in 10.7 */
SecPolicyRef
SecPolicyCreateWithOID(CFTypeRef policyOID)
{
	// for now, we only accept the policy constants that are defined in SecPolicy.h
	CFStringRef oidStr = (CFStringRef)policyOID;
	CSSM_OID *oidPtr = NULL;
	SecPolicyRef policy = NULL;
	if (!oidStr) {
		return policy;
	}
	struct oidmap_entry_t {
		const CFTypeRef oidstr;
		const SecAsn1Oid *oidptr;
	};
	const oidmap_entry_t oidmap[] = {
		{ kSecPolicyAppleX509Basic, &CSSMOID_APPLE_X509_BASIC },
		{ kSecPolicyAppleSSL, &CSSMOID_APPLE_TP_SSL },
		{ kSecPolicyAppleSMIME, &CSSMOID_APPLE_TP_SMIME },
		{ kSecPolicyAppleEAP, &CSSMOID_APPLE_TP_EAP },
		{ kSecPolicyAppleIPsec, &CSSMOID_APPLE_TP_IP_SEC },
		{ kSecPolicyAppleiChat, &CSSMOID_APPLE_TP_ICHAT },
		{ kSecPolicyApplePKINITClient, &CSSMOID_APPLE_TP_PKINIT_CLIENT },
		{ kSecPolicyApplePKINITServer, &CSSMOID_APPLE_TP_PKINIT_SERVER },
		{ kSecPolicyAppleCodeSigning, &CSSMOID_APPLE_TP_CODE_SIGNING },
		{ kSecPolicyMacAppStoreReceipt, &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT },
		{ kSecPolicyAppleIDValidation, &CSSMOID_APPLE_TP_APPLEID_SHARING },
		{ kSecPolicyAppleTimeStamping, &CSSMOID_APPLE_TP_TIMESTAMPING },
		{ kSecPolicyAppleRevocation, &CSSMOID_APPLE_TP_REVOCATION },
		{ kSecPolicyApplePassbookSigning, &CSSMOID_APPLE_TP_PASSBOOK_SIGNING },
		{ kSecPolicyAppleMobileStore, &CSSMOID_APPLE_TP_MOBILE_STORE },
		{ kSecPolicyAppleEscrowService, &CSSMOID_APPLE_TP_ESCROW_SERVICE },
		{ kSecPolicyAppleProfileSigner, &CSSMOID_APPLE_TP_PROFILE_SIGNING },
		{ kSecPolicyAppleQAProfileSigner, &CSSMOID_APPLE_TP_QA_PROFILE_SIGNING },
		{ kSecPolicyAppleTestMobileStore, &CSSMOID_APPLE_TP_TEST_MOBILE_STORE },
		{ kSecPolicyApplePCSEscrowService, &CSSMOID_APPLE_TP_PCS_ESCROW_SERVICE },
	};
	unsigned int i, oidmaplen = sizeof(oidmap) / sizeof(oidmap_entry_t);
	for (i=0; i<oidmaplen; i++) {
		CFStringRef str = (CFStringRef) oidmap[i].oidstr;
		if (CFStringCompare(str, oidStr, 0) == kCFCompareEqualTo) {
			oidPtr = (CSSM_OID*)oidmap[i].oidptr;
			break;
		}
	}
	if (CFEqual(oidStr, kSecPolicyAppleServerAuthentication)) {
		return SecPolicyCreateAppleSSLService(NULL);
	}
	if (oidPtr) {
		SecPolicySearchRef policySearch = NULL;
		OSStatus status = SecPolicySearchCreate(CSSM_CERT_X_509v3, oidPtr, NULL, &policySearch);
		if (!status && policySearch) {
			status = SecPolicySearchCopyNext(policySearch, &policy);
			CFRelease(policySearch);
		}
		if (!policy && CFEqual(policyOID, kSecPolicyAppleRevocation)) {
			policy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod);
		}
		if (!policy) {
			policy = SecPolicyCreateWithSecAsn1Oid((SecAsn1Oid*)oidPtr);
		}
	}
	return policy;
}