r23456: Update Samba4 to current lorikeet-heimdal.
[samba.git] / source4 / heimdal / lib / hx509 / ks_keychain.c
1 /*
2  * Copyright (c) 2007 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
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. 
16  *
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. 
20  *
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 
31  * SUCH DAMAGE. 
32  */
33
34 #include "hx_locl.h"
35 RCSID("$Id: ks_keychain.c 20945 2007-06-06 22:17:17Z lha $");
36
37 #ifdef HAVE_FRAMEWORK_SECURITY
38
39 #include <Security/Security.h>
40
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
46
47
48 static int
49 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
50              SecKeychainAttributeList **attrs)
51 {            
52     SecKeychainAttributeInfo attrInfo;
53     uint32 attrFormat = 0;
54     OSStatus ret;
55
56     *attrs = NULL;
57
58     attrInfo.count = 1;
59     attrInfo.tag = &item;
60     attrInfo.format = &attrFormat;
61   
62     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
63                                                attrs, NULL, NULL);
64     if (ret)
65         return EINVAL;
66     return 0;
67 }
68
69
70 /*
71  *
72  */
73
74 struct kc_rsa {
75     SecKeychainItemRef item;
76     size_t keysize;
77 };
78
79
80 static int
81 kc_rsa_public_encrypt(int flen,
82                       const unsigned char *from,
83                       unsigned char *to,
84                       RSA *rsa,
85                       int padding)
86 {
87     return -1;
88 }
89
90 static int
91 kc_rsa_public_decrypt(int flen,
92                       const unsigned char *from,
93                       unsigned char *to,
94                       RSA *rsa,
95                       int padding)
96 {
97     return -1;
98 }
99
100
101 static int
102 kc_rsa_private_encrypt(int flen, 
103                        const unsigned char *from,
104                        unsigned char *to,
105                        RSA *rsa,
106                        int padding)
107 {
108     struct kc_rsa *kc = RSA_get_app_data(rsa);
109
110     CSSM_RETURN cret;
111     OSStatus ret;
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;
117     CSSM_DATA sig, in;
118     int fret = 0;
119
120
121     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
122     if(cret) abort();
123
124     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
125     if(cret) abort();
126
127     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
128                                kSecCredentialTypeDefault, &creds);
129     if(ret) abort();
130
131     ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
132                                           creds, cssmKey, &sigHandle);
133     if(ret) abort();
134
135     in.Data = (uint8 *)from;
136     in.Length = flen;
137         
138     sig.Data = (uint8 *)to;
139     sig.Length = kc->keysize;
140         
141     cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
142     if(cret) {
143         /* cssmErrorString(cret); */
144         fret = -1;
145     } else
146         fret = sig.Length;
147
148     if(sigHandle)
149         CSSM_DeleteContext(sigHandle);
150
151     return fret;
152 }
153
154 static int
155 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
156                        RSA * rsa, int padding)
157 {
158     return -1;
159 }
160
161 static int 
162 kc_rsa_init(RSA *rsa)
163 {
164     return 1;
165 }
166
167 static int
168 kc_rsa_finish(RSA *rsa)
169 {
170     struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
171     CFRelease(kc_rsa->item);
172     memset(kc_rsa, 0, sizeof(*kc_rsa));
173     free(kc_rsa);
174     return 1;
175 }
176
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,
183     NULL,
184     NULL,
185     kc_rsa_init,
186     kc_rsa_finish,
187     0,
188     NULL,
189     NULL,
190     NULL
191 };
192
193 static int
194 set_private_key(hx509_context context,
195                 SecKeychainItemRef itemRef,
196                 hx509_cert cert)
197 {
198     struct kc_rsa *kc;
199     hx509_private_key key;
200     RSA *rsa;
201     int ret;
202
203     ret = _hx509_private_key_init(&key, NULL, NULL);
204     if (ret)
205         return ret;
206
207     kc = calloc(1, sizeof(*kc));
208     if (kc == NULL)
209         _hx509_abort("out of memory");
210
211     kc->item = itemRef;
212
213     rsa = RSA_new();
214     if (rsa == NULL)
215         _hx509_abort("out of memory");
216
217     /* Argh, fake modulus since OpenSSL API is on crack */
218     {
219         SecKeychainAttributeList *attrs = NULL;
220         uint32_t size;
221         void *data;
222
223         rsa->n = BN_new();
224         if (rsa->n == NULL) abort();
225
226         ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
227         if (ret) abort();
228
229         size = *(uint32_t *)attrs->attr[0].data;
230         SecKeychainItemFreeAttributesAndData(attrs, NULL);
231
232         kc->keysize = (size + 7) / 8;
233
234         data = malloc(kc->keysize);
235         memset(data, 0xe0, kc->keysize);
236         BN_bin2bn(data, kc->keysize, rsa->n);
237         free(data);
238     }
239     rsa->e = NULL;
240
241     RSA_set_method(rsa, &kc_rsa_pkcs1_method);
242     ret = RSA_set_app_data(rsa, kc);
243     if (ret != 1)
244         _hx509_abort("RSA_set_app_data");
245
246     _hx509_private_key_assign_rsa(key, rsa);
247     _hx509_cert_assign_key(cert, key);
248
249     return 0;
250 }
251
252 /*
253  *
254  */
255
256 struct ks_keychain {
257     SecKeychainRef keychain;
258 };
259
260 static int
261 keychain_init(hx509_context context,
262               hx509_certs certs, void **data, int flags,
263               const char *residue, hx509_lock lock)
264 {
265     struct ks_keychain *ctx;
266     OSStatus ret;
267
268     ctx = calloc(1, sizeof(*ctx));
269     if (ctx == NULL) {
270         hx509_clear_error_string(context);
271         return ENOMEM;
272     }
273
274     if (residue) {
275         if (strcasecmp(residue, "system") == 0)
276             residue = "/System/Library/Keychains/X509Anchors";
277
278         ret = SecKeychainOpen(residue, &ctx->keychain);
279         if (ret != noErr) {
280             hx509_set_error_string(context, 0, ENOENT, 
281                                    "Failed to open %s", residue);
282             return ENOENT;
283         }
284     }
285
286     *data = ctx;
287     return 0;
288 }
289
290 /*
291  *
292  */
293
294 static int
295 keychain_free(hx509_certs certs, void *data)
296 {
297     struct ks_keychain *ctx = data;
298     if (ctx->keychain)
299         CFRelease(ctx->keychain);
300     memset(ctx, 0, sizeof(*ctx));
301     free(ctx);
302     return 0;
303 }
304
305 /*
306  *
307  */
308
309 struct iter {
310     SecKeychainSearchRef searchRef;
311 };
312
313 static int 
314 keychain_iter_start(hx509_context context,
315                     hx509_certs certs, void *data, void **cursor)
316 {
317     struct ks_keychain *ctx = data;
318     struct iter *iter;
319     OSStatus ret;
320
321     iter = calloc(1, sizeof(*iter));
322     if (iter == NULL) {
323         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
324         return ENOMEM;
325     }
326
327     ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
328                                                 kSecCertificateItemClass,
329                                                 NULL,
330                                                 &iter->searchRef);
331     if (ret) {
332         free(iter);
333         hx509_set_error_string(context, 0, ret, 
334                                "Failed to start search for attributes");
335         return ENOMEM;
336     }
337
338     *cursor = iter;
339     return 0;
340 }
341
342 /*
343  *
344  */
345
346 static int
347 keychain_iter(hx509_context context,
348               hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
349 {
350     SecKeychainAttributeList *attrs = NULL;
351     SecKeychainAttributeInfo attrInfo;
352     uint32 attrFormat = 0;
353     SecKeychainItemRef itemRef;
354     SecItemAttr item;
355     struct iter *iter = cursor;
356     Certificate t;
357     OSStatus ret;
358     UInt32 len;
359     void *ptr = NULL;
360     size_t size;
361
362     *cert = NULL;
363
364     ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
365     if (ret == errSecItemNotFound)
366         return 0;
367     else if (ret != 0)
368         return EINVAL;
369         
370     /*
371      * Pick out certificate and matching "keyid"
372      */
373
374     item = kSecPublicKeyHashItemAttr;
375
376     attrInfo.count = 1;
377     attrInfo.tag = &item;
378     attrInfo.format = &attrFormat;
379   
380     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
381                                                &attrs, &len, &ptr);
382     if (ret)
383         return EINVAL;
384     
385     ret = decode_Certificate(ptr, len, &t, &size);
386     CFRelease(itemRef);
387     if (ret) {
388         hx509_set_error_string(context, 0, ret, "Failed to parse certificate");
389         goto out;
390     }
391
392     ret = hx509_cert_init(context, &t, cert);
393     free_Certificate(&t);
394     if (ret)
395         goto out;
396
397     /* 
398      * Find related private key if there is one by looking at
399      * kSecPublicKeyHashItemAttr == kSecKeyLabel
400      */
401     {
402         SecKeychainSearchRef search;
403         SecKeychainAttribute attrKeyid;
404         SecKeychainAttributeList attrList;
405
406         attrKeyid.tag = kSecKeyLabel;
407         attrKeyid.length = attrs->attr[0].length;
408         attrKeyid.data = attrs->attr[0].data;
409         
410         attrList.count = 1;
411         attrList.attr = &attrKeyid;
412
413         ret = SecKeychainSearchCreateFromAttributes(NULL,
414                                                     CSSM_DL_DB_RECORD_PRIVATE_KEY,
415                                                     &attrList,
416                                                     &search);
417         if (ret) {
418             ret = 0;
419             goto out;
420         }
421
422         ret = SecKeychainSearchCopyNext(search, &itemRef);
423         CFRelease(search);
424         if (ret == errSecItemNotFound) {
425             ret = 0;
426             goto out;
427         } else if (ret) {
428             ret = EINVAL;
429             goto out;
430         }
431         set_private_key(context, itemRef, *cert);
432     }
433
434 out:
435     SecKeychainItemFreeAttributesAndData(attrs, ptr);
436
437     return ret;
438 }
439
440 /*
441  *
442  */
443
444 static int
445 keychain_iter_end(hx509_context context,
446                   hx509_certs certs,
447                   void *data,
448                   void *cursor)
449 {
450     struct iter *iter = cursor;
451
452     CFRelease(iter->searchRef);
453     memset(iter, 0, sizeof(*iter));
454     free(iter);
455     return 0;
456 }
457
458 /*
459  *
460  */
461
462 struct hx509_keyset_ops keyset_keychain = {
463     "KEYCHAIN",
464     0,
465     keychain_init,
466     NULL,
467     keychain_free,
468     NULL,
469     NULL,
470     keychain_iter_start,
471     keychain_iter,
472     keychain_iter_end
473 };
474
475 #endif /* HAVE_FRAMEWORK_SECURITY */
476
477 /*
478  *
479  */
480
481 void
482 _hx509_ks_keychain_register(hx509_context context)
483 {
484 #ifdef HAVE_FRAMEWORK_SECURITY
485     _hx509_ks_register(context, &keyset_keychain);
486 #endif
487 }