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