]> git.saurik.com Git - apple/security.git/blob - SecurityTool/keychain_export.m
Security-58286.70.7.tar.gz
[apple/security.git] / SecurityTool / keychain_export.m
1 /*
2 * Copyright (c) 2003-2004,2006,2012,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 * keychain_export.c
24 */
25
26 #import <Foundation/Foundation.h>
27
28 #include "keychain_export.h"
29 #include "keychain_utilities.h"
30 #include "security_tool.h"
31
32 #include <errno.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <Security/SecImportExport.h>
36 #include <Security/SecKeychainItem.h>
37 #include <Security/SecKeychainSearch.h>
38 #include <Security/SecIdentitySearch.h>
39 #include <Security/SecKey.h>
40 #include <Security/SecCertificate.h>
41 #include <Security/SecCertificatePriv.h>
42 #include <Security/SecItem.h>
43 #include <Security/SecAccessControl.h>
44 #include <Security/SecAccessControlPriv.h>
45 #include <security_cdsa_utils/cuFileIo.h>
46 #include <CoreFoundation/CoreFoundation.h>
47 #include <stdio.h>
48
49 typedef enum {
50 IS_Certs,
51 IS_AllKeys,
52 IS_PubKeys,
53 IS_PrivKeys,
54 IS_Identities,
55 IS_All
56 } ItemSpec;
57
58 /*
59 * Add all itmes of specified class from a keychain to an array.
60 * Item class are things like kSecCertificateItemClass, and
61 * CSSM_DL_DB_RECORD_PRIVATE_KEY. Identities are searched separately.
62 */
63 static OSStatus addKcItems(
64 SecKeychainRef kcRef,
65 SecItemClass itemClass, // kSecCertificateItemClass
66 CFMutableArrayRef outArray,
67 unsigned *numItems) // UPDATED on return
68 {
69 OSStatus ortn;
70 SecKeychainSearchRef srchRef;
71
72 ortn = SecKeychainSearchCreateFromAttributes(kcRef,
73 itemClass,
74 NULL, // no attrs
75 &srchRef);
76 if(ortn) {
77 sec_perror("SecKeychainSearchCreateFromAttributes", ortn);
78 return ortn;
79 }
80 for(;;) {
81 SecKeychainItemRef itemRef;
82 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
83 if(ortn) {
84 if(ortn == errSecItemNotFound) {
85 /* normal search end */
86 ortn = noErr;
87 }
88 else {
89 sec_perror("SecIdentitySearchCopyNext", ortn);
90 }
91 break;
92 }
93 CFArrayAppendValue(outArray, itemRef);
94 CFRelease(itemRef); // array owns the item
95 (*numItems)++;
96 }
97 CFRelease(srchRef);
98 return ortn;
99 }
100
101 /*
102 * Add all SecIdentityRefs from a keychain into an array.
103 */
104 static OSStatus addIdentities(
105 SecKeychainRef kcRef,
106 CFMutableArrayRef outArray,
107 unsigned *numItems) // UPDATED on return
108 {
109 /* Search for all identities */
110 SecIdentitySearchRef srchRef;
111 OSStatus ortn = SecIdentitySearchCreate(kcRef,
112 0, // keyUsage - any
113 &srchRef);
114 if(ortn) {
115 sec_perror("SecIdentitySearchCreate", ortn);
116 return ortn;
117 }
118
119 do {
120 SecIdentityRef identity;
121 ortn = SecIdentitySearchCopyNext(srchRef, &identity);
122 if(ortn) {
123 if(ortn == errSecItemNotFound) {
124 /* normal search end */
125 ortn = noErr;
126 }
127 else {
128 sec_perror("SecIdentitySearchCopyNext", ortn);
129 }
130 break;
131 }
132 CFArrayAppendValue(outArray, identity);
133
134 /* the array has the retain count we need */
135 CFRelease(identity);
136 (*numItems)++;
137 } while(ortn == noErr);
138 CFRelease(srchRef);
139 return ortn;
140 }
141
142 static int do_keychain_export(
143 SecKeychainRef kcRef,
144 SecExternalFormat externFormat,
145 ItemSpec itemSpec,
146 const char *passphrase,
147 int doPem,
148 const char *fileName)
149 {
150 int result = 0;
151 CFIndex numItems;
152 unsigned numPrivKeys = 0;
153 unsigned numPubKeys = 0;
154 unsigned numCerts = 0;
155 unsigned numIdents = 0;
156 OSStatus ortn;
157 uint32 expFlags = 0; // SecItemImportExportFlags
158 SecKeyImportExportParameters keyParams;
159 CFStringRef passStr = NULL;
160 CFDataRef outData = NULL;
161 size_t len;
162
163 /* gather items */
164 CFMutableArrayRef exportItems = CFArrayCreateMutable(NULL, 0,
165 &kCFTypeArrayCallBacks);
166 switch(itemSpec) {
167 case IS_Certs:
168 ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems, &numCerts);
169 if(ortn) {
170 result = 1;
171 goto loser;
172 }
173 break;
174
175 case IS_PrivKeys:
176 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems,
177 &numPrivKeys);
178 if(ortn) {
179 result = 1;
180 goto loser;
181 }
182 break;
183
184 case IS_PubKeys:
185 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems,
186 &numPubKeys);
187 if(ortn) {
188 result = 1;
189 goto loser;
190 }
191 break;
192
193 case IS_AllKeys:
194 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems,
195 &numPrivKeys);
196 if(ortn) {
197 result = 1;
198 goto loser;
199 }
200 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems,
201 &numPubKeys);
202 if(ortn) {
203 result = 1;
204 goto loser;
205 }
206 break;
207
208 case IS_All:
209 /* No public keys here - PKCS12 doesn't support them */
210 ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems, &numCerts);
211 if(ortn) {
212 result = 1;
213 goto loser;
214 }
215 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems,
216 &numPrivKeys);
217 if(ortn) {
218 result = 1;
219 goto loser;
220 }
221 break;
222
223 case IS_Identities:
224 ortn = addIdentities(kcRef, exportItems, &numIdents);
225 if(ortn) {
226 result = 1;
227 goto loser;
228 }
229 if(numIdents) {
230 numPrivKeys += numIdents;
231 numCerts += numIdents;
232 }
233 break;
234 default:
235 sec_error("Internal error parsing item_spec");
236 result = 1;
237 goto loser;
238 }
239
240 numItems = CFArrayGetCount(exportItems);
241 if(externFormat == kSecFormatUnknown) {
242 /* Use default export format per set of items */
243 if(numItems > 1) {
244 externFormat = kSecFormatPEMSequence;
245 }
246 else if(numCerts) {
247 externFormat = kSecFormatX509Cert;
248 }
249 else {
250 externFormat = kSecFormatOpenSSL;
251 }
252 }
253 if(doPem) {
254 expFlags |= kSecItemPemArmour;
255 }
256
257 /*
258 * Key related arguments, ignored if we're not exporting keys.
259 * Always specify some kind of passphrase - default is secure passkey.
260 */
261 memset(&keyParams, 0, sizeof(keyParams));
262 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
263 if(passphrase != NULL) {
264 passStr = CFStringCreateWithCString(NULL, passphrase, kCFStringEncodingASCII);
265 keyParams.passphrase = passStr;
266 }
267 else {
268 keyParams.flags = kSecKeySecurePassphrase;
269 }
270
271 /* Go */
272 ortn = SecKeychainItemExport(exportItems, externFormat, expFlags, &keyParams,
273 &outData);
274 if(ortn) {
275 sec_perror("SecKeychainItemExport", ortn);
276 result = 1;
277 goto loser;
278 }
279
280 len = CFDataGetLength(outData);
281 if(fileName) {
282 int rtn = writeFileSizet(fileName, CFDataGetBytePtr(outData), len);
283 if(rtn == 0) {
284 if(!do_quiet) {
285 fprintf(stderr, "...%lu bytes written to %s\n", len, fileName);
286 }
287 }
288 else {
289 sec_error("Error writing to %s: %s", fileName, strerror(errno));
290 result = 1;
291 }
292 }
293 else {
294 size_t irtn = write(STDOUT_FILENO, CFDataGetBytePtr(outData), len);
295 if(irtn != (size_t)len) {
296 perror("write");
297 }
298 }
299 loser:
300 if(exportItems) {
301 CFRelease(exportItems);
302 }
303 if(passStr) {
304 CFRelease(passStr);
305 }
306 if(outData) {
307 CFRelease(outData);
308 }
309 return result;
310 }
311
312 int
313 keychain_export(int argc, char * const *argv)
314 {
315 int ch, result = 0;
316
317 char *outFile = NULL;
318 char *kcName = NULL;
319 SecKeychainRef kcRef = NULL;
320 SecExternalFormat externFormat = kSecFormatUnknown;
321 ItemSpec itemSpec = IS_All;
322 int wrapped = 0;
323 int doPem = 0;
324 const char *passphrase = NULL;
325
326 while ((ch = getopt(argc, argv, "k:o:t:f:P:wph")) != -1)
327 {
328 switch (ch)
329 {
330 case 'k':
331 kcName = optarg;
332 break;
333 case 'o':
334 outFile = optarg;
335 break;
336 case 't':
337 if(!strcmp("certs", optarg)) {
338 itemSpec = IS_Certs;
339 }
340 else if(!strcmp("allKeys", optarg)) {
341 itemSpec = IS_AllKeys;
342 }
343 else if(!strcmp("pubKeys", optarg)) {
344 itemSpec = IS_PubKeys;
345 }
346 else if(!strcmp("privKeys", optarg)) {
347 itemSpec = IS_PrivKeys;
348 }
349 else if(!strcmp("identities", optarg)) {
350 itemSpec = IS_Identities;
351 }
352 else if(!strcmp("all", optarg)) {
353 itemSpec = IS_All;
354 }
355 else {
356 return SHOW_USAGE_MESSAGE;
357 }
358 break;
359 case 'f':
360 if(!strcmp("openssl", optarg)) {
361 externFormat = kSecFormatOpenSSL;
362 }
363 else if(!strcmp("openssh1", optarg)) {
364 externFormat = kSecFormatSSH;
365 }
366 else if(!strcmp("openssh2", optarg)) {
367 externFormat = kSecFormatSSHv2;
368 }
369 else if(!strcmp("bsafe", optarg)) {
370 externFormat = kSecFormatBSAFE;
371 }
372 else if(!strcmp("raw", optarg)) {
373 externFormat = kSecFormatRawKey;
374 }
375 else if(!strcmp("pkcs7", optarg)) {
376 externFormat = kSecFormatPKCS7;
377 }
378 else if(!strcmp("pkcs8", optarg)) {
379 externFormat = kSecFormatWrappedPKCS8;
380 }
381 else if(!strcmp("pkcs12", optarg)) {
382 externFormat = kSecFormatPKCS12;
383 }
384 else if(!strcmp("netscape", optarg)) {
385 externFormat = kSecFormatNetscapeCertSequence;
386 }
387 else if(!strcmp("x509", optarg)) {
388 externFormat = kSecFormatX509Cert;
389 }
390 else if(!strcmp("pemseq", optarg)) {
391 externFormat = kSecFormatPEMSequence;
392 }
393 else {
394 return SHOW_USAGE_MESSAGE;
395 }
396 break;
397 case 'w':
398 wrapped = 1;
399 break;
400 case 'p':
401 doPem = 1;
402 break;
403 case 'P':
404 passphrase = optarg;
405 break;
406 case '?':
407 default:
408 return SHOW_USAGE_MESSAGE;
409 }
410 }
411
412 if(wrapped) {
413 switch(externFormat) {
414 case kSecFormatOpenSSL:
415 case kSecFormatUnknown: // i.e., use default
416 externFormat = kSecFormatWrappedOpenSSL;
417 break;
418 case kSecFormatSSH:
419 externFormat = kSecFormatWrappedSSH;
420 break;
421 case kSecFormatSSHv2:
422 /* there is no wrappedSSHv2 */
423 externFormat = kSecFormatWrappedOpenSSL;
424 break;
425 case kSecFormatWrappedPKCS8:
426 /* proceed */
427 break;
428 default:
429 sec_error("Don't know how to wrap in specified format/type");
430 return SHOW_USAGE_MESSAGE;
431 }
432 }
433
434 if(kcName) {
435 kcRef = keychain_open(kcName);
436 if(kcRef == NULL) {
437 return 1;
438 }
439 }
440 result = do_keychain_export(kcRef, externFormat, itemSpec,
441 passphrase, doPem, outFile);
442
443 if(kcRef) {
444 CFRelease(kcRef);
445 }
446 return result;
447 }
448
449 typedef struct {
450 CFMutableStringRef str;
451 } ctk_dict2str_context;
452
453
454 static void
455 ctk_obj_to_str(CFTypeRef obj, char *buf, int bufLen, Boolean key);
456
457 static void
458 ctk_dict2str(const void *key, const void *value, void *context)
459 {
460 char keyBuf[64] = { 0 };
461 ctk_obj_to_str(key, keyBuf, sizeof(keyBuf), true);
462
463 char valueBuf[1024] = { 0 };
464 ctk_obj_to_str(value, valueBuf, sizeof(valueBuf), false);
465
466 CFStringRef str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("\n\t\t\t%s : %s,"), keyBuf, valueBuf);
467 CFStringAppend(((ctk_dict2str_context *)context)->str, str);
468 CFRelease(str);
469 }
470
471 static void
472 ctk_obj_to_str(CFTypeRef obj, char *buf, int bufLen, Boolean key)
473 {
474 CFStringRef str = NULL;
475
476 if(CFGetTypeID(obj) == CFStringGetTypeID()) {
477 // CFStringRef - print the string as is (for keys) or quoted (values)
478 str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, key ? CFSTR("%@") : CFSTR("\"%@\""), obj);
479 } else if(CFGetTypeID(obj) == CFNumberGetTypeID()) {
480 // CFNumber - print the value using current locale
481 CFNumberRef num = (CFNumberRef)obj;
482
483 CFLocaleRef locale = CFLocaleCopyCurrent();
484 CFNumberFormatterRef fmt = CFNumberFormatterCreate(kCFAllocatorDefault, locale, kCFNumberFormatterDecimalStyle);
485 CFRelease(locale);
486
487 str = CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault, fmt, num);
488 CFRelease(fmt);
489 } else if(CFGetTypeID(obj) == CFDataGetTypeID()) {
490 // CFData - print the data as <hex bytes>
491 CFDataRef data = (CFDataRef)obj;
492
493 CFMutableStringRef hexStr = CFStringCreateMutable(kCFAllocatorDefault, CFDataGetLength(data) * 3);
494
495 for(int i = 0; i < CFDataGetLength(data); i++) {
496 CFStringRef hexByte = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x "), *(CFDataGetBytePtr(data) + i));
497 CFStringAppend(hexStr, hexByte);
498 CFRelease(hexByte);
499 }
500
501 // Get rid of the last excessive space.
502 if(CFDataGetLength(data)) {
503 CFStringDelete(hexStr, CFRangeMake(CFStringGetLength(hexStr) - 1, 1));
504 }
505
506 str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<%@>"), hexStr);
507 CFRelease(hexStr);
508 } else if(CFGetTypeID(obj) == CFBooleanGetTypeID()) {
509 // CFBoolean - print true/false
510 CFBooleanRef cfbool = (CFBooleanRef)obj;
511
512 str = CFStringCreateWithCString(kCFAllocatorDefault, CFBooleanGetValue(cfbool) ? "true" : "false", kCFStringEncodingUTF8);
513 } else if(CFGetTypeID(obj) == SecAccessControlGetTypeID()) {
514 // SecAccessControlRef - print the constraints dictionary
515 SecAccessControlRef ac = (SecAccessControlRef)obj;
516
517 CFDictionaryRef constraints = SecAccessControlGetConstraints(ac);
518 CFMutableStringRef constraintsStr = CFStringCreateMutable(kCFAllocatorDefault, 1024);
519 if(constraints && CFDictionaryGetCount(constraints)) {
520 ctk_dict2str_context context;
521 context.str = constraintsStr;
522 CFDictionaryApplyFunction(constraints, ctk_dict2str, &context);
523 CFStringReplace(constraintsStr, CFRangeMake(CFStringGetLength(constraintsStr) - 1, 1), CFSTR("\n\t\t"));
524 }
525
526 CFDictionaryRef protection = SecAccessControlGetProtection(ac);
527 CFMutableStringRef protectionStr = CFStringCreateMutable(kCFAllocatorDefault, 512);
528 if(protection && CFDictionaryGetCount(protection)) {
529 ctk_dict2str_context context;
530 context.str = protectionStr;
531 CFDictionaryApplyFunction(protection, ctk_dict2str, &context);
532 CFStringReplace(protectionStr, CFRangeMake(CFStringGetLength(protectionStr) - 1, 1), CFSTR("\n\t\t"));
533 }
534
535 str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("constraints: {%@}\n\t\tprotection: {%@}"), constraintsStr, protectionStr);
536 CFRelease(constraintsStr);
537 CFRelease(protectionStr);
538 }
539
540 // Fill the provided buffer with the converted string.
541 if(str) {
542 Boolean success = CFStringGetCString(str, buf, bufLen, kCFStringEncodingUTF8);
543 CFRelease(str);
544
545 if(success) {
546 return;
547 }
548 }
549
550 // Use object description as fallback...
551 CFStringRef description = CFCopyDescription(obj);
552 if(!CFStringGetCString(description, buf, bufLen, kCFStringEncodingUTF8)) {
553 // ...or else we don't know.
554 strncpy(buf, "<?>", bufLen);
555 }
556
557 CFRelease(description);
558 }
559
560 typedef struct {
561 int i;
562 const char *name;
563 } ctk_print_context;
564
565 OSStatus
566 ctk_dump_item(CFTypeRef item, ctk_print_context *ctx);
567
568 static void
569 ctk_print_dict(const void *key, const void *value, void *context)
570 {
571 char keyBuf[64] = { 0 };
572 ctk_obj_to_str(key, keyBuf, sizeof(keyBuf), true);
573
574 char valueBuf[1024] = { 0 };
575 ctk_obj_to_str(value, valueBuf, sizeof(valueBuf), false);
576
577 printf("\t%s : %s\n", keyBuf, valueBuf);
578 }
579
580 static void
581 ctk_dump_item_header(ctk_print_context *ctx)
582 {
583 printf("\n");
584 printf("==== %s #%d\n", ctx->name, ctx->i);
585 }
586
587 static void
588 ctk_dump_item_footer(ctk_print_context *ctx)
589 {
590 printf("====\n");
591 }
592
593 OSStatus
594 ctk_dump_item(CFTypeRef item, ctk_print_context *ctx)
595 {
596 OSStatus stat = errSecSuccess;
597
598 CFTypeID tid = CFGetTypeID(item);
599 if(tid == CFDictionaryGetTypeID()) {
600 // We expect a dictionary containing item attributes.
601 ctk_dump_item_header(ctx);
602 CFDictionaryApplyFunction((CFDictionaryRef)item, ctk_print_dict, ctx);
603 ctk_dump_item_footer(ctx);
604 } else {
605 stat = errSecInternalComponent;
606 printf("Unexpected item type ID: %lu\n", tid);
607 }
608
609 return stat;
610 }
611
612 static OSStatus
613 ctk_dump_items(CFArrayRef items, CFTypeRef secClass, const char *name)
614 {
615 OSStatus stat = errSecSuccess;
616
617 ctk_print_context ctx = { 1, name };
618
619 for(CFIndex i = 0; i < CFArrayGetCount(items); i++) {
620 CFTypeRef item = CFArrayGetValueAtIndex(items, i);
621 stat = ctk_dump_item(item, &ctx);
622 ctx.i++;
623
624 if(stat) {
625 break;
626 }
627 }
628
629 return stat;
630 }
631
632 static OSStatus
633 ctk_dump(CFTypeRef secClass, const char *name, const char *tid)
634 {
635 NSArray *result;
636 BOOL returnRef = NO;
637
638 if ([(__bridge id)secClass isEqual:(id)kSecClassIdentity] || [(__bridge id)secClass isEqual:(id)kSecClassCertificate])
639 returnRef = YES;
640
641 NSDictionary *query = @{
642 (id)kSecClass : (__bridge id)secClass,
643 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
644 (id)kSecAttrAccessGroup : (id)kSecAttrAccessGroupToken,
645 (id)kSecReturnAttributes : @YES,
646 (id)kSecReturnRef : @(returnRef)
647 };
648
649 if(tid) {
650 NSMutableDictionary *updatedQuery = [NSMutableDictionary dictionaryWithDictionary:query];
651 updatedQuery[(id)kSecAttrTokenID] = [NSString stringWithUTF8String:tid];
652 query = updatedQuery;
653 }
654
655 OSStatus stat = SecItemCopyMatching((__bridge CFTypeRef)query, (void *)&result);
656 if(stat) {
657 if (stat == errSecItemNotFound) {
658 fprintf(stderr, "No items found.\n");
659 } else {
660 sec_error("SecItemCopyMatching: %x (%d) - %s", stat, stat, sec_errstr(stat));
661 }
662 return stat;
663 }
664
665 // We expect an array of dictionaries containing item attributes as result.
666 if([result isKindOfClass:[NSArray class]]) {
667 if (returnRef) {
668 NSMutableArray *updatedResult = [NSMutableArray array];
669 for (NSDictionary *dict in result) {
670 NSMutableDictionary *updatedItem = [NSMutableDictionary dictionaryWithDictionary:dict];
671 id itemRef = updatedItem[(id)kSecValueRef];
672 if ([(__bridge id)secClass isEqual:(id)kSecClassIdentity]) {
673 id certificateRef;
674 if (SecIdentityCopyCertificate((__bridge SecIdentityRef)itemRef, (void *)&certificateRef) != errSecSuccess)
675 continue;
676 itemRef = certificateRef;
677 }
678
679 NSData *certDigest = (__bridge NSData*)SecCertificateGetSHA1Digest((__bridge SecCertificateRef)itemRef);
680 updatedItem[@"sha1"] = certDigest;
681 [updatedItem removeObjectForKey:(id)kSecValueRef];
682 [updatedResult addObject:updatedItem];
683 }
684 result = updatedResult;
685 }
686
687 stat = ctk_dump_items((__bridge CFArrayRef)result, secClass, name);
688 } else {
689 stat = errSecInternalComponent;
690 }
691 return stat;
692 }
693
694 int
695 ctk_export(int argc, char * const *argv)
696 {
697 OSStatus stat = errSecSuccess;
698
699 ItemSpec itemSpec = IS_All;
700 const char *tid = NULL;
701 int ch;
702
703 while ((ch = getopt(argc, argv, "i:t:h")) != -1) {
704 switch (ch) {
705 case 't':
706 if(!strcmp("certs", optarg)) {
707 itemSpec = IS_Certs;
708 }
709 else if(!strcmp("privKeys", optarg)) {
710 itemSpec = IS_PrivKeys;
711 }
712 else if(!strcmp("identities", optarg)) {
713 itemSpec = IS_Identities;
714 }
715 else if(!strcmp("all", optarg)) {
716 itemSpec = IS_All;
717 }
718 else {
719 return SHOW_USAGE_MESSAGE;
720 }
721 break;
722 case 'i':
723 tid = optarg;
724 break;
725
726 case '?':
727 default:
728 return SHOW_USAGE_MESSAGE;
729 }
730 }
731
732 CFTypeRef classes[] = { kSecClassCertificate, kSecClassKey, kSecClassIdentity };
733 const char* names[] = { "certificate", "private key", "identity" };
734 ItemSpec specs[] = { IS_Certs, IS_PrivKeys, IS_Identities };
735
736 for(size_t i = 0; i < sizeof(classes)/sizeof(classes[0]); i++) {
737 if(specs[i] == itemSpec || itemSpec == IS_All) {
738 stat = ctk_dump(classes[i], names[i], tid);
739 if(stat) {
740 break;
741 }
742 }
743 }
744
745 return stat;
746 }