]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/kcImport/kcImport.cpp
Security-57031.30.12.tar.gz
[apple/security.git] / SecurityTests / clxutils / kcImport / kcImport.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 #include <clAppUtils/identPicker.h>
14
15 static void usage(char **argv)
16 {
17 printf("Usage: %s infile [option ...]\n", argv[0]);
18 printf("Options:\n");
19 printf(" -k keychain Keychain to import into\n");
20 printf(" -z passphrase For PKCS12 and wrapped keys only\n");
21 printf(" -w Private keys are wrapped\n");
22 printf(" -d Display Imported Items\n");
23 printf(" -i Interactive: displays items before possible import\n");
24 printf(" -v Verbose display\n");
25 printf(" -l Loop & Pause for MallocDebug\n");
26 printf(" -q Quiet\n");
27 printf("Import type/format options:\n");
28 printf(" -t <type> type = pub|priv|session|cert|agg\n");
29 printf(" -f <format> format = openssl|openssh1|openssh2|bsafe|\n"
30 " raw|pkcs7|pkcs8|pkcs12|netscape|pemseq\n");
31 printf("Private key options:\n");
32 printf(" -a appPath Add appPath to list of trusted apps in private key's ACL\n");
33 printf(" -e Allow private keys to be extractable in the clear\n");
34 printf(" -n Private keys have *NO* ACL\n");
35 printf(" -s Private keys can sign (only)\n");
36 printf("Secure passphrase options:\n");
37 printf(" -Z Get secure passphrase\n");
38 printf(" -L title\n");
39 printf(" -p prompt\n");
40 printf("Verification options:\n");
41 printf(" -C numCerts Verify number of certificates\n");
42 printf(" -K numKeys Verify number of keys\n");
43 printf(" -I numIdents Verify number of identities\n");
44 printf(" -F rtnFormat Returned format = "
45 "openssl|openssh1|openssh2|bsafe|raw|pkcs7|pkcs12|netscape|pemseq\n");
46 printf(" -T <type> Returned type = pub|priv|session|cert|agg\n");
47 printf(" -m Set ImportOnlyOneKey bit\n");
48 printf(" -M Set ImportOnlyOneKey bit and expect errSecMultiplePrivKeys\n");
49 exit(1);
50 }
51
52 const char *secExtFormatStr(
53 SecExternalFormat format)
54 {
55 switch(format) {
56 case kSecFormatUnknown: return "kSecFormatUnknown";
57 case kSecFormatOpenSSL: return "kSecFormatOpenSSL";
58 case kSecFormatSSH: return "kSecFormatSSH";
59 case kSecFormatBSAFE: return "kSecFormatBSAFE";
60 case kSecFormatRawKey: return "kSecFormatRawKey";
61 case kSecFormatWrappedPKCS8: return "kSecFormatWrappedPKCS8";
62 case kSecFormatWrappedOpenSSL: return "kSecFormatWrappedOpenSSL";
63 case kSecFormatWrappedSSH: return "kSecFormatWrappedSSH";
64 case kSecFormatWrappedLSH: return "kSecFormatWrappedLSH";
65 case kSecFormatX509Cert: return "kSecFormatX509Cert";
66 case kSecFormatPEMSequence: return "kSecFormatPEMSequence";
67 case kSecFormatPKCS7: return "kSecFormatPKCS7";
68 case kSecFormatPKCS12: return "kSecFormatPKCS12";
69 case kSecFormatNetscapeCertSequence: return "kSecFormatNetscapeCertSequence";
70 case kSecFormatSSHv2: return "kSecFormatSSHv2";
71 default: return "UNKNOWN FORMAT ENUM";
72 }
73 }
74
75 const char *secExtItemTypeStr(
76 SecExternalItemType itemType)
77 {
78 switch(itemType) {
79 case kSecItemTypeUnknown: return "kSecItemTypeUnknown";
80 case kSecItemTypePrivateKey: return "kSecItemTypePrivateKey";
81 case kSecItemTypePublicKey: return "kSecItemTypePublicKey";
82 case kSecItemTypeSessionKey: return "kSecItemTypeSessionKey";
83 case kSecItemTypeCertificate: return "kSecItemTypeCertificate";
84 case kSecItemTypeAggregate: return "kSecItemTypeAggregate";
85 default: return "UNKNOWN ITEM TYPE ENUM";
86 }
87 }
88
89 static OSStatus processItem(
90 SecKeychainRef keychain,
91 SecKeychainItemRef item,
92 int *numCerts, // IN/OUT
93 int *numKeys,
94 int *numIds,
95 bool interactive, // unimplemented
96 bool verbose)
97 {
98 char *kcName = NULL;
99 CFTypeID itemType = CFGetTypeID(item);
100 if(itemType == SecIdentityGetTypeID()) {
101 (*numIds)++;
102 if(verbose) {
103 /* identities don't have keychains, only their components do */
104 SecCertificateRef certRef = NULL;
105 OSStatus ortn;
106 ortn = SecIdentityCopyCertificate((SecIdentityRef)item, &certRef);
107 if(ortn) {
108 cssmPerror("SecIdentityCopyCertificate", ortn);
109 return ortn;
110 }
111 kcName = kcItemKcFileName((SecKeychainItemRef)certRef);
112 printf(" identity : cert keychain name %s\n", kcName ? kcName : "<none>");
113 CFRelease(certRef);
114
115 SecKeyRef keyRef = NULL;
116 ortn = SecIdentityCopyPrivateKey((SecIdentityRef)item, &keyRef);
117 if(ortn) {
118 cssmPerror("SecIdentityCopyPrivateKey", ortn);
119 return ortn;
120 }
121 free(kcName);
122 kcName = kcItemKcFileName((SecKeychainItemRef)keyRef);
123 printf(" identity : key keychain name %s\n", kcName ? kcName : "<none>");
124 CFRelease(keyRef);
125 }
126 }
127 else if(itemType == SecCertificateGetTypeID()) {
128 (*numCerts)++;
129 if(verbose) {
130 kcName = kcItemKcFileName(item);
131 printf(" cert : keychain name %s\n", kcName ? kcName : "<none>");
132 }
133 }
134 else if(itemType == SecKeyGetTypeID()) {
135 (*numKeys)++;
136 if(verbose) {
137 kcName = kcItemKcFileName(item);
138 printf(" key : keychain name %s\n", kcName ? kcName : "<none>");
139 }
140 }
141 /* FIX display attr info, at least names, eventually */
142 else {
143 printf("***Unknown type returned from SecKeychainItemImport()\n");
144 return errSecUnknownFormat;
145 }
146 if(kcName) {
147 free(kcName);
148 }
149 return noErr;
150 }
151
152 static OSStatus processItems(
153 SecKeychainRef keychain,
154 CFArrayRef outArray,
155 int expectNumCerts, // -1 means don't check
156 int expectNumKeys,
157 int expectNumIds,
158 bool interactive,
159 bool displayItems,
160 bool verbose)
161 {
162 int numCerts = 0;
163 int numKeys = 0;
164 int numIds = 0;
165 OSStatus ortn;
166
167 CFIndex numItems = CFArrayGetCount(outArray);
168 for(CFIndex dex=0; dex<numItems; dex++) {
169 ortn = processItem(keychain,
170 (SecKeychainItemRef)CFArrayGetValueAtIndex(outArray, dex),
171 &numCerts, &numKeys, &numIds, interactive, verbose);
172 if(ortn) {
173 break;
174 }
175 }
176 if(ortn) {
177 return ortn;
178 }
179
180 if(displayItems) {
181 printf("Certs found : %d\n", numCerts);
182 printf("Keys found : %d\n", numKeys);
183 printf("Idents found : %d\n", numIds);
184 }
185 if(expectNumCerts >= 0) {
186 if(expectNumCerts != numCerts) {
187 printf("***Expected %d certs, got %d\n",
188 expectNumCerts, numCerts);
189 ortn = -1;
190 }
191 }
192 if(expectNumKeys >= 0) {
193 if(expectNumKeys != numKeys) {
194 printf("***Expected %d keys, got %d\n",
195 expectNumKeys, numKeys);
196 ortn = -1;
197 }
198 }
199 if(expectNumIds >= 0) {
200 if(expectNumIds != numIds) {
201 printf("***Expected %d certs, got %d\n",
202 expectNumIds, numIds);
203 ortn = -1;
204 }
205 }
206 return ortn;
207 }
208
209 /*
210 * Parse cmd-line format specifier into an SecExternalFormat.
211 * Returns true if it works.
212 */
213 static bool formatFromString(
214 const char *formStr,
215 SecExternalFormat *externFormat)
216 {
217 if(!strcmp("openssl", formStr)) {
218 *externFormat = kSecFormatOpenSSL;
219 }
220 else if(!strcmp("openssh1", formStr)) {
221 *externFormat = kSecFormatSSH;
222 }
223 else if(!strcmp("openssh2", formStr)) {
224 *externFormat = kSecFormatSSHv2;
225 }
226 else if(!strcmp("bsafe", formStr)) {
227 *externFormat = kSecFormatBSAFE;
228 }
229 else if(!strcmp("raw", formStr)) {
230 *externFormat = kSecFormatRawKey;
231 }
232 else if(!strcmp("pkcs7", formStr)) {
233 *externFormat = kSecFormatPKCS7;
234 }
235 else if(!strcmp("pkcs8", formStr)) {
236 *externFormat = kSecFormatWrappedPKCS8;
237 }
238 else if(!strcmp("pkcs12", formStr)) {
239 *externFormat = kSecFormatPKCS12;
240 }
241 else if(!strcmp("netscape", formStr)) {
242 *externFormat = kSecFormatNetscapeCertSequence;
243 }
244 else if(!strcmp("pemseq", formStr)) {
245 *externFormat = kSecFormatPEMSequence;
246 }
247 else {
248 return false;
249 }
250 return true;
251 }
252
253 /*
254 * Parse cmd-line type specifier into an SecExternalItemType.
255 * Returns true if it works.
256 */
257 static bool itemTypeFromString(
258 const char *typeStr,
259 SecExternalItemType *itemType)
260 {
261 if(!strcmp("pub", typeStr)) {
262 *itemType = kSecItemTypePublicKey;
263 }
264 else if(!strcmp("priv", typeStr)) {
265 *itemType = kSecItemTypePrivateKey;
266 }
267 else if(!strcmp("session", typeStr)) {
268 *itemType = kSecItemTypeSessionKey;
269 }
270 else if(!strcmp("cert", typeStr)) {
271 *itemType = kSecItemTypeCertificate;
272 }
273 else if(!strcmp("agg", typeStr)) {
274 *itemType = kSecItemTypeAggregate;
275 }
276 else {
277 return false;
278 }
279 return true;
280 }
281
282 int main(int argc, char **argv)
283 {
284 if(argc < 2) {
285 usage(argv);
286 }
287
288 const char *inFileName = argv[1];
289
290 extern int optind;
291 extern char *optarg;
292 int arg;
293 optind = 2;
294 int ourRtn = 0;
295 SecAccessRef accessRef = NULL;
296 OSStatus ortn;
297
298 /* optional args */
299 const char *keychainName = NULL;
300 CFStringRef passphrase = NULL;
301 bool interactive = false;
302 bool securePassphrase = false;
303 SecExternalFormat externFormat = kSecFormatUnknown;
304 SecExternalItemType itemType = kSecItemTypeUnknown;
305 bool doWrap = false;
306 bool allowClearExtract = false;
307 int expectNumCerts = -1; // >=0 means verify per user spec
308 int expectNumKeys = -1;
309 int expectNumIds = -1;
310 bool processOutput = false;
311 bool displayItems = false;
312 SecExternalFormat expectFormat = kSecFormatUnknown; // otherwise verify
313 SecExternalItemType expectItemType = kSecItemTypeUnknown; // ditto
314 bool quiet = false;
315 bool noACL = false;
316 char *alertTitle = NULL;
317 char *alertPrompt = NULL;
318 bool setAllowOnlyOne = false;
319 bool expectMultiKeysError = false;
320 CFMutableArrayRef trustedAppList = NULL;
321 bool loopPause = false;
322 bool signOnly = false;
323 bool verbose = false;
324
325 while ((arg = getopt(argc, argv, "k:iZz:wet:f:C:K:I:F:T:qnL:p:mMa:dlsv")) != -1) {
326 switch (arg) {
327 case 'k':
328 keychainName = optarg;
329 break;
330 case 'i':
331 interactive = true;
332 processOutput = true;
333 break;
334 case 'Z':
335 securePassphrase = true;
336 break;
337 case 'z':
338 passphrase = CFStringCreateWithCString(NULL, optarg,
339 kCFStringEncodingASCII);
340 break;
341 case 'w':
342 doWrap = true;
343 break;
344 case 'e':
345 allowClearExtract = true;
346 break;
347 case 't':
348 if(!itemTypeFromString(optarg, &itemType)) {
349 usage(argv);
350 }
351 break;
352 case 'T':
353 if(!itemTypeFromString(optarg, &expectItemType)) {
354 usage(argv);
355 }
356 break;
357 case 'f':
358 if(!formatFromString(optarg, &externFormat)) {
359 usage(argv);
360 }
361 break;
362 case 'F':
363 if(!formatFromString(optarg, &expectFormat)) {
364 usage(argv);
365 }
366 break;
367 case 'C':
368 expectNumCerts = atoi(optarg);
369 processOutput = true;
370 break;
371 case 'K':
372 expectNumKeys = atoi(optarg);
373 processOutput = true;
374 break;
375 case 'I':
376 expectNumIds = atoi(optarg);
377 processOutput = true;
378 break;
379 case 'd':
380 displayItems = true;
381 processOutput = true;
382 break;
383 case 'q':
384 quiet = true;
385 break;
386 case 'n':
387 noACL = true;
388 break;
389 case 'L':
390 alertTitle = optarg;
391 break;
392 case 'p':
393 alertPrompt = optarg;
394 break;
395 case 'm':
396 setAllowOnlyOne = true;
397 break;
398 case 'M':
399 setAllowOnlyOne = true;
400 expectMultiKeysError = true;
401 break;
402 case 'a':
403 {
404 if(trustedAppList == NULL) {
405 trustedAppList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
406 }
407 SecTrustedApplicationRef appRef;
408 ortn = SecTrustedApplicationCreateFromPath(optarg, &appRef);
409 if(ortn) {
410 cssmPerror("SecTrustedApplicationCreateFromPath", ortn);
411 exit(1);
412 }
413 CFArrayAppendValue(trustedAppList, appRef);
414 break;
415 }
416 case 's':
417 signOnly = true;
418 break;
419 case 'l':
420 loopPause = true;
421 break;
422 case 'v':
423 verbose = true;
424 break;
425 default:
426 case '?':
427 usage(argv);
428 }
429 }
430 if(optind != argc) {
431 /* getopt does not return '?' */
432 usage(argv);
433 }
434 if(doWrap) {
435 switch(externFormat) {
436 case kSecFormatOpenSSL:
437 case kSecFormatUnknown: // i.e., use default
438 externFormat = kSecFormatWrappedOpenSSL;
439 break;
440 case kSecFormatSSH:
441 externFormat = kSecFormatWrappedSSH;
442 break;
443 case kSecFormatSSHv2:
444 /* there is no wrappedSSHv2 */
445 externFormat = kSecFormatWrappedOpenSSL;
446 break;
447 case kSecFormatWrappedPKCS8:
448 /* proceed */
449 break;
450 default:
451 printf("Don't know how to wrap in specified format/type.\n");
452 exit(1);
453 }
454 }
455
456 CFArrayRef outArray = NULL;
457 CFArrayRef *outArrayP = NULL;
458 if(processOutput) {
459 outArrayP = &outArray;
460 }
461
462 SecKeychainRef kcRef = NULL;
463 if(keychainName) {
464 OSStatus ortn = SecKeychainOpen(keychainName, &kcRef);
465 if(ortn) {
466 cssmPerror("SecKeychainOpen", ortn);
467 exit(1);
468 }
469 /* why is this failing later */
470 CSSM_DL_DB_HANDLE dlDbHandle;
471 ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHandle);
472 if(ortn) {
473 cssmPerror("SecKeychainGetDLDBHandle", ortn);
474 exit(1);
475 }
476
477 }
478
479 unsigned char *inFile = NULL;
480 unsigned inFileLen = 0;
481 if(readFile(inFileName, &inFile, &inFileLen)) {
482 printf("***Error reading input file %s. Aborting.\n", inFileName);
483 exit(1);
484 }
485 CFDataRef inFileRef = CFDataCreate(NULL, inFile, inFileLen);
486 CFStringRef fileNameStr = CFStringCreateWithCString(NULL, inFileName,
487 kCFStringEncodingASCII);
488
489 loopTop:
490 SecKeyImportExportParameters keyParams;
491 SecKeyImportExportParameters *keyParamPtr = NULL;
492
493 if(passphrase || securePassphrase || allowClearExtract || noACL ||
494 setAllowOnlyOne || trustedAppList || signOnly) {
495 keyParamPtr = &keyParams;
496 memset(&keyParams, 0, sizeof(keyParams));
497 if(securePassphrase) {
498 /* give this precedence */
499 keyParams.flags |= kSecKeySecurePassphrase;
500 if(alertTitle) {
501 keyParams.alertTitle =
502 CFStringCreateWithCString(NULL, alertTitle, kCFStringEncodingASCII);
503 }
504 if(alertPrompt) {
505 keyParams.alertPrompt =
506 CFStringCreateWithCString(NULL, alertPrompt, kCFStringEncodingASCII);
507 }
508 }
509 else if(passphrase) {
510 keyParams.passphrase = passphrase;
511 }
512 if(noACL) {
513 keyParams.flags |= kSecKeyNoAccessControl;
514 }
515 if(setAllowOnlyOne) {
516 keyParams.flags |= kSecKeyImportOnlyOne;
517 }
518 keyParams.keyAttributes = ( CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
519 if(!allowClearExtract) {
520 keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE;
521 }
522 if(kcRef) {
523 keyParams.keyAttributes |= CSSM_KEYATTR_PERMANENT;
524 }
525 if(signOnly) {
526 keyParams.keyUsage = CSSM_KEYUSE_SIGN;
527 }
528 else {
529 keyParams.keyUsage = CSSM_KEYUSE_ANY;
530 }
531 if(trustedAppList) {
532 ortn = SecAccessCreate(CFSTR("Imported Private Key"), trustedAppList, &accessRef);
533 if(ortn) {
534 cssmPerror("SecAccessCreate", ortn);
535 exit(1);
536 }
537 keyParams.accessRef = accessRef;
538 }
539 /* TBD other stuff - usage? Other? */
540 }
541
542 /* GO */
543 ortn = SecKeychainItemImport(inFileRef,
544 fileNameStr,
545 &externFormat,
546 &itemType,
547 0, // flags
548 keyParamPtr,
549 kcRef,
550 outArrayP);
551 ourRtn = 0;
552 if(ortn) {
553 if(expectMultiKeysError && (ortn == errSecMultiplePrivKeys)) {
554 if(!quiet) {
555 printf("...errSecMultiplePrivKeys error seen as expected\n");
556 }
557 }
558 else {
559 cssmPerror("SecKeychainItemImport", ortn);
560 ourRtn = -1;
561 }
562 }
563 else if(expectMultiKeysError) {
564 printf("***errSecMultiplePrivKeys expected but no error seen\n");
565 ourRtn = -1;
566 }
567 if(ortn == noErr) {
568 if(!quiet) {
569 printf("...import successful. Returned format %s\n",
570 secExtFormatStr(externFormat));
571 }
572 if(expectFormat != kSecFormatUnknown) {
573 if(expectFormat != externFormat) {
574 printf("***Expected format %s, got %s\n",
575 secExtFormatStr(expectFormat),
576 secExtFormatStr(externFormat));
577 ourRtn = -1;
578 }
579 }
580 if(expectItemType != kSecItemTypeUnknown) {
581 if(expectItemType != itemType) {
582 printf("***Expected itemType %s, got %s\n",
583 secExtItemTypeStr(expectItemType),
584 secExtItemTypeStr(itemType));
585 ourRtn = -1;
586 }
587 }
588 if(processOutput) {
589 ourRtn |= processItems(kcRef, outArray, expectNumCerts,
590 expectNumKeys, expectNumIds, interactive, displayItems, verbose);
591 }
592 }
593 if(loopPause) {
594 fflush(stdin);
595 printf("Pausing for MallocDebug; CR to continue: ");
596 getchar();
597 goto loopTop;
598 }
599 return ourRtn;
600 }