From: Martin Willi Date: Tue, 30 Apr 2013 09:59:01 +0000 (+0200) Subject: keychain: support on-the-fly enumeration of trusted/untrusted certificates X-Git-Tag: 5.1.0rc1~25^2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f00ddb90c2fa1c37b0bceda630292fa16a7cdf9;p=thirdparty%2Fstrongswan.git keychain: support on-the-fly enumeration of trusted/untrusted certificates --- diff --git a/src/libstrongswan/plugins/keychain/Makefile.am b/src/libstrongswan/plugins/keychain/Makefile.am index e0d25b686f..508a4b024f 100644 --- a/src/libstrongswan/plugins/keychain/Makefile.am +++ b/src/libstrongswan/plugins/keychain/Makefile.am @@ -13,4 +13,5 @@ libstrongswan_keychain_la_SOURCES = \ keychain_plugin.h keychain_plugin.c \ keychain_creds.h keychain_creds.c -libstrongswan_keychain_la_LDFLAGS = -module -avoid-version +libstrongswan_keychain_la_LDFLAGS = -module -avoid-version \ + -framework Security -framework CoreFoundation diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index d3331fa407..08ef826142 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -17,6 +17,8 @@ #include +#include + typedef struct private_keychain_creds_t private_keychain_creds_t; /** @@ -30,10 +32,124 @@ struct 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(); }