2 * Copyright (c) 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
36 #ifdef HAVE_FRAMEWORK_SECURITY
38 #pragma clang diagnostic push
39 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
41 #include <Security/Security.h>
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
54 getAttribute(SecKeychainItemRef itemRef
, SecItemAttr item
,
55 SecKeychainAttributeList
**attrs
)
57 SecKeychainAttributeInfo attrInfo
;
58 UInt32 attrFormat
= 0;
65 attrInfo
.format
= &attrFormat
;
67 ret
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
,
80 SecKeychainItemRef item
;
86 kc_rsa_public_encrypt(int flen
,
87 const unsigned char *from
,
96 kc_rsa_public_decrypt(int flen
,
97 const unsigned char *from
,
107 kc_rsa_private_encrypt(int flen
,
108 const unsigned char *from
,
113 struct kc_rsa
*kc
= RSA_get_app_data(rsa
);
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;
125 if (padding
!= RSA_PKCS1_PADDING
)
128 cret
= SecKeyGetCSSMKey(privKeyRef
, &cssmKey
);
131 cret
= SecKeyGetCSPHandle(privKeyRef
, &cspHandle
);
134 ret
= SecKeyGetCredentials(privKeyRef
, CSSM_ACL_AUTHORIZATION_SIGN
,
135 kSecCredentialTypeDefault
, &creds
);
138 ret
= CSSM_CSP_CreateSignatureContext(cspHandle
, CSSM_ALGID_RSA
,
139 creds
, cssmKey
, &sigHandle
);
142 in
.Data
= (uint8
*)from
;
145 sig
.Data
= (uint8
*)to
;
146 sig
.Length
= kc
->keysize
;
148 cret
= CSSM_SignData(sigHandle
, &in
, 1, CSSM_ALGID_NONE
, &sig
);
150 /* cssmErrorString(cret); */
156 CSSM_DeleteContext(sigHandle
);
162 kc_rsa_private_decrypt(int flen
, const unsigned char *from
, unsigned char *to
,
163 RSA
* rsa
, int padding
)
165 struct kc_rsa
*kc
= RSA_get_app_data(rsa
);
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
;
176 CSSM_SIZE outlen
= 0;
179 if (padding
!= RSA_PKCS1_PADDING
)
182 cret
= SecKeyGetCSSMKey(privKeyRef
, &cssmKey
);
185 cret
= SecKeyGetCSPHandle(privKeyRef
, &cspHandle
);
188 ret
= SecKeyGetCredentials(privKeyRef
, CSSM_ACL_AUTHORIZATION_DECRYPT
,
189 kSecCredentialTypeDefault
, &creds
);
193 ret
= CSSM_CSP_CreateAsymmetricContext (cspHandle
,
201 in
.Data
= (uint8
*)from
;
204 out
.Data
= (uint8
*)to
;
205 out
.Length
= kc
->keysize
;
207 rem
.Data
= (uint8
*)remdata
;
208 rem
.Length
= sizeof(remdata
);
210 cret
= CSSM_DecryptData(handle
, &in
, 1, &out
, 1, &outlen
, &rem
);
212 /* cssmErrorString(cret); */
218 CSSM_DeleteContext(handle
);
224 kc_rsa_init(RSA
*rsa
)
230 kc_rsa_finish(RSA
*rsa
)
232 struct kc_rsa
*kc_rsa
= RSA_get_app_data(rsa
);
233 CFRelease(kc_rsa
->item
);
234 memset(kc_rsa
, 0, sizeof(*kc_rsa
));
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
,
257 set_private_key(hx509_context context
,
258 SecKeychainItemRef itemRef
,
262 hx509_private_key key
;
266 ret
= hx509_private_key_init(&key
, NULL
, NULL
);
270 kc
= calloc(1, sizeof(*kc
));
272 _hx509_abort("out of memory");
278 _hx509_abort("out of memory");
280 /* Argh, fake modulus since OpenSSL API is on crack */
282 SecKeychainAttributeList
*attrs
= NULL
;
287 if (rsa
->n
== NULL
) abort();
289 ret
= getAttribute(itemRef
, kSecKeyKeySizeInBits
, &attrs
);
292 size
= *(uint32_t *)attrs
->attr
[0].data
;
293 SecKeychainItemFreeAttributesAndData(attrs
, NULL
);
295 kc
->keysize
= (size
+ 7) / 8;
297 data
= malloc(kc
->keysize
);
298 memset(data
, 0xe0, kc
->keysize
);
299 BN_bin2bn(data
, kc
->keysize
, rsa
->n
);
304 RSA_set_method(rsa
, &kc_rsa_pkcs1_method
);
305 ret
= RSA_set_app_data(rsa
, kc
);
307 _hx509_abort("RSA_set_app_data");
309 hx509_private_key_assign_rsa(key
, rsa
);
310 _hx509_cert_assign_key(cert
, key
);
321 SecKeychainRef keychain
;
325 keychain_init(hx509_context context
,
326 hx509_certs certs
, void **data
, int flags
,
327 const char *residue
, hx509_lock lock
)
329 struct ks_keychain
*ctx
;
331 if (flags
& HX509_CERTS_NO_PRIVATE_KEYS
) {
332 hx509_set_error_string(context
, 0, ENOTSUP
,
333 "KEYCHAIN store does not support not reading "
338 ctx
= calloc(1, sizeof(*ctx
));
340 hx509_clear_error_string(context
);
345 if (strcasecmp(residue
, "system-anchors") == 0) {
347 } else if (strncasecmp(residue
, "FILE:", 5) == 0) {
350 ret
= SecKeychainOpen(residue
+ 5, &ctx
->keychain
);
352 hx509_set_error_string(context
, 0, ENOENT
,
353 "Failed to open %s", residue
);
358 hx509_set_error_string(context
, 0, ENOENT
,
359 "Unknown subtype %s", residue
);
374 keychain_free(hx509_certs certs
, void *data
)
376 struct ks_keychain
*ctx
= data
;
378 CFRelease(ctx
->keychain
);
379 memset(ctx
, 0, sizeof(*ctx
));
391 SecKeychainSearchRef searchRef
;
395 keychain_iter_start(hx509_context context
,
396 hx509_certs certs
, void *data
, void **cursor
)
398 struct ks_keychain
*ctx
= data
;
401 iter
= calloc(1, sizeof(*iter
));
403 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
412 ret
= hx509_certs_init(context
, "MEMORY:ks-file-create",
413 0, NULL
, &iter
->certs
);
419 ret
= SecTrustCopyAnchorCertificates(&anchors
);
421 hx509_certs_free(&iter
->certs
);
423 hx509_set_error_string(context
, 0, ENOMEM
,
424 "Can't get trust anchors from Keychain");
427 for (i
= 0; i
< CFArrayGetCount(anchors
); i
++) {
428 SecCertificateRef cr
;
432 cr
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, i
);
434 SecCertificateGetData(cr
, &cssm
);
436 cert
= hx509_cert_init_data(context
, cssm
.Data
, cssm
.Length
, NULL
);
440 ret
= hx509_certs_add(context
, iter
->certs
, cert
);
441 hx509_cert_free(cert
);
448 ret
= hx509_certs_start_seq(context
, iter
->certs
, &iter
->cursor
);
450 hx509_certs_free(&iter
->certs
);
457 ret
= SecKeychainSearchCreateFromAttributes(ctx
->keychain
,
458 kSecCertificateItemClass
,
463 hx509_set_error_string(context
, 0, ret
,
464 "Failed to start search for attributes");
478 keychain_iter(hx509_context context
,
479 hx509_certs certs
, void *data
, void *cursor
, hx509_cert
*cert
)
481 SecKeychainAttributeList
*attrs
= NULL
;
482 SecKeychainAttributeInfo attrInfo
;
483 UInt32 attrFormat
[1] = { 0 };
484 SecKeychainItemRef itemRef
;
486 heim_error_t error
= NULL
;
487 struct iter
*iter
= cursor
;
493 return hx509_certs_next_cert(context
, iter
->certs
, iter
->cursor
, cert
);
497 ret
= SecKeychainSearchCopyNext(iter
->searchRef
, &itemRef
);
498 if (ret
== errSecItemNotFound
)
504 * Pick out certificate and matching "keyid"
507 item
[0] = kSecPublicKeyHashItemAttr
;
511 attrInfo
.format
= attrFormat
;
513 ret
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
,
518 *cert
= hx509_cert_init_data(context
, ptr
, len
, &error
);
520 ret
= heim_error_get_code(error
);
526 * Find related private key if there is one by looking at
527 * kSecPublicKeyHashItemAttr == kSecKeyLabel
530 SecKeychainSearchRef search
;
531 SecKeychainAttribute attrKeyid
;
532 SecKeychainAttributeList attrList
;
534 attrKeyid
.tag
= kSecKeyLabel
;
535 attrKeyid
.length
= attrs
->attr
[0].length
;
536 attrKeyid
.data
= attrs
->attr
[0].data
;
539 attrList
.attr
= &attrKeyid
;
541 ret
= SecKeychainSearchCreateFromAttributes(NULL
,
542 CSSM_DL_DB_RECORD_PRIVATE_KEY
,
550 ret
= SecKeychainSearchCopyNext(search
, &itemRef
);
552 if (ret
== errSecItemNotFound
) {
559 set_private_key(context
, itemRef
, *cert
);
563 SecKeychainItemFreeAttributesAndData(attrs
, ptr
);
573 keychain_iter_end(hx509_context context
,
578 struct iter
*iter
= cursor
;
581 hx509_certs_end_seq(context
, iter
->certs
, iter
->cursor
);
582 hx509_certs_free(&iter
->certs
);
584 CFRelease(iter
->searchRef
);
587 memset(iter
, 0, sizeof(*iter
));
596 struct hx509_keyset_ops keyset_keychain
= {
613 #pragma clang diagnostic pop
615 #endif /* HAVE_FRAMEWORK_SECURITY */
621 HX509_LIB_FUNCTION
void HX509_LIB_CALL
622 _hx509_ks_keychain_register(hx509_context context
)
624 #ifdef HAVE_FRAMEWORK_SECURITY
625 _hx509_ks_register(context
, &keyset_keychain
);