#include <utils/debug.h>
+#include <Security/Security.h>
+
typedef struct private_keychain_creds_t private_keychain_creds_t;
/**
keychain_creds_t public;
};
+/**
+ * Enumerator for certificates
+ */
+typedef struct {
+ /* implements enumerator_t */
+ enumerator_t public;
+ /* currently enumerating certificate */
+ certificate_t *current;
+ /* id to filter for */
+ identification_t *id;
+ /* certificate public key type we are looking for */
+ key_type_t type;
+ /* array of binary certificates to enumerate */
+ CFArrayRef certs;
+ /* current position in array */
+ int i;
+} cert_enumerator_t;
+
+METHOD(enumerator_t, enumerate_certs, bool,
+ cert_enumerator_t *this, certificate_t **out)
+{
+ DESTROY_IF(this->current);
+ this->current = NULL;
+
+ while (this->i < CFArrayGetCount(this->certs))
+ {
+ certificate_t *cert;
+ public_key_t *key;
+ CFDataRef data;
+ chunk_t chunk;
+
+ data = CFArrayGetValueAtIndex(this->certs, this->i++);
+ if (data)
+ {
+ chunk = chunk_create((char*)CFDataGetBytePtr(data),
+ CFDataGetLength(data));
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
+ if (cert)
+ {
+ if (!this->id || cert->has_subject(cert, this->id))
+ {
+ key = cert->get_public_key(cert);
+ if (key)
+ {
+ if (this->type == KEY_ANY ||
+ this->type == key->get_type(key))
+ {
+ key->destroy(key);
+ this->current = cert;
+ *out = cert;
+ return TRUE;
+ }
+ key->destroy(key);
+ }
+ }
+ cert->destroy(cert);
+ }
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, destroy_certs, void,
+ cert_enumerator_t *this)
+{
+ DESTROY_IF(this->current);
+ CFRelease(this->certs);
+ free(this);
+}
+
METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
private_keychain_creds_t *this, certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted)
{
+ cert_enumerator_t *enumerator;
+ OSStatus status;
+ CFDictionaryRef query;
+ CFArrayRef result;
+ const void* keys[] = {
+ kSecReturnData,
+ kSecMatchLimit,
+ kSecClass,
+ kSecAttrCanVerify,
+ kSecMatchTrustedOnly,
+ };
+ const void* values[] = {
+ kCFBooleanTrue,
+ kSecMatchLimitAll,
+ kSecClassCertificate,
+ kCFBooleanTrue,
+ trusted ? kCFBooleanTrue : kCFBooleanFalse,
+ };
+
+ if (cert == CERT_ANY || cert == CERT_X509)
+ {
+ query = CFDictionaryCreate(NULL, keys, values, countof(keys),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (query)
+ {
+ status = SecItemCopyMatching(query, (CFTypeRef*)&result);
+ CFRelease(query);
+ if (status == errSecSuccess)
+ {
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_enumerate_certs,
+ .destroy = _destroy_certs,
+ },
+ .certs = result,
+ .id = id,
+ .type = key,
+ );
+ return &enumerator->public;
+ }
+ }
+ }
return enumerator_create_empty();
}