]> git.saurik.com Git - apple/security.git/blob - SecurityTool/sharedTool/pkcs12_util.c
Security-59754.80.3.tar.gz
[apple/security.git] / SecurityTool / sharedTool / pkcs12_util.c
1 /*
2 * Copyright (c) 2008-2010,2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <TargetConditionals.h>
25 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <stdint.h>
34 #include <stdbool.h>
35 #include <errno.h>
36 #include <string.h>
37
38 #include <CoreFoundation/CFData.h>
39 #include <CoreFoundation/CFDictionary.h>
40 #include <CoreFoundation/CFNumber.h>
41 #include <CoreFoundation/CFString.h>
42 #include <Security/SecImportExport.h>
43 #include <Security/SecItem.h>
44 #include <Security/SecCertificate.h>
45 #include <Security/SecIdentity.h>
46 #include <Security/SecTrust.h>
47 #include <Security/SecInternal.h>
48 #include <utilities/array_size.h>
49
50 #include "SecurityCommands.h"
51 #include "SecurityTool/sharedTool/print_cert.h"
52
53 static void *
54 read_file(const char * filename, size_t * data_length)
55 {
56 void * data = NULL;
57 int len = 0;
58 int fd = -1;
59 struct stat sb;
60
61 *data_length = 0;
62 if (stat(filename, &sb) < 0)
63 goto done;
64 if (sb.st_size > INT32_MAX)
65 goto done;
66 len = (uint32_t)sb.st_size;
67 if (len == 0)
68 goto done;
69
70 data = malloc(len);
71 if (data == NULL)
72 goto done;
73
74 fd = open(filename, O_RDONLY);
75 if (fd < 0)
76 goto done;
77
78 if (read(fd, data, len) != len) {
79 goto done;
80 }
81 done:
82 if (fd >= 0)
83 close(fd);
84 if (data) {
85 *data_length = len;
86 }
87 return (data);
88 }
89
90 static OSStatus
91 add_cert_item(SecCertificateRef cert)
92 {
93 CFDictionaryRef dict;
94 OSStatus status;
95
96 dict = CFDictionaryCreate(NULL,
97 (const void * *)&kSecValueRef,
98 (const void * *)&cert, 1,
99 &kCFTypeDictionaryKeyCallBacks,
100 &kCFTypeDictionaryValueCallBacks);
101 status = SecItemAdd(dict, NULL);
102 CFReleaseNull(dict);
103 return (status);
104 }
105
106 static OSStatus
107 remove_cert_item(SecCertificateRef cert)
108 {
109 CFDictionaryRef dict;
110 OSStatus status;
111
112 dict = CFDictionaryCreate(NULL,
113 (const void * *)&kSecValueRef,
114 (const void * *)&cert, 1,
115 &kCFTypeDictionaryKeyCallBacks,
116 &kCFTypeDictionaryValueCallBacks);
117 status = SecItemDelete(dict);
118 CFReleaseNull(dict);
119 if (status == errSecItemNotFound)
120 status = errSecSuccess; /* already gone, no problem */
121 return (status);
122 }
123
124 static CFArrayRef
125 PKCS12FileCreateArray(const char * filename, const char * password)
126 {
127 void * file_data = NULL;
128 size_t file_data_length;
129 CFArrayRef items = NULL;
130 CFDictionaryRef options = NULL;
131 CFDataRef pkcs12_data = NULL;
132 CFStringRef password_cf = NULL;
133
134 file_data = read_file(filename, &file_data_length);
135 if (file_data == NULL) {
136 int this_error = errno;
137
138 fprintf(stderr, "failed to read file '%s', %s\n",
139 filename, strerror(this_error));
140 goto done;
141 }
142 pkcs12_data = CFDataCreate(NULL, file_data, file_data_length);
143 password_cf
144 = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8);
145
146 options = CFDictionaryCreate(NULL,
147 (const void * *)&kSecImportExportPassphrase,
148 (const void * *)&password_cf, 1,
149 &kCFTypeDictionaryKeyCallBacks,
150 &kCFTypeDictionaryValueCallBacks);
151 if (SecPKCS12Import(pkcs12_data, options, &items) != 0) {
152 fprintf(stderr, "failed to import PKCS12 '%s'\n",
153 filename);
154 }
155 done:
156 if (file_data != NULL) {
157 free(file_data);
158 }
159 CFReleaseNull(pkcs12_data);
160 CFReleaseNull(password_cf);
161 CFReleaseNull(options);
162 return (items);
163 }
164
165 static void
166 find_identity_using_handle(CFTypeRef identity_handle)
167 {
168 CFDictionaryRef dict;
169 CFTypeRef identity_ref;
170 const void * keys[] = { kSecClass,
171 kSecReturnRef,
172 kSecValuePersistentRef };
173 const void * values[] = { kSecClassIdentity,
174 kCFBooleanTrue,
175 identity_handle };
176 OSStatus status;
177
178 /* find the identity using the persistent handle */
179 dict = CFDictionaryCreate(NULL, keys, values,
180 (array_size(keys)),
181 &kCFTypeDictionaryKeyCallBacks,
182 &kCFTypeDictionaryValueCallBacks);
183 status = SecItemCopyMatching(dict, &identity_ref);
184 CFReleaseNull(dict);
185 if (status != errSecSuccess) {
186 fprintf(stderr, "SecItemCopyMatching() failed %d\n",
187 (int)status);
188 }
189 else {
190 printf("Found identity:\n");
191 fflush(stdout);
192 fflush(stderr);
193 CFShow(identity_ref);
194 CFReleaseNull(identity_ref);
195 }
196 return;
197 }
198
199 static bool
200 PKCS12ArrayAddSecItems(CFArrayRef items, bool verbose)
201 {
202 CFIndex count;
203 CFIndex i;
204 bool success = TRUE;
205
206 count = CFArrayGetCount(items);
207 for (i = 0; i < count; i++) {
208 SecTrustRef trust_ref;
209 SecIdentityRef identity;
210 CFDictionaryRef item_dict = CFArrayGetValueAtIndex(items, 0);
211 OSStatus status;
212
213 /* add identity */
214 identity = (SecIdentityRef)CFDictionaryGetValue(item_dict, kSecImportItemIdentity);
215 if (identity != NULL) {
216 if (verbose) {
217 SecCertificateRef cert = NULL;
218 SecIdentityCopyCertificate(identity, &cert);
219 print_cert(cert, false);
220 CFReleaseSafe(cert);
221 }
222 CFDictionaryRef dict;
223 CFTypeRef identity_handle = NULL;
224 const void * keys[] = { kSecReturnPersistentRef,
225 kSecValueRef };
226 const void * values[] = { kCFBooleanTrue,
227 identity };
228 dict = CFDictionaryCreate(NULL,
229 keys, values,
230 array_size(keys),
231 &kCFTypeDictionaryKeyCallBacks,
232 &kCFTypeDictionaryValueCallBacks);
233 status = SecItemAdd(dict, &identity_handle);
234 if (identity_handle != NULL) {
235 find_identity_using_handle(identity_handle);
236 }
237 CFReleaseNull(identity_handle);
238 if (status != errSecSuccess) {
239 fprintf(stderr, "SecItemAdd(identity) failed %d\n",
240 (int)status);
241 success = FALSE;
242 }
243 CFReleaseNull(dict);
244 }
245
246 /* add certs */
247 trust_ref = (SecTrustRef)CFDictionaryGetValue(item_dict, kSecImportItemTrust);
248 if (trust_ref != NULL) {
249 CFIndex cert_count;
250 CFIndex cert_index;
251
252 cert_count = SecTrustGetCertificateCount(trust_ref);
253 for (cert_index = 1; cert_index < cert_count; cert_index++) {
254 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust_ref, cert_index);
255 if (verbose)
256 print_cert(cert, false);
257 status = add_cert_item(cert);
258 if (status != errSecSuccess) {
259 fprintf(stderr, "add_cert_item %d failed %d\n", (int)cert_index, (int)status);
260 success = FALSE;
261 }
262 }
263 }
264 }
265 return (success);
266 }
267
268 static bool
269 PKCS12ArrayRemoveSecItems(CFArrayRef items, bool verbose)
270 {
271 CFIndex count;
272 CFIndex i;
273 bool success = TRUE;
274
275 count = CFArrayGetCount(items);
276 for (i = 0; i < count; i++) {
277 CFTypeRef cert_chain;
278 SecIdentityRef identity;
279 CFDictionaryRef item_dict = CFArrayGetValueAtIndex(items, i);
280 OSStatus status;
281
282 /* remove identity */
283 identity = (SecIdentityRef)CFDictionaryGetValue(item_dict,
284 kSecImportItemIdentity);
285 if (identity != NULL) {
286 if (verbose) {
287 SecCertificateRef cert = NULL;
288 SecIdentityCopyCertificate(identity, &cert);
289 print_cert(cert, false);
290 CFReleaseSafe(cert);
291 }
292 CFDictionaryRef dict;
293
294 dict = CFDictionaryCreate(NULL,
295 (const void * *)&kSecValueRef,
296 (const void * *)&identity, 1,
297 &kCFTypeDictionaryKeyCallBacks,
298 &kCFTypeDictionaryValueCallBacks);
299 status = SecItemDelete(dict);
300 if (status != errSecSuccess) {
301 fprintf(stderr, "SecItemDelete(identity) failed %d\n",
302 (int)status);
303 success = FALSE;
304 }
305 CFReleaseNull(dict);
306 }
307 /* remove cert chain */
308 cert_chain = CFDictionaryGetValue(item_dict, kSecImportItemCertChain);
309 if (cert_chain != NULL) {
310 CFIndex cert_count;
311 CFIndex cert_index;
312
313 cert_count = CFArrayGetCount(cert_chain);
314 for (cert_index = 0; cert_index < cert_count; cert_index++) {
315 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_chain, cert_index);
316 if (verbose)
317 print_cert(cert, false);
318 status = remove_cert_item(cert);
319 if (status != errSecSuccess) {
320 fprintf(stderr, "remove_cert_item %d failed %d\n", (int)cert_index, (int)status);
321 success = FALSE;
322 }
323 }
324 }
325 }
326 return (success);
327 }
328
329
330 extern int pkcs12_util(int argc, char * const *argv)
331 {
332 CFArrayRef array;
333 const char * filename = NULL;
334 const char * passphrase = NULL;
335 bool delete = false;
336 bool verbose = false;
337 char ch;
338
339 while ((ch = getopt(argc, argv, "p:dv")) != -1)
340 {
341 switch (ch)
342 {
343 case 'p':
344 passphrase = optarg;
345 break;
346 case 'd':
347 delete = true;
348 break;
349 case 'v':
350 verbose = true;
351 break;
352 default:
353 return SHOW_USAGE_MESSAGE;
354 }
355 }
356
357 argc -= optind;
358 argv += optind;
359
360 if (argc != 1 || !passphrase)
361 return SHOW_USAGE_MESSAGE;
362
363 filename = argv[0];
364 array = PKCS12FileCreateArray(filename, passphrase);
365 if (array == NULL)
366 return -1;
367
368 bool success = false;
369 if (delete)
370 success = PKCS12ArrayRemoveSecItems(array, verbose);
371 else
372 success = PKCS12ArrayAddSecItems(array, verbose);
373
374 CFReleaseNull(array);
375
376 return success ? 0 : -1;
377 }
378
379 #endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR