ks_keychain.c revision 178825
1275970Scy/*
2275970Scy * Copyright (c) 2007 Kungliga Tekniska H�gskolan
3275970Scy * (Royal Institute of Technology, Stockholm, Sweden).
4275970Scy * All rights reserved.
5275970Scy *
6275970Scy * Redistribution and use in source and binary forms, with or without
7275970Scy * modification, are permitted provided that the following conditions
8275970Scy * are met:
9275970Scy *
10275970Scy * 1. Redistributions of source code must retain the above copyright
11275970Scy *    notice, this list of conditions and the following disclaimer.
12275970Scy *
13275970Scy * 2. Redistributions in binary form must reproduce the above copyright
14275970Scy *    notice, this list of conditions and the following disclaimer in the
15275970Scy *    documentation and/or other materials provided with the distribution.
16275970Scy *
17275970Scy * 3. Neither the name of the Institute nor the names of its contributors
18275970Scy *    may be used to endorse or promote products derived from this software
19275970Scy *    without specific prior written permission.
20275970Scy *
21275970Scy * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24275970Scy * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31275970Scy * SUCH DAMAGE.
32275970Scy */
33275970Scy
34275970Scy#include "hx_locl.h"
35275970ScyRCSID("$Id: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $");
36275970Scy
37275970Scy#ifdef HAVE_FRAMEWORK_SECURITY
38275970Scy
39275970Scy#include <Security/Security.h>
40275970Scy
41275970Scy/* Missing function decls in pre Leopard */
42275970Scy#ifdef NEED_SECKEYGETCSPHANDLE_PROTO
43275970ScyOSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
44275970ScyOSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
45275970Scy			      int, const CSSM_ACCESS_CREDENTIALS **);
46275970Scy#define kSecCredentialTypeDefault 0
47275970Scy#endif
48275970Scy
49275970Scy
50275970Scystatic int
51275970ScygetAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
52275970Scy	     SecKeychainAttributeList **attrs)
53275970Scy{
54275970Scy    SecKeychainAttributeInfo attrInfo;
55275970Scy    UInt32 attrFormat = 0;
56275970Scy    OSStatus ret;
57275970Scy
58275970Scy    *attrs = NULL;
59275970Scy
60275970Scy    attrInfo.count = 1;
61275970Scy    attrInfo.tag = &item;
62275970Scy    attrInfo.format = &attrFormat;
63275970Scy
64275970Scy    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
65275970Scy					       attrs, NULL, NULL);
66275970Scy    if (ret)
67275970Scy	return EINVAL;
68275970Scy    return 0;
69275970Scy}
70275970Scy
71275970Scy
72275970Scy/*
73275970Scy *
74275970Scy */
75275970Scy
76275970Scystruct kc_rsa {
77275970Scy    SecKeychainItemRef item;
78275970Scy    size_t keysize;
79275970Scy};
80275970Scy
81275970Scy
82275970Scystatic int
83275970Scykc_rsa_public_encrypt(int flen,
84275970Scy		      const unsigned char *from,
85275970Scy		      unsigned char *to,
86275970Scy		      RSA *rsa,
87275970Scy		      int padding)
88275970Scy{
89275970Scy    return -1;
90275970Scy}
91275970Scy
92275970Scystatic int
93275970Scykc_rsa_public_decrypt(int flen,
94275970Scy		      const unsigned char *from,
95275970Scy		      unsigned char *to,
96275970Scy		      RSA *rsa,
97275970Scy		      int padding)
98275970Scy{
99275970Scy    return -1;
100275970Scy}
101275970Scy
102275970Scy
103275970Scystatic int
104275970Scykc_rsa_private_encrypt(int flen,
105275970Scy		       const unsigned char *from,
106275970Scy		       unsigned char *to,
107275970Scy		       RSA *rsa,
108275970Scy		       int padding)
109275970Scy{
110275970Scy    struct kc_rsa *kc = RSA_get_app_data(rsa);
111275970Scy
112275970Scy    CSSM_RETURN cret;
113275970Scy    OSStatus ret;
114275970Scy    const CSSM_ACCESS_CREDENTIALS *creds;
115275970Scy    SecKeyRef privKeyRef = (SecKeyRef)kc->item;
116275970Scy    CSSM_CSP_HANDLE cspHandle;
117275970Scy    const CSSM_KEY *cssmKey;
118275970Scy    CSSM_CC_HANDLE sigHandle = 0;
119275970Scy    CSSM_DATA sig, in;
120275970Scy    int fret = 0;
121275970Scy
122275970Scy
123275970Scy    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
124275970Scy    if(cret) abort();
125275970Scy
126275970Scy    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
127275970Scy    if(cret) abort();
128275970Scy
129275970Scy    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
130275970Scy			       kSecCredentialTypeDefault, &creds);
131275970Scy    if(ret) abort();
132275970Scy
133275970Scy    ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
134275970Scy					  creds, cssmKey, &sigHandle);
135275970Scy    if(ret) abort();
136275970Scy
137275970Scy    in.Data = (uint8 *)from;
138275970Scy    in.Length = flen;
139275970Scy
140275970Scy    sig.Data = (uint8 *)to;
141275970Scy    sig.Length = kc->keysize;
142275970Scy
143275970Scy    cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
144275970Scy    if(cret) {
145275970Scy	/* cssmErrorString(cret); */
146275970Scy	fret = -1;
147275970Scy    } else
148275970Scy	fret = sig.Length;
149275970Scy
150275970Scy    if(sigHandle)
151275970Scy	CSSM_DeleteContext(sigHandle);
152275970Scy
153275970Scy    return fret;
154275970Scy}
155275970Scy
156275970Scystatic int
157275970Scykc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
158275970Scy		       RSA * rsa, int padding)
159275970Scy{
160275970Scy    return -1;
161275970Scy}
162275970Scy
163275970Scystatic int
164275970Scykc_rsa_init(RSA *rsa)
165275970Scy{
166275970Scy    return 1;
167275970Scy}
168275970Scy
169275970Scystatic int
170275970Scykc_rsa_finish(RSA *rsa)
171275970Scy{
172275970Scy    struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
173275970Scy    CFRelease(kc_rsa->item);
174275970Scy    memset(kc_rsa, 0, sizeof(*kc_rsa));
175275970Scy    free(kc_rsa);
176275970Scy    return 1;
177275970Scy}
178275970Scy
179275970Scystatic const RSA_METHOD kc_rsa_pkcs1_method = {
180275970Scy    "hx509 Keychain PKCS#1 RSA",
181275970Scy    kc_rsa_public_encrypt,
182275970Scy    kc_rsa_public_decrypt,
183275970Scy    kc_rsa_private_encrypt,
184275970Scy    kc_rsa_private_decrypt,
185275970Scy    NULL,
186275970Scy    NULL,
187275970Scy    kc_rsa_init,
188275970Scy    kc_rsa_finish,
189275970Scy    0,
190275970Scy    NULL,
191275970Scy    NULL,
192275970Scy    NULL
193275970Scy};
194275970Scy
195275970Scystatic int
196275970Scyset_private_key(hx509_context context,
197275970Scy		SecKeychainItemRef itemRef,
198275970Scy		hx509_cert cert)
199275970Scy{
200275970Scy    struct kc_rsa *kc;
201275970Scy    hx509_private_key key;
202275970Scy    RSA *rsa;
203275970Scy    int ret;
204275970Scy
205275970Scy    ret = _hx509_private_key_init(&key, NULL, NULL);
206275970Scy    if (ret)
207275970Scy	return ret;
208275970Scy
209275970Scy    kc = calloc(1, sizeof(*kc));
210275970Scy    if (kc == NULL)
211275970Scy	_hx509_abort("out of memory");
212275970Scy
213275970Scy    kc->item = itemRef;
214275970Scy
215275970Scy    rsa = RSA_new();
216275970Scy    if (rsa == NULL)
217275970Scy	_hx509_abort("out of memory");
218275970Scy
219275970Scy    /* Argh, fake modulus since OpenSSL API is on crack */
220275970Scy    {
221275970Scy	SecKeychainAttributeList *attrs = NULL;
222275970Scy	uint32_t size;
223275970Scy	void *data;
224275970Scy
225275970Scy	rsa->n = BN_new();
226275970Scy	if (rsa->n == NULL) abort();
227275970Scy
228275970Scy	ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
229275970Scy	if (ret) abort();
230275970Scy
231275970Scy	size = *(uint32_t *)attrs->attr[0].data;
232275970Scy	SecKeychainItemFreeAttributesAndData(attrs, NULL);
233275970Scy
234275970Scy	kc->keysize = (size + 7) / 8;
235275970Scy
236275970Scy	data = malloc(kc->keysize);
237275970Scy	memset(data, 0xe0, kc->keysize);
238275970Scy	BN_bin2bn(data, kc->keysize, rsa->n);
239275970Scy	free(data);
240275970Scy    }
241275970Scy    rsa->e = NULL;
242275970Scy
243275970Scy    RSA_set_method(rsa, &kc_rsa_pkcs1_method);
244275970Scy    ret = RSA_set_app_data(rsa, kc);
245275970Scy    if (ret != 1)
246275970Scy	_hx509_abort("RSA_set_app_data");
247275970Scy
248275970Scy    _hx509_private_key_assign_rsa(key, rsa);
249275970Scy    _hx509_cert_assign_key(cert, key);
250275970Scy
251275970Scy    return 0;
252275970Scy}
253275970Scy
254275970Scy/*
255275970Scy *
256275970Scy */
257275970Scy
258275970Scystruct ks_keychain {
259275970Scy    int anchors;
260275970Scy    SecKeychainRef keychain;
261275970Scy};
262275970Scy
263275970Scystatic int
264275970Scykeychain_init(hx509_context context,
265275970Scy	      hx509_certs certs, void **data, int flags,
266275970Scy	      const char *residue, hx509_lock lock)
267275970Scy{
268275970Scy    struct ks_keychain *ctx;
269275970Scy
270275970Scy    ctx = calloc(1, sizeof(*ctx));
271275970Scy    if (ctx == NULL) {
272275970Scy	hx509_clear_error_string(context);
273275970Scy	return ENOMEM;
274275970Scy    }
275275970Scy
276275970Scy    if (residue) {
277275970Scy	if (strcasecmp(residue, "system-anchors") == 0) {
278275970Scy	    ctx->anchors = 1;
279275970Scy	} else if (strncasecmp(residue, "FILE:", 5) == 0) {
280275970Scy	    OSStatus ret;
281275970Scy
282275970Scy	    ret = SecKeychainOpen(residue + 5, &ctx->keychain);
283275970Scy	    if (ret != noErr) {
284275970Scy		hx509_set_error_string(context, 0, ENOENT,
285275970Scy				       "Failed to open %s", residue);
286275970Scy		return ENOENT;
287275970Scy	    }
288275970Scy	} else {
289275970Scy	    hx509_set_error_string(context, 0, ENOENT,
290275970Scy				   "Unknown subtype %s", residue);
291275970Scy	    return ENOENT;
292275970Scy	}
293275970Scy    }
294275970Scy
295275970Scy    *data = ctx;
296275970Scy    return 0;
297275970Scy}
298275970Scy
299275970Scy/*
300275970Scy *
301275970Scy */
302275970Scy
303275970Scystatic int
304275970Scykeychain_free(hx509_certs certs, void *data)
305275970Scy{
306275970Scy    struct ks_keychain *ctx = data;
307275970Scy    if (ctx->keychain)
308275970Scy	CFRelease(ctx->keychain);
309275970Scy    memset(ctx, 0, sizeof(*ctx));
310275970Scy    free(ctx);
311275970Scy    return 0;
312275970Scy}
313275970Scy
314275970Scy/*
315275970Scy *
316275970Scy */
317275970Scy
318275970Scystruct iter {
319275970Scy    hx509_certs certs;
320275970Scy    void *cursor;
321275970Scy    SecKeychainSearchRef searchRef;
322275970Scy};
323275970Scy
324275970Scystatic int
325275970Scykeychain_iter_start(hx509_context context,
326275970Scy		    hx509_certs certs, void *data, void **cursor)
327275970Scy{
328275970Scy    struct ks_keychain *ctx = data;
329275970Scy    struct iter *iter;
330275970Scy
331275970Scy    iter = calloc(1, sizeof(*iter));
332275970Scy    if (iter == NULL) {
333275970Scy	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
334275970Scy	return ENOMEM;
335275970Scy    }
336275970Scy
337275970Scy    if (ctx->anchors) {
338275970Scy        CFArrayRef anchors;
339275970Scy	int ret;
340275970Scy	int i;
341275970Scy
342275970Scy	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
343275970Scy			       0, NULL, &iter->certs);
344275970Scy	if (ret) {
345275970Scy	    free(iter);
346275970Scy	    return ret;
347275970Scy	}
348275970Scy
349275970Scy	ret = SecTrustCopyAnchorCertificates(&anchors);
350275970Scy	if (ret != 0) {
351275970Scy	    hx509_certs_free(&iter->certs);
352275970Scy	    free(iter);
353275970Scy	    hx509_set_error_string(context, 0, ENOMEM,
354275970Scy				   "Can't get trust anchors from Keychain");
355275970Scy	    return ENOMEM;
356275970Scy	}
357275970Scy	for (i = 0; i < CFArrayGetCount(anchors); i++) {
358275970Scy	    SecCertificateRef cr;
359275970Scy	    hx509_cert cert;
360275970Scy	    CSSM_DATA cssm;
361275970Scy
362275970Scy	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
363275970Scy
364275970Scy	    SecCertificateGetData(cr, &cssm);
365275970Scy
366275970Scy	    ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
367275970Scy	    if (ret)
368275970Scy		continue;
369275970Scy
370275970Scy	    ret = hx509_certs_add(context, iter->certs, cert);
371275970Scy	    hx509_cert_free(cert);
372275970Scy	}
373275970Scy	CFRelease(anchors);
374275970Scy    }
375275970Scy
376275970Scy    if (iter->certs) {
377275970Scy	int ret;
378275970Scy	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
379275970Scy	if (ret) {
380275970Scy	    hx509_certs_free(&iter->certs);
381275970Scy	    free(iter);
382275970Scy	    return ret;
383275970Scy	}
384275970Scy    } else {
385275970Scy	OSStatus ret;
386275970Scy
387275970Scy	ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
388275970Scy						    kSecCertificateItemClass,
389275970Scy						    NULL,
390275970Scy						    &iter->searchRef);
391275970Scy	if (ret) {
392275970Scy	    free(iter);
393275970Scy	    hx509_set_error_string(context, 0, ret,
394275970Scy				   "Failed to start search for attributes");
395275970Scy	    return ENOMEM;
396275970Scy	}
397275970Scy    }
398275970Scy
399275970Scy    *cursor = iter;
400275970Scy    return 0;
401275970Scy}
402275970Scy
403275970Scy/*
404275970Scy *
405275970Scy */
406275970Scy
407275970Scystatic int
408275970Scykeychain_iter(hx509_context context,
409275970Scy	      hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
410275970Scy{
411275970Scy    SecKeychainAttributeList *attrs = NULL;
412275970Scy    SecKeychainAttributeInfo attrInfo;
413275970Scy    UInt32 attrFormat[1] = { 0 };
414275970Scy    SecKeychainItemRef itemRef;
415275970Scy    SecItemAttr item[1];
416275970Scy    struct iter *iter = cursor;
417275970Scy    OSStatus ret;
418275970Scy    UInt32 len;
419275970Scy    void *ptr = NULL;
420275970Scy
421275970Scy    if (iter->certs)
422275970Scy	return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
423275970Scy
424275970Scy    *cert = NULL;
425275970Scy
426275970Scy    ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
427275970Scy    if (ret == errSecItemNotFound)
428275970Scy	return 0;
429275970Scy    else if (ret != 0)
430275970Scy	return EINVAL;
431275970Scy
432275970Scy    /*
433275970Scy     * Pick out certificate and matching "keyid"
434275970Scy     */
435275970Scy
436275970Scy    item[0] = kSecPublicKeyHashItemAttr;
437275970Scy
438275970Scy    attrInfo.count = 1;
439275970Scy    attrInfo.tag = item;
440275970Scy    attrInfo.format = attrFormat;
441275970Scy
442275970Scy    ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
443275970Scy					       &attrs, &len, &ptr);
444275970Scy    if (ret)
445275970Scy	return EINVAL;
446275970Scy
447275970Scy    ret = hx509_cert_init_data(context, ptr, len, cert);
448275970Scy    if (ret)
449275970Scy	goto out;
450275970Scy
451275970Scy    /*
452275970Scy     * Find related private key if there is one by looking at
453275970Scy     * kSecPublicKeyHashItemAttr == kSecKeyLabel
454275970Scy     */
455275970Scy    {
456275970Scy	SecKeychainSearchRef search;
457275970Scy	SecKeychainAttribute attrKeyid;
458275970Scy	SecKeychainAttributeList attrList;
459275970Scy
460275970Scy	attrKeyid.tag = kSecKeyLabel;
461275970Scy	attrKeyid.length = attrs->attr[0].length;
462275970Scy	attrKeyid.data = attrs->attr[0].data;
463275970Scy
464275970Scy	attrList.count = 1;
465275970Scy	attrList.attr = &attrKeyid;
466275970Scy
467275970Scy	ret = SecKeychainSearchCreateFromAttributes(NULL,
468275970Scy						    CSSM_DL_DB_RECORD_PRIVATE_KEY,
469275970Scy						    &attrList,
470275970Scy						    &search);
471275970Scy	if (ret) {
472275970Scy	    ret = 0;
473275970Scy	    goto out;
474275970Scy	}
475275970Scy
476275970Scy	ret = SecKeychainSearchCopyNext(search, &itemRef);
477275970Scy	CFRelease(search);
478275970Scy	if (ret == errSecItemNotFound) {
479275970Scy	    ret = 0;
480275970Scy	    goto out;
481275970Scy	} else if (ret) {
482275970Scy	    ret = EINVAL;
483275970Scy	    goto out;
484275970Scy	}
485275970Scy	set_private_key(context, itemRef, *cert);
486275970Scy    }
487275970Scy
488275970Scyout:
489275970Scy    SecKeychainItemFreeAttributesAndData(attrs, ptr);
490275970Scy
491275970Scy    return ret;
492275970Scy}
493275970Scy
494275970Scy/*
495275970Scy *
496275970Scy */
497275970Scy
498275970Scystatic int
499275970Scykeychain_iter_end(hx509_context context,
500275970Scy		  hx509_certs certs,
501275970Scy		  void *data,
502275970Scy		  void *cursor)
503275970Scy{
504275970Scy    struct iter *iter = cursor;
505275970Scy
506275970Scy    if (iter->certs) {
507275970Scy	int ret;
508275970Scy	ret = hx509_certs_end_seq(context, iter->certs, iter->cursor);
509275970Scy	hx509_certs_free(&iter->certs);
510275970Scy    } else {
511275970Scy	CFRelease(iter->searchRef);
512275970Scy    }
513275970Scy
514275970Scy    memset(iter, 0, sizeof(*iter));
515275970Scy    free(iter);
516275970Scy    return 0;
517275970Scy}
518275970Scy
519275970Scy/*
520275970Scy *
521275970Scy */
522275970Scy
523275970Scystruct hx509_keyset_ops keyset_keychain = {
524275970Scy    "KEYCHAIN",
525275970Scy    0,
526275970Scy    keychain_init,
527275970Scy    NULL,
528275970Scy    keychain_free,
529275970Scy    NULL,
530275970Scy    NULL,
531275970Scy    keychain_iter_start,
532275970Scy    keychain_iter,
533275970Scy    keychain_iter_end
534275970Scy};
535275970Scy
536275970Scy#endif /* HAVE_FRAMEWORK_SECURITY */
537275970Scy
538275970Scy/*
539275970Scy *
540275970Scy */
541275970Scy
542275970Scyvoid
543275970Scy_hx509_ks_keychain_register(hx509_context context)
544285612Sdelphij{
545285612Sdelphij#ifdef HAVE_FRAMEWORK_SECURITY
546285612Sdelphij    _hx509_ks_register(context, &keyset_keychain);
547285612Sdelphij#endif
548285612Sdelphij}
549285612Sdelphij