2 * Copyright (c) 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$Id: ks_keychain.c 20945 2007-06-06 22:17:17Z lha $");
37 #ifdef HAVE_FRAMEWORK_SECURITY
39 #include <Security/Security.h>
41 /* Missing function decls */
42 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
43 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
44 int, const CSSM_ACCESS_CREDENTIALS **);
45 #define kSecCredentialTypeDefault 0
49 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
50 SecKeychainAttributeList **attrs)
52 SecKeychainAttributeInfo attrInfo;
53 uint32 attrFormat = 0;
60 attrInfo.format = &attrFormat;
62 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
75 SecKeychainItemRef item;
81 kc_rsa_public_encrypt(int flen,
82 const unsigned char *from,
91 kc_rsa_public_decrypt(int flen,
92 const unsigned char *from,
102 kc_rsa_private_encrypt(int flen,
103 const unsigned char *from,
108 struct kc_rsa *kc = RSA_get_app_data(rsa);
112 const CSSM_ACCESS_CREDENTIALS *creds;
113 SecKeyRef privKeyRef = (SecKeyRef)kc->item;
114 CSSM_CSP_HANDLE cspHandle;
115 const CSSM_KEY *cssmKey;
116 CSSM_CC_HANDLE sigHandle = 0;
121 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
124 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
127 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
128 kSecCredentialTypeDefault, &creds);
131 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
132 creds, cssmKey, &sigHandle);
135 in.Data = (uint8 *)from;
138 sig.Data = (uint8 *)to;
139 sig.Length = kc->keysize;
141 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
143 /* cssmErrorString(cret); */
149 CSSM_DeleteContext(sigHandle);
155 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
156 RSA * rsa, int padding)
162 kc_rsa_init(RSA *rsa)
168 kc_rsa_finish(RSA *rsa)
170 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
171 CFRelease(kc_rsa->item);
172 memset(kc_rsa, 0, sizeof(*kc_rsa));
177 static const RSA_METHOD kc_rsa_pkcs1_method = {
178 "hx509 Keychain PKCS#1 RSA",
179 kc_rsa_public_encrypt,
180 kc_rsa_public_decrypt,
181 kc_rsa_private_encrypt,
182 kc_rsa_private_decrypt,
194 set_private_key(hx509_context context,
195 SecKeychainItemRef itemRef,
199 hx509_private_key key;
203 ret = _hx509_private_key_init(&key, NULL, NULL);
207 kc = calloc(1, sizeof(*kc));
209 _hx509_abort("out of memory");
215 _hx509_abort("out of memory");
217 /* Argh, fake modulus since OpenSSL API is on crack */
219 SecKeychainAttributeList *attrs = NULL;
224 if (rsa->n == NULL) abort();
226 ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
229 size = *(uint32_t *)attrs->attr[0].data;
230 SecKeychainItemFreeAttributesAndData(attrs, NULL);
232 kc->keysize = (size + 7) / 8;
234 data = malloc(kc->keysize);
235 memset(data, 0xe0, kc->keysize);
236 BN_bin2bn(data, kc->keysize, rsa->n);
241 RSA_set_method(rsa, &kc_rsa_pkcs1_method);
242 ret = RSA_set_app_data(rsa, kc);
244 _hx509_abort("RSA_set_app_data");
246 _hx509_private_key_assign_rsa(key, rsa);
247 _hx509_cert_assign_key(cert, key);
257 SecKeychainRef keychain;
261 keychain_init(hx509_context context,
262 hx509_certs certs, void **data, int flags,
263 const char *residue, hx509_lock lock)
265 struct ks_keychain *ctx;
268 ctx = calloc(1, sizeof(*ctx));
270 hx509_clear_error_string(context);
275 if (strcasecmp(residue, "system") == 0)
276 residue = "/System/Library/Keychains/X509Anchors";
278 ret = SecKeychainOpen(residue, &ctx->keychain);
280 hx509_set_error_string(context, 0, ENOENT,
281 "Failed to open %s", residue);
295 keychain_free(hx509_certs certs, void *data)
297 struct ks_keychain *ctx = data;
299 CFRelease(ctx->keychain);
300 memset(ctx, 0, sizeof(*ctx));
310 SecKeychainSearchRef searchRef;
314 keychain_iter_start(hx509_context context,
315 hx509_certs certs, void *data, void **cursor)
317 struct ks_keychain *ctx = data;
321 iter = calloc(1, sizeof(*iter));
323 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
327 ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
328 kSecCertificateItemClass,
333 hx509_set_error_string(context, 0, ret,
334 "Failed to start search for attributes");
347 keychain_iter(hx509_context context,
348 hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
350 SecKeychainAttributeList *attrs = NULL;
351 SecKeychainAttributeInfo attrInfo;
352 uint32 attrFormat = 0;
353 SecKeychainItemRef itemRef;
355 struct iter *iter = cursor;
364 ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
365 if (ret == errSecItemNotFound)
371 * Pick out certificate and matching "keyid"
374 item = kSecPublicKeyHashItemAttr;
377 attrInfo.tag = &item;
378 attrInfo.format = &attrFormat;
380 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
385 ret = decode_Certificate(ptr, len, &t, &size);
388 hx509_set_error_string(context, 0, ret, "Failed to parse certificate");
392 ret = hx509_cert_init(context, &t, cert);
393 free_Certificate(&t);
398 * Find related private key if there is one by looking at
399 * kSecPublicKeyHashItemAttr == kSecKeyLabel
402 SecKeychainSearchRef search;
403 SecKeychainAttribute attrKeyid;
404 SecKeychainAttributeList attrList;
406 attrKeyid.tag = kSecKeyLabel;
407 attrKeyid.length = attrs->attr[0].length;
408 attrKeyid.data = attrs->attr[0].data;
411 attrList.attr = &attrKeyid;
413 ret = SecKeychainSearchCreateFromAttributes(NULL,
414 CSSM_DL_DB_RECORD_PRIVATE_KEY,
422 ret = SecKeychainSearchCopyNext(search, &itemRef);
424 if (ret == errSecItemNotFound) {
431 set_private_key(context, itemRef, *cert);
435 SecKeychainItemFreeAttributesAndData(attrs, ptr);
445 keychain_iter_end(hx509_context context,
450 struct iter *iter = cursor;
452 CFRelease(iter->searchRef);
453 memset(iter, 0, sizeof(*iter));
462 struct hx509_keyset_ops keyset_keychain = {
475 #endif /* HAVE_FRAMEWORK_SECURITY */
482 _hx509_ks_keychain_register(hx509_context context)
484 #ifdef HAVE_FRAMEWORK_SECURITY
485 _hx509_ks_register(context, &keyset_keychain);