s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / third_party / 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
36 #ifdef HAVE_FRAMEWORK_SECURITY
37
38 #pragma clang diagnostic push
39 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
40
41 #include <Security/Security.h>
42
43 /* Missing function decls in pre Leopard */
44 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO
45 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *);
46 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG,
47                               int, const CSSM_ACCESS_CREDENTIALS **);
48 #define kSecCredentialTypeDefault 0
49 #define CSSM_SIZE uint32_t
50 #endif
51
52
53 static int
54 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item,
55              SecKeychainAttributeList **attrs)
56 {
57     SecKeychainAttributeInfo attrInfo;
58     UInt32 attrFormat = 0;
59     OSStatus ret;
60
61     *attrs = NULL;
62
63     attrInfo.count = 1;
64     attrInfo.tag = &item;
65     attrInfo.format = &attrFormat;
66
67     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
68                                                attrs, NULL, NULL);
69     if (ret)
70         return EINVAL;
71     return 0;
72 }
73
74
75 /*
76  *
77  */
78
79 struct kc_rsa {
80     SecKeychainItemRef item;
81     size_t keysize;
82 };
83
84
85 static int
86 kc_rsa_public_encrypt(int flen,
87                       const unsigned char *from,
88                       unsigned char *to,
89                       RSA *rsa,
90                       int padding)
91 {
92     return -1;
93 }
94
95 static int
96 kc_rsa_public_decrypt(int flen,
97                       const unsigned char *from,
98                       unsigned char *to,
99                       RSA *rsa,
100                       int padding)
101 {
102     return -1;
103 }
104
105
106 static int
107 kc_rsa_private_encrypt(int flen,
108                        const unsigned char *from,
109                        unsigned char *to,
110                        RSA *rsa,
111                        int padding)
112 {
113     struct kc_rsa *kc = RSA_get_app_data(rsa);
114
115     CSSM_RETURN cret;
116     OSStatus ret;
117     const CSSM_ACCESS_CREDENTIALS *creds;
118     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
119     CSSM_CSP_HANDLE cspHandle;
120     const CSSM_KEY *cssmKey;
121     CSSM_CC_HANDLE sigHandle = 0;
122     CSSM_DATA sig, in;
123     int fret = 0;
124
125     if (padding != RSA_PKCS1_PADDING)
126         return -1;
127
128     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
129     if(cret) abort();
130
131     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
132     if(cret) abort();
133
134     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
135                                kSecCredentialTypeDefault, &creds);
136     if(ret) abort();
137
138     ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
139                                           creds, cssmKey, &sigHandle);
140     if(ret) abort();
141
142     in.Data = (uint8 *)from;
143     in.Length = flen;
144
145     sig.Data = (uint8 *)to;
146     sig.Length = kc->keysize;
147
148     cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
149     if(cret) {
150         /* cssmErrorString(cret); */
151         fret = -1;
152     } else
153         fret = sig.Length;
154
155     if(sigHandle)
156         CSSM_DeleteContext(sigHandle);
157
158     return fret;
159 }
160
161 static int
162 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
163                        RSA * rsa, int padding)
164 {
165     struct kc_rsa *kc = RSA_get_app_data(rsa);
166
167     CSSM_RETURN cret;
168     OSStatus ret;
169     const CSSM_ACCESS_CREDENTIALS *creds;
170     SecKeyRef privKeyRef = (SecKeyRef)kc->item;
171     CSSM_CSP_HANDLE cspHandle;
172     const CSSM_KEY *cssmKey;
173     CSSM_CC_HANDLE handle = 0;
174     CSSM_DATA out, in, rem;
175     int fret = 0;
176     CSSM_SIZE outlen = 0;
177     char remdata[1024];
178
179     if (padding != RSA_PKCS1_PADDING)
180         return -1;
181
182     cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
183     if(cret) abort();
184
185     cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
186     if(cret) abort();
187
188     ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
189                                kSecCredentialTypeDefault, &creds);
190     if(ret) abort();
191
192
193     ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
194                                             CSSM_ALGID_RSA,
195                                             creds,
196                                             cssmKey,
197                                             CSSM_PADDING_PKCS1,
198                                             &handle);
199     if(ret) abort();
200
201     in.Data = (uint8 *)from;
202     in.Length = flen;
203
204     out.Data = (uint8 *)to;
205     out.Length = kc->keysize;
206
207     rem.Data = (uint8 *)remdata;
208     rem.Length = sizeof(remdata);
209
210     cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
211     if(cret) {
212         /* cssmErrorString(cret); */
213         fret = -1;
214     } else
215         fret = out.Length;
216
217     if(handle)
218         CSSM_DeleteContext(handle);
219
220     return fret;
221 }
222
223 static int
224 kc_rsa_init(RSA *rsa)
225 {
226     return 1;
227 }
228
229 static int
230 kc_rsa_finish(RSA *rsa)
231 {
232     struct kc_rsa *kc_rsa = RSA_get_app_data(rsa);
233     CFRelease(kc_rsa->item);
234     memset(kc_rsa, 0, sizeof(*kc_rsa));
235     free(kc_rsa);
236     return 1;
237 }
238
239 static const RSA_METHOD kc_rsa_pkcs1_method = {
240     "hx509 Keychain PKCS#1 RSA",
241     kc_rsa_public_encrypt,
242     kc_rsa_public_decrypt,
243     kc_rsa_private_encrypt,
244     kc_rsa_private_decrypt,
245     NULL,
246     NULL,
247     kc_rsa_init,
248     kc_rsa_finish,
249     0,
250     NULL,
251     NULL,
252     NULL,
253     NULL
254 };
255
256 static int
257 set_private_key(hx509_context context,
258                 SecKeychainItemRef itemRef,
259                 hx509_cert cert)
260 {
261     struct kc_rsa *kc;
262     hx509_private_key key;
263     RSA *rsa;
264     int ret;
265
266     ret = hx509_private_key_init(&key, NULL, NULL);
267     if (ret)
268         return ret;
269
270     kc = calloc(1, sizeof(*kc));
271     if (kc == NULL)
272         _hx509_abort("out of memory");
273
274     kc->item = itemRef;
275
276     rsa = RSA_new();
277     if (rsa == NULL)
278         _hx509_abort("out of memory");
279
280     /* Argh, fake modulus since OpenSSL API is on crack */
281     {
282         SecKeychainAttributeList *attrs = NULL;
283         uint32_t size;
284         void *data;
285
286         rsa->n = BN_new();
287         if (rsa->n == NULL) abort();
288
289         ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs);
290         if (ret) abort();
291
292         size = *(uint32_t *)attrs->attr[0].data;
293         SecKeychainItemFreeAttributesAndData(attrs, NULL);
294
295         kc->keysize = (size + 7) / 8;
296
297         data = malloc(kc->keysize);
298         memset(data, 0xe0, kc->keysize);
299         BN_bin2bn(data, kc->keysize, rsa->n);
300         free(data);
301     }
302     rsa->e = NULL;
303
304     RSA_set_method(rsa, &kc_rsa_pkcs1_method);
305     ret = RSA_set_app_data(rsa, kc);
306     if (ret != 1)
307         _hx509_abort("RSA_set_app_data");
308
309     hx509_private_key_assign_rsa(key, rsa);
310     _hx509_cert_assign_key(cert, key);
311
312     return 0;
313 }
314
315 /*
316  *
317  */
318
319 struct ks_keychain {
320     int anchors;
321     SecKeychainRef keychain;
322 };
323
324 static int
325 keychain_init(hx509_context context,
326               hx509_certs certs, void **data, int flags,
327               const char *residue, hx509_lock lock)
328 {
329     struct ks_keychain *ctx;
330
331     if (flags & HX509_CERTS_NO_PRIVATE_KEYS) {
332         hx509_set_error_string(context, 0, ENOTSUP,
333                                "KEYCHAIN store does not support not reading "
334                                "private keys");
335         return ENOTSUP;
336     }
337
338     ctx = calloc(1, sizeof(*ctx));
339     if (ctx == NULL) {
340         hx509_clear_error_string(context);
341         return ENOMEM;
342     }
343
344     if (residue) {
345         if (strcasecmp(residue, "system-anchors") == 0) {
346             ctx->anchors = 1;
347         } else if (strncasecmp(residue, "FILE:", 5) == 0) {
348             OSStatus ret;
349
350             ret = SecKeychainOpen(residue + 5, &ctx->keychain);
351             if (ret != noErr) {
352                 hx509_set_error_string(context, 0, ENOENT,
353                                        "Failed to open %s", residue);
354                 free(ctx);
355                 return ENOENT;
356             }
357         } else {
358             hx509_set_error_string(context, 0, ENOENT,
359                                    "Unknown subtype %s", residue);
360             free(ctx);
361             return ENOENT;
362         }
363     }
364
365     *data = ctx;
366     return 0;
367 }
368
369 /*
370  *
371  */
372
373 static int
374 keychain_free(hx509_certs certs, void *data)
375 {
376     struct ks_keychain *ctx = data;
377     if (ctx->keychain)
378         CFRelease(ctx->keychain);
379     memset(ctx, 0, sizeof(*ctx));
380     free(ctx);
381     return 0;
382 }
383
384 /*
385  *
386  */
387
388 struct iter {
389     hx509_certs certs;
390     void *cursor;
391     SecKeychainSearchRef searchRef;
392 };
393
394 static int
395 keychain_iter_start(hx509_context context,
396                     hx509_certs certs, void *data, void **cursor)
397 {
398     struct ks_keychain *ctx = data;
399     struct iter *iter;
400
401     iter = calloc(1, sizeof(*iter));
402     if (iter == NULL) {
403         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
404         return ENOMEM;
405     }
406
407     if (ctx->anchors) {
408         CFArrayRef anchors;
409         int ret;
410         int i;
411
412         ret = hx509_certs_init(context, "MEMORY:ks-file-create",
413                                0, NULL, &iter->certs);
414         if (ret) {
415             free(iter);
416             return ret;
417         }
418
419         ret = SecTrustCopyAnchorCertificates(&anchors);
420         if (ret != 0) {
421             hx509_certs_free(&iter->certs);
422             free(iter);
423             hx509_set_error_string(context, 0, ENOMEM,
424                                    "Can't get trust anchors from Keychain");
425             return ENOMEM;
426         }
427         for (i = 0; i < CFArrayGetCount(anchors); i++) {
428             SecCertificateRef cr;
429             hx509_cert cert;
430             CSSM_DATA cssm;
431
432             cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);
433
434             SecCertificateGetData(cr, &cssm);
435
436             cert = hx509_cert_init_data(context, cssm.Data, cssm.Length, NULL);
437             if (cert == NULL)
438                 continue;
439
440             ret = hx509_certs_add(context, iter->certs, cert);
441             hx509_cert_free(cert);
442         }
443         CFRelease(anchors);
444     }
445
446     if (iter->certs) {
447         int ret;
448         ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
449         if (ret) {
450             hx509_certs_free(&iter->certs);
451             free(iter);
452             return ret;
453         }
454     } else {
455         OSStatus ret;
456
457         ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
458                                                     kSecCertificateItemClass,
459                                                     NULL,
460                                                     &iter->searchRef);
461         if (ret) {
462             free(iter);
463             hx509_set_error_string(context, 0, ret,
464                                    "Failed to start search for attributes");
465             return ENOMEM;
466         }
467     }
468
469     *cursor = iter;
470     return 0;
471 }
472
473 /*
474  *
475  */
476
477 static int
478 keychain_iter(hx509_context context,
479               hx509_certs certs, void *data, void *cursor, hx509_cert *cert)
480 {
481     SecKeychainAttributeList *attrs = NULL;
482     SecKeychainAttributeInfo attrInfo;
483     UInt32 attrFormat[1] = { 0 };
484     SecKeychainItemRef itemRef;
485     SecItemAttr item[1];
486     heim_error_t error = NULL;
487     struct iter *iter = cursor;
488     OSStatus ret;
489     UInt32 len;
490     void *ptr = NULL;
491
492     if (iter->certs)
493         return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert);
494
495     *cert = NULL;
496
497     ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef);
498     if (ret == errSecItemNotFound)
499         return 0;
500     else if (ret != 0)
501         return EINVAL;
502
503     /*
504      * Pick out certificate and matching "keyid"
505      */
506
507     item[0] = kSecPublicKeyHashItemAttr;
508
509     attrInfo.count = 1;
510     attrInfo.tag = item;
511     attrInfo.format = attrFormat;
512
513     ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL,
514                                                &attrs, &len, &ptr);
515     if (ret)
516         return EINVAL;
517
518     *cert = hx509_cert_init_data(context, ptr, len, &error);
519     if (*cert == NULL) {
520         ret = heim_error_get_code(error);
521         heim_release(error);
522         goto out;
523     }
524
525     /*
526      * Find related private key if there is one by looking at
527      * kSecPublicKeyHashItemAttr == kSecKeyLabel
528      */
529     {
530         SecKeychainSearchRef search;
531         SecKeychainAttribute attrKeyid;
532         SecKeychainAttributeList attrList;
533
534         attrKeyid.tag = kSecKeyLabel;
535         attrKeyid.length = attrs->attr[0].length;
536         attrKeyid.data = attrs->attr[0].data;
537
538         attrList.count = 1;
539         attrList.attr = &attrKeyid;
540
541         ret = SecKeychainSearchCreateFromAttributes(NULL,
542                                                     CSSM_DL_DB_RECORD_PRIVATE_KEY,
543                                                     &attrList,
544                                                     &search);
545         if (ret) {
546             ret = 0;
547             goto out;
548         }
549
550         ret = SecKeychainSearchCopyNext(search, &itemRef);
551         CFRelease(search);
552         if (ret == errSecItemNotFound) {
553             ret = 0;
554             goto out;
555         } else if (ret) {
556             ret = EINVAL;
557             goto out;
558         }
559         set_private_key(context, itemRef, *cert);
560     }
561
562 out:
563     SecKeychainItemFreeAttributesAndData(attrs, ptr);
564
565     return ret;
566 }
567
568 /*
569  *
570  */
571
572 static int
573 keychain_iter_end(hx509_context context,
574                   hx509_certs certs,
575                   void *data,
576                   void *cursor)
577 {
578     struct iter *iter = cursor;
579
580     if (iter->certs) {
581         hx509_certs_end_seq(context, iter->certs, iter->cursor);
582         hx509_certs_free(&iter->certs);
583     } else {
584         CFRelease(iter->searchRef);
585     }
586
587     memset(iter, 0, sizeof(*iter));
588     free(iter);
589     return 0;
590 }
591
592 /*
593  *
594  */
595
596 struct hx509_keyset_ops keyset_keychain = {
597     "KEYCHAIN",
598     0,
599     keychain_init,
600     NULL,
601     keychain_free,
602     NULL,
603     NULL,
604     keychain_iter_start,
605     keychain_iter,
606     keychain_iter_end,
607     NULL,
608     NULL,
609     NULL,
610     NULL
611 };
612
613 #pragma clang diagnostic pop
614
615 #endif /* HAVE_FRAMEWORK_SECURITY */
616
617 /*
618  *
619  */
620
621 HX509_LIB_FUNCTION void HX509_LIB_CALL
622 _hx509_ks_keychain_register(hx509_context context)
623 {
624 #ifdef HAVE_FRAMEWORK_SECURITY
625     _hx509_ks_register(context, &keyset_keychain);
626 #endif
627 }