/*
 * Search specified keychain/array/NULL (NULL meaning the default search list) for
 * an Identity matching specified key usage and optional Issuer/Serial number.
 * If issuer/serial is specified and no identities match, or if no identities found
 * matching specified Key usage, errSecItemNotFound is returned.
 *
 * Caller must CFRelease a non-NULL returned idRef.
 */
static OSStatus pkinit_search_ident(
    CFTypeRef           keychainOrArray,
    CSSM_KEYUSE         keyUsage,
    const CSSM_DATA     *issuerSerial,  /* optional */
    SecIdentityRef      *foundId)       /* RETURNED */
{
    OSStatus ortn;
    SecIdentityRef idRef = NULL;
    SecIdentitySearchRef srchRef = NULL;

    ortn = SecIdentitySearchCreate(keychainOrArray, keyUsage, &srchRef);
    if(ortn) {
        pkiCssmErr("SecIdentitySearchCreate", ortn);
        return ortn;
    }
    do {
        ortn = SecIdentitySearchCopyNext(srchRef, &idRef);
        if(ortn != noErr) {
            break;
        }
        if(issuerSerial == NULL) {
            /* no match needed, we're done - this is the KDC cert case */
            break;
        }
        else if(pkinit_issuer_sn_match(idRef, issuerSerial)) {
            /* match, we're done */
            break;
        }
        /* finished with this one */
        CFRelease(idRef);
        idRef = NULL;
    } while(ortn == noErr);

    CFRelease(srchRef);
    if(idRef == NULL) {
        return errSecItemNotFound;
    }
    else {
        *foundId = idRef;
        return noErr;
    }
}
/*
 * Add all SecIdentityRefs from a keychain into an array.
 */
static OSStatus addIdentities(
	SecKeychainRef kcRef,
	CFMutableArrayRef outArray,
	unsigned *numItems)			// UPDATED on return
{
	/* Search for all identities */
	SecIdentitySearchRef srchRef;
	OSStatus ortn = SecIdentitySearchCreate(kcRef,
		0,				// keyUsage - any
		&srchRef);
	if(ortn) {
		sec_perror("SecIdentitySearchCreate", ortn);
		return ortn;
	}

	do {
		SecIdentityRef identity;
		ortn = SecIdentitySearchCopyNext(srchRef, &identity);
		if(ortn) {
			if(ortn == errSecItemNotFound) {
				/* normal search end */
				ortn = noErr;
			}
			else {
				sec_perror("SecIdentitySearchCopyNext", ortn);
			}
			break;
		}
		CFArrayAppendValue(outArray, identity);

		/* the array has the retain count we need */
		CFRelease(identity);
		(*numItems)++;
	} while(ortn == noErr);
	CFRelease(srchRef);
	return ortn;
}
Beispiel #3
0
int findEncryptionIdentities(CFTypeRef *identityOrArray)
{
	/*
		Similar code is available in Leopard9A311 and later as "DIHLFVCopyEncryptionIdentities".
		See <rdar://problem/4816811> FV: Add SecTokenBasedEncryptionIdentities call
		We reproduce it here for two reasons:
		1)	The semantics of DIHLFVCopyEncryptionIdentities are different, 
			returning either a CFData or CFArray
		2)	We don' have to introduce a dependence on DiskImages.framework here


		Since CSSM searching for attributes is an AND, not an OR, we need to get all
		identities then check each one for a good key usage. If we built up a search
		using an OR predicate, we would want to specify this for key usage:
		
		uint32_t keyuse = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP;
	*/
	OSStatus status = noErr;
	CFArrayRef searchList = NULL;
	CFMutableArrayRef idArray = NULL;			// holds all SecIdentityRefs found

	status = SecKeychainCopyDomainSearchList(kSecPreferencesDomainDynamic, &searchList);
	if (status)
		return status;
		
	CFIndex count = searchList ? CFArrayGetCount(searchList) : 0;
	if (!count)
		return errSecNoSuchKeychain;

	// Search for all identities
	uint32_t keyuse = 0;
	SecIdentitySearchRef srchRef = NULL;
	status = SecIdentitySearchCreate(searchList, keyuse, &srchRef);
	if (status)
		return status;

	while (!status)
	{
		SecIdentityRef identity = NULL;
		status = SecIdentitySearchCopyNext(srchRef, &identity);
		if (status == errSecItemNotFound)	// done
			break;
		if (status)
			return status;

		SecKeyRef privateKeyRef = NULL;
		status = SecIdentityCopyPrivateKey(identity, &privateKeyRef);
		if (status)
			continue;
		bool canEncrypt = encryptionEnabled(privateKeyRef);
		CFRelease(privateKeyRef);
		if (!canEncrypt)
			continue;
			
		// add the identity to the array
		if (!idArray)
			idArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
		CFArrayAppendValue(idArray, identity);
	}

	if ((status == noErr || status == errSecItemNotFound) && idArray && CFArrayGetCount(idArray))
	{
		if (idArray)
		{
			*identityOrArray = idArray;
			::CFRetain(*identityOrArray);
		}
		status = noErr;
	}
	else
	if (idArray)
		CFRelease(idArray);

	return status;
}
/*
 * Given an open keychain, find a SecIdentityRef and munge it into
 * a CFArrayRef required by SSLSetCertificate().
 */
CFArrayRef sslKcRefToCertArray(
	SecKeychainRef		kcRef,
	bool                encryptOnly,
	bool                completeCertChain,
	const char			*trustedAnchorFile)
{
	/* quick check to make sure the keychain exists */
	SecKeychainStatus kcStat;
	OSStatus ortn = SecKeychainGetStatus(kcRef, &kcStat);
	if(ortn) {
		printSslErrStr("SecKeychainGetStatus", ortn);
		printf("Can not open keychain. Aborting.\n");
		return nil;
	}
	
	/*
	 * Search for "any" identity matching specified key use; 
	 * in this app, we expect there to be exactly one. 
	 */
	SecIdentitySearchRef srchRef = nil;
	ortn = SecIdentitySearchCreate(kcRef, 
		encryptOnly ? CSSM_KEYUSE_DECRYPT : CSSM_KEYUSE_SIGN,
		&srchRef);
	if(ortn) {
		printf("SecIdentitySearchCreate returned %d.\n", (int)ortn);
		printf("Cannot find signing key in keychain. Aborting.\n");
		return nil;
	}
	SecIdentityRef identity = nil;
	ortn = SecIdentitySearchCopyNext(srchRef, &identity);
	if(ortn) {
		printf("SecIdentitySearchCopyNext returned %d.\n", (int)ortn);
		printf("Cannot find signing key in keychain. Aborting.\n");
		return nil;
	}
	if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
		printf("SecIdentitySearchCopyNext CFTypeID failure!\n");
		return nil;
	}

	/* 
	 * Found one. 
	 */
	if(completeCertChain) {
		/* 
		 * Place it and the other certs needed to verify it -
		 * up to but not including the root - in a CFArray.
		 */
		SecCertificateRef anchorCert = NULL;
		if(trustedAnchorFile) {
			ortn = sslReadAnchor(trustedAnchorFile, &anchorCert);
			if(ortn) {
				printf("***Error reading anchor file\n");
			}
		}
		CFArrayRef ca;
		ortn = sslCompleteCertChain(identity, anchorCert, false, &ca);
		if(anchorCert) {
			CFRelease(anchorCert);
		}
		return ca;
	}
	else {
		/* simple case, just this one identity */
		CFArrayRef ca = CFArrayCreate(NULL,
			(const void **)&identity,
			1,
			NULL);
		if(ca == nil) {
			printf("CFArrayCreate error\n");
		}
		return ca;
	}
}