keychain: use SearchCopyNext keychain enumeration for System certs as well
[strongswan.git] / src / libstrongswan / plugins / keychain / keychain_creds.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "keychain_creds.h"
17
18 #include <utils/debug.h>
19 #include <credentials/sets/mem_cred.h>
20
21 #include <Security/Security.h>
22
23 /**
24 * System Roots keychain
25 */
26 #define SYSTEM_ROOTS "/System/Library/Keychains/SystemRootCertificates.keychain"
27
28 /**
29 * System keychain
30 */
31 #define SYSTEM "/Library/Keychains/System.keychain"
32
33 typedef struct private_keychain_creds_t private_keychain_creds_t;
34
35 /**
36 * Private data of an keychain_creds_t object.
37 */
38 struct private_keychain_creds_t {
39
40 /**
41 * Public keychain_creds_t interface.
42 */
43 keychain_creds_t public;
44
45 /**
46 * Active in-memory credential set
47 */
48 mem_cred_t *set;
49
50 /**
51 * System roots credential set
52 */
53 mem_cred_t *roots;
54 };
55
56 /**
57 * Load a credential sets with certificates from a keychain path
58 */
59 static mem_cred_t* load_certs(private_keychain_creds_t *this, char *path)
60 {
61 SecKeychainRef keychain;
62 SecKeychainSearchRef search;
63 SecKeychainItemRef item;
64 mem_cred_t *set;
65 OSStatus status;
66
67 set = mem_cred_create();
68
69 DBG1(DBG_CFG, "loading certificates from %s:", path);
70 status = SecKeychainOpen(path, &keychain);
71 if (status == errSecSuccess)
72 {
73 status = SecKeychainSearchCreateFromAttributes(keychain,
74 kSecCertificateItemClass, NULL, &search);
75 if (status == errSecSuccess)
76 {
77 while (SecKeychainSearchCopyNext(search, &item) == errSecSuccess)
78 {
79 certificate_t *cert;
80 UInt32 len;
81 void *data;
82
83 if (SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL,
84 &len, &data) == errSecSuccess)
85 {
86 cert = lib->creds->create(lib->creds,
87 CRED_CERTIFICATE, CERT_X509,
88 BUILD_BLOB_ASN1_DER, chunk_create(data, len),
89 BUILD_END);
90 if (cert)
91 {
92 DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert));
93 set->add_cert(set, TRUE, cert);
94 }
95 SecKeychainItemFreeAttributesAndData(NULL, data);
96 }
97 CFRelease(item);
98 }
99 CFRelease(search);
100 }
101 CFRelease(keychain);
102 }
103 return set;
104 }
105
106 METHOD(keychain_creds_t, destroy, void,
107 private_keychain_creds_t *this)
108 {
109 lib->credmgr->remove_set(lib->credmgr, &this->set->set);
110 lib->credmgr->remove_set(lib->credmgr, &this->roots->set);
111 this->set->destroy(this->set);
112 this->roots->destroy(this->roots);
113 free(this);
114 }
115
116 /**
117 * See header
118 */
119 keychain_creds_t *keychain_creds_create()
120 {
121 private_keychain_creds_t *this;
122
123 INIT(this,
124 .public = {
125 .destroy = _destroy,
126 },
127 );
128
129 this->roots = load_certs(this, SYSTEM_ROOTS);
130 this->set = load_certs(this, SYSTEM);
131
132 lib->credmgr->add_set(lib->credmgr, &this->roots->set);
133 lib->credmgr->add_set(lib->credmgr, &this->set->set);
134
135 return &this->public;
136 }