From b14a49e02eaf91b7924d44462f018005e3f60bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 5 Jun 2007 05:54:19 +0000 Subject: [PATCH] Find and attach private key (does not provide operations yet though). git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@20921 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/hx509/ks_keychain.c | 197 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 182 insertions(+), 15 deletions(-) diff --git a/lib/hx509/ks_keychain.c b/lib/hx509/ks_keychain.c index a594fda42..f5ab52946 100644 --- a/lib/hx509/ks_keychain.c +++ b/lib/hx509/ks_keychain.c @@ -37,11 +37,126 @@ RCSID("$Id$"); #ifdef HAVE_FRAMEWORK_SECURITY +/* + * + */ + +struct kc_rsa { + SecKeychainItemRef item; +}; + + +static int +kc_rsa_public_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + +static int +kc_rsa_public_decrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + + +static int +kc_rsa_private_encrypt(int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding) +{ + return -1; +} + +static int +kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, + RSA * rsa, int padding) +{ + return -1; +} + +static int +kc_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +kc_rsa_finish(RSA *rsa) +{ + struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); + CFRelease(kc_rsa->item); + free(kc_rsa); + return 1; +} + +static const RSA_METHOD kc_rsa_pkcs1_method = { + "hx509 Keychain PKCS#1 RSA", + kc_rsa_public_encrypt, + kc_rsa_public_decrypt, + kc_rsa_private_encrypt, + kc_rsa_private_decrypt, + NULL, + NULL, + kc_rsa_init, + kc_rsa_finish, + 0, + NULL, + NULL, + NULL +}; + +static int +private_key(hx509_context context, SecKeychainItemRef itemRef, + hx509_cert cert) +{ + struct kc_rsa *kc_rsa; + hx509_private_key key; + RSA *rsa; + int ret; + + ret = _hx509_private_key_init(&key, NULL, NULL); + if (ret) + return ret; + + rsa = RSA_new(); + if (rsa == NULL) + _hx509_abort("out of memory"); + + kc_rsa = calloc(1, sizeof(*kc_rsa)); + if (kc_rsa == NULL) + _hx509_abort("out of memory"); + + kc_rsa->item = itemRef; + + RSA_set_method(rsa, &kc_rsa_pkcs1_method); + ret = RSA_set_app_data(rsa, kc_rsa); + if (ret != 1) + _hx509_abort("RSA_set_app_data"); + + _hx509_private_key_assign_rsa(key, rsa); + _hx509_cert_assign_key(cert, key); + + return 0; +} + +/* + * + */ + struct ks_keychain { SecKeychainRef keychain; }; - static int keychain_init(hx509_context context, hx509_certs certs, void **data, int flags, @@ -56,10 +171,10 @@ keychain_init(hx509_context context, return ENOMEM; } - if (strcasecmp(residue, "system") == 0) - residue = "/System/Library/Keychains/X509Anchors"; + if (residue) { + if (strcasecmp(residue, "system") == 0) + residue = "/System/Library/Keychains/X509Anchors"; - if (residue && residue[0] != '\0') { ret = SecKeychainOpen(residue, &ctx->keychain); if (ret != noErr) { hx509_set_error_string(context, 0, ENOENT, @@ -93,7 +208,6 @@ keychain_free(hx509_certs certs, void *data) struct iter { SecKeychainSearchRef searchRef; - SecKeychainItemRef itemRef; }; static int @@ -132,14 +246,18 @@ static int keychain_iter(hx509_context context, hx509_certs certs, void *data, void *cursor, hx509_cert *cert) { + SecKeychainAttributeList *attrs = NULL; + SecKeychainAttributeInfo attrInfo; + uint32 attrFormat = 0; SecKeychainItemRef itemRef; + SecItemAttr item; struct iter *iter = cursor; Certificate t; OSStatus ret; UInt32 len; - void *ptr; + void *ptr = NULL; size_t size; - + *cert = NULL; ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); @@ -148,26 +266,75 @@ keychain_iter(hx509_context context, else if (ret != 0) return EINVAL; - ret = SecKeychainItemCopyAttributesAndData(itemRef, NULL, NULL, - NULL, &len, &ptr); + /* + * Pick out certificate and matching "keyid" + */ + + item = kSecPublicKeyHashItemAttr; + + attrInfo.count = 1; + attrInfo.tag = &item; + attrInfo.format = &attrFormat; + + ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, + &attrs, &len, &ptr); if (ret) return EINVAL; ret = decode_Certificate(ptr, len, &t, &size); - SecKeychainItemFreeAttributesAndData(NULL, ptr); CFRelease(itemRef); if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to parse certificate"); - return ret; + hx509_set_error_string(context, 0, ret, "Failed to parse certificate"); + goto out; } ret = hx509_cert_init(context, &t, cert); free_Certificate(&t); if (ret) - return ret; + goto out; - return 0; + /* + * Find related private key if there is one by looking at + * kSecPublicKeyHashItemAttr == kSecKeyLabel + */ + { + SecKeychainSearchRef search; + SecKeychainAttribute attrKeyid; + SecKeychainAttributeList attrList; + + attrKeyid.tag = kSecKeyLabel; + attrKeyid.length = attrs->attr[0].length; + attrKeyid.data = attrs->attr[0].data; + + attrList.count = 1; + attrList.attr = &attrKeyid; + + ret = SecKeychainSearchCreateFromAttributes(NULL, + CSSM_DL_DB_RECORD_PRIVATE_KEY, + &attrList, + &search); + if (ret) { + ret = 0; + goto out; + } + + ret = SecKeychainSearchCopyNext(search, &itemRef); + CFRelease(search); + if (ret == errSecItemNotFound) { + ret = 0; + goto out; + } else if (ret) { + ret = EINVAL; + goto out; + } + + private_key(context, itemRef, *cert); + } + +out: + SecKeychainItemFreeAttributesAndData(attrs, ptr); + + return ret; } /*