]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/kcExport/kcExport.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / kcExport / kcExport.cpp
1 /*
2 * kcExport.cpp - export keychain items using SecKeychainItemExport
3 */
4
5 #include <Security/Security.h>
6 #include <Security/SecImportExport.h>
7 #include <security_cdsa_utils/cuFileIo.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <utilLib/common.h>
13
14 static void usage(char **argv)
15 {
16 printf("Usage: %s keychain [option ...]\n", argv[0]);
17 printf("Options:\n");
18 printf(" -t <type> itemType = certs|allKeys|pubKeys|privKeys|identities|all\n");
19 printf(" ...default itemType=all\n");
20 printf(" -f <format> format = openssl|openssh1|openssh2|bsafe|pkcs7|pkcs8|pkcs12|pemseq\n"
21 " ...default itemType is pemseq for aggregate, openssl\n"
22 " for single \n");
23 printf(" -p PEM encode\n");
24 printf(" -w Private keys are wrapped\n");
25 printf(" -o outFileName (default is stdout)\n");
26 printf(" -z passphrase (for PKCS12 and wrapped keys only)\n");
27 printf(" -Z Use secure passphrase\n");
28 printf(" -q Quiet\n");
29 printf(" -h help\n");
30 exit(1);
31 }
32
33 typedef enum {
34 IS_Certs,
35 IS_AllKeys,
36 IS_PubKeys,
37 IS_PrivKeys,
38 IS_Identities,
39 IS_All
40 } ItemSpec;
41
42 /*
43 * Add all itmes of specified class from a keychain to an array.
44 * Item class are things like kSecCertificateItemClass, and
45 * CSSM_DL_DB_RECORD_PRIVATE_KEY. Identities are searched separately.
46 */
47 static OSStatus addKcItems(
48 SecKeychainRef kcRef,
49 SecItemClass itemClass, // kSecCertificateItemClass
50 CFMutableArrayRef outArray)
51 {
52 OSStatus ortn;
53 SecKeychainSearchRef srchRef;
54
55 ortn = SecKeychainSearchCreateFromAttributes(kcRef,
56 itemClass,
57 NULL, // no attrs
58 &srchRef);
59 if(ortn) {
60 cssmPerror("SecKeychainSearchCreateFromAttributes", ortn);
61 return ortn;
62 }
63 for(;;) {
64 SecKeychainItemRef itemRef;
65 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
66 if(ortn) {
67 if(ortn == errSecItemNotFound) {
68 /* normal search end */
69 ortn = noErr;
70 }
71 else {
72 cssmPerror("SecKeychainSearchCopyNext", ortn);
73 }
74 break;
75 }
76 CFArrayAppendValue(outArray, itemRef);
77 CFRelease(itemRef); // array owns it
78 }
79 CFRelease(srchRef);
80 return ortn;
81 }
82
83 /*
84 * Add all SecIdentityRefs from a keychain into an array.
85 */
86 static OSStatus addIdentities(
87 SecKeychainRef kcRef,
88 CFMutableArrayRef outArray)
89 {
90 /* Search for all identities */
91 SecIdentitySearchRef srchRef;
92 OSStatus ortn = SecIdentitySearchCreate(kcRef,
93 0, // keyUsage - any
94 &srchRef);
95 if(ortn) {
96 cssmPerror("SecIdentitySearchCreate", ortn);
97 return ortn;
98 }
99
100 do {
101 SecIdentityRef identity;
102 ortn = SecIdentitySearchCopyNext(srchRef, &identity);
103 if(ortn) {
104 if(ortn == errSecItemNotFound) {
105 /* normal search end */
106 ortn = noErr;
107 }
108 else {
109 cssmPerror("SecIdentitySearchCopyNext", ortn);
110 }
111 break;
112 }
113 CFArrayAppendValue(outArray, identity);
114
115 /* the array has the retain count we need */
116 CFRelease(identity);
117 } while(ortn == noErr);
118 CFRelease(srchRef);
119 return ortn;
120 }
121
122 int main(int argc, char **argv)
123 {
124 if(argc < 4) {
125 usage(argv);
126 }
127
128 const char *kcName = argv[1];
129 SecKeychainRef kcRef = NULL;
130 OSStatus ortn = SecKeychainOpen(kcName, &kcRef);
131 if(ortn) {
132 cssmPerror("SecKeychainOpen", ortn);
133 exit(1);
134 }
135
136 /* user specified options */
137 ItemSpec itemSpec = IS_All; // default
138 SecExternalFormat exportForm = kSecFormatUnknown;
139 bool pemEncode = false;
140 const char *outFile = NULL;
141 CFStringRef passphrase = NULL;
142 bool securePassphrase = false;
143 bool quiet = false;
144 bool wrapPrivKeys = false;
145
146 extern int optind;
147 extern char *optarg;
148 int arg;
149 optind = 2;
150
151 while ((arg = getopt(argc, argv, "t:f:po:z:Zhqw")) != -1) {
152 switch (arg) {
153 case 't':
154 if(!strcmp("certs", optarg)) {
155 itemSpec = IS_Certs;
156 }
157 else if(!strcmp("allKeys", optarg)) {
158 itemSpec = IS_AllKeys;
159 }
160 else if(!strcmp("pubKeys", optarg)) {
161 itemSpec = IS_PubKeys;
162 }
163 else if(!strcmp("privKeys", optarg)) {
164 itemSpec = IS_PrivKeys;
165 }
166 else if(!strcmp("identities", optarg)) {
167 itemSpec = IS_Identities;
168 }
169 else if(!strcmp("all", optarg)) {
170 itemSpec = IS_All;
171 }
172 else {
173 usage(argv);
174 }
175 break;
176 case 'f':
177 if(!strcmp("openssl", optarg)) {
178 exportForm = kSecFormatOpenSSL;
179 }
180 else if(!strcmp("openssh1", optarg)) {
181 exportForm = kSecFormatSSH;
182 }
183 else if(!strcmp("openssh2", optarg)) {
184 exportForm = kSecFormatSSHv2;
185 }
186 else if(!strcmp("bsafe", optarg)) {
187 exportForm = kSecFormatBSAFE;
188 }
189 else if(!strcmp("pkcs7", optarg)) {
190 exportForm = kSecFormatPKCS7;
191 }
192 else if(!strcmp("pkcs8", optarg)) {
193 exportForm = kSecFormatWrappedPKCS8;
194 }
195 else if(!strcmp("pkcs12", optarg)) {
196 exportForm = kSecFormatPKCS12;
197 }
198 else if(!strcmp("pemseq", optarg)) {
199 exportForm = kSecFormatPEMSequence;
200 }
201 else {
202 usage(argv);
203 }
204 break;
205 case 'p':
206 pemEncode = true;
207 break;
208 case 'o':
209 outFile = optarg;
210 break;
211 case 'z':
212 passphrase = CFStringCreateWithCString(NULL, optarg,
213 kCFStringEncodingASCII);
214 break;
215 case 'Z':
216 securePassphrase = true;
217 break;
218 case 'w':
219 wrapPrivKeys = true;
220 break;
221 case 'q':
222 quiet = true;
223 break;
224 case '?':
225 case 'h':
226 default:
227 usage(argv);
228 }
229
230 }
231 if(optind != argc) {
232 /* getopt does not return '?' */
233 usage(argv);
234 }
235 if(wrapPrivKeys) {
236 switch(exportForm) {
237 case kSecFormatOpenSSL:
238 case kSecFormatUnknown: // i.e., use default
239 exportForm = kSecFormatWrappedOpenSSL;
240 break;
241 case kSecFormatSSH:
242 exportForm = kSecFormatWrappedSSH;
243 break;
244 case kSecFormatSSHv2:
245 /* there is no wrappedSSHv2 */
246 exportForm = kSecFormatWrappedOpenSSL;
247 break;
248 case kSecFormatWrappedPKCS8:
249 /* proceed */
250 break;
251 default:
252 printf("Don't know how to wrap in specified format/type.\n");
253 exit(1);
254 }
255 }
256
257 /* gather items */
258 CFMutableArrayRef exportItems = CFArrayCreateMutable(NULL, 0,
259 &kCFTypeArrayCallBacks);
260 switch(itemSpec) {
261 case IS_Certs:
262 ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems);
263 if(ortn) {
264 exit(1);
265 }
266 break;
267
268 case IS_PrivKeys:
269 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems);
270 if(ortn) {
271 exit(1);
272 }
273 break;
274
275 case IS_PubKeys:
276 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems);
277 if(ortn) {
278 exit(1);
279 }
280 break;
281
282 case IS_AllKeys:
283 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems);
284 if(ortn) {
285 exit(1);
286 }
287 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems);
288 if(ortn) {
289 exit(1);
290 }
291 break;
292
293 case IS_All:
294 /* No public keys here - PKCS12 doesn't support them */
295 ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems);
296 if(ortn) {
297 exit(1);
298 }
299 ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems);
300 if(ortn) {
301 exit(1);
302 }
303 break;
304
305 case IS_Identities:
306 ortn = addIdentities(kcRef, exportItems);
307 if(ortn) {
308 exit(1);
309 }
310 break;
311 default:
312 printf("Huh? Bogus itemSpec!\n");
313 exit(1);
314 }
315
316 CFIndex numItems = CFArrayGetCount(exportItems);
317
318 if(exportForm == kSecFormatUnknown) {
319 /* Use default export format per set of items */
320 if(numItems > 1) {
321 exportForm = kSecFormatPEMSequence;
322 }
323 else {
324 exportForm = kSecFormatOpenSSL;
325 }
326 }
327 uint32 expFlags = 0; // SecItemImportExportFlags
328 if(pemEncode) {
329 expFlags |= kSecItemPemArmour;
330 }
331
332 /* optional key related arguments */
333 SecKeyImportExportParameters keyParams;
334 SecKeyImportExportParameters *keyParamPtr = NULL;
335 if((passphrase != NULL) || securePassphrase) {
336 memset(&keyParams, 0, sizeof(keyParams));
337 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
338 if(securePassphrase) {
339 /* give this precedence */
340 keyParams.flags |= kSecKeySecurePassphrase;
341 }
342 else {
343 keyParams.passphrase = passphrase; // may be NULL
344 }
345 keyParamPtr = &keyParams;
346 }
347
348 /* GO */
349 CFDataRef outData = NULL;
350 ortn = SecKeychainItemExport(exportItems, exportForm, expFlags, keyParamPtr,
351 &outData);
352 if(ortn) {
353 cssmPerror("SecKeychainItemExport", ortn);
354 exit(1);
355 }
356
357 unsigned len = CFDataGetLength(outData);
358 if(outFile) {
359 int rtn = writeFile(outFile, CFDataGetBytePtr(outData), len);
360 if(rtn == 0) {
361 if(!quiet) {
362 printf("...%u bytes written to %s\n", len, outFile);
363 }
364 }
365 else {
366 printf("***Error writing to %s\n", outFile);
367 }
368 }
369 else {
370 int irtn = write(STDOUT_FILENO, CFDataGetBytePtr(outData), len);
371 if(irtn != (int)len) {
372 perror("write");
373 }
374 }
375 if(!quiet) {
376 fprintf(stderr, "\n%u items exported.\n", (unsigned)numItems);
377 }
378 if(exportItems) {
379 /* FIXME this in conjunction with the release of the KC crashes */
380 CFRelease(exportItems);
381 }
382 if(passphrase) {
383 CFRelease(passphrase);
384 }
385 if(outData) {
386 CFRelease(outData);
387 }
388 if(kcRef) {
389 CFRelease(kcRef);
390 }
391 return 0;
392 }