~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/hx509/ks_keychain.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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