2 * kcExport.cpp - export keychain items using SecKeychainItemExport
5 #include <Security/Security.h>
6 #include <Security/SecImportExport.h>
7 #include <security_cdsa_utils/cuFileIo.h>
12 #include <utilLib/common.h>
13 #include <clAppUtils/identPicker.h>
15 static void usage(char **argv
)
17 printf("Usage: %s infile [option ...]\n", argv
[0]);
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");
52 const char *secExtFormatStr(
53 SecExternalFormat 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";
75 const char *secExtItemTypeStr(
76 SecExternalItemType 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";
89 static OSStatus
processItem(
90 SecKeychainRef keychain
,
91 SecKeychainItemRef item
,
92 int *numCerts
, // IN/OUT
95 bool interactive
, // unimplemented
99 CFTypeID itemType
= CFGetTypeID(item
);
100 if(itemType
== SecIdentityGetTypeID()) {
103 /* identities don't have keychains, only their components do */
104 SecCertificateRef certRef
= NULL
;
106 ortn
= SecIdentityCopyCertificate((SecIdentityRef
)item
, &certRef
);
108 cssmPerror("SecIdentityCopyCertificate", ortn
);
111 kcName
= kcItemKcFileName((SecKeychainItemRef
)certRef
);
112 printf(" identity : cert keychain name %s\n", kcName
? kcName
: "<none>");
115 SecKeyRef keyRef
= NULL
;
116 ortn
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, &keyRef
);
118 cssmPerror("SecIdentityCopyPrivateKey", ortn
);
122 kcName
= kcItemKcFileName((SecKeychainItemRef
)keyRef
);
123 printf(" identity : key keychain name %s\n", kcName
? kcName
: "<none>");
127 else if(itemType
== SecCertificateGetTypeID()) {
130 kcName
= kcItemKcFileName(item
);
131 printf(" cert : keychain name %s\n", kcName
? kcName
: "<none>");
134 else if(itemType
== SecKeyGetTypeID()) {
137 kcName
= kcItemKcFileName(item
);
138 printf(" key : keychain name %s\n", kcName
? kcName
: "<none>");
141 /* FIX display attr info, at least names, eventually */
143 printf("***Unknown type returned from SecKeychainItemImport()\n");
144 return errSecUnknownFormat
;
152 static OSStatus
processItems(
153 SecKeychainRef keychain
,
155 int expectNumCerts
, // -1 means don't check
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
);
181 printf("Certs found : %d\n", numCerts
);
182 printf("Keys found : %d\n", numKeys
);
183 printf("Idents found : %d\n", numIds
);
185 if(expectNumCerts
>= 0) {
186 if(expectNumCerts
!= numCerts
) {
187 printf("***Expected %d certs, got %d\n",
188 expectNumCerts
, numCerts
);
192 if(expectNumKeys
>= 0) {
193 if(expectNumKeys
!= numKeys
) {
194 printf("***Expected %d keys, got %d\n",
195 expectNumKeys
, numKeys
);
199 if(expectNumIds
>= 0) {
200 if(expectNumIds
!= numIds
) {
201 printf("***Expected %d certs, got %d\n",
202 expectNumIds
, numIds
);
210 * Parse cmd-line format specifier into an SecExternalFormat.
211 * Returns true if it works.
213 static bool formatFromString(
215 SecExternalFormat
*externFormat
)
217 if(!strcmp("openssl", formStr
)) {
218 *externFormat
= kSecFormatOpenSSL
;
220 else if(!strcmp("openssh1", formStr
)) {
221 *externFormat
= kSecFormatSSH
;
223 else if(!strcmp("openssh2", formStr
)) {
224 *externFormat
= kSecFormatSSHv2
;
226 else if(!strcmp("bsafe", formStr
)) {
227 *externFormat
= kSecFormatBSAFE
;
229 else if(!strcmp("raw", formStr
)) {
230 *externFormat
= kSecFormatRawKey
;
232 else if(!strcmp("pkcs7", formStr
)) {
233 *externFormat
= kSecFormatPKCS7
;
235 else if(!strcmp("pkcs8", formStr
)) {
236 *externFormat
= kSecFormatWrappedPKCS8
;
238 else if(!strcmp("pkcs12", formStr
)) {
239 *externFormat
= kSecFormatPKCS12
;
241 else if(!strcmp("netscape", formStr
)) {
242 *externFormat
= kSecFormatNetscapeCertSequence
;
244 else if(!strcmp("pemseq", formStr
)) {
245 *externFormat
= kSecFormatPEMSequence
;
254 * Parse cmd-line type specifier into an SecExternalItemType.
255 * Returns true if it works.
257 static bool itemTypeFromString(
259 SecExternalItemType
*itemType
)
261 if(!strcmp("pub", typeStr
)) {
262 *itemType
= kSecItemTypePublicKey
;
264 else if(!strcmp("priv", typeStr
)) {
265 *itemType
= kSecItemTypePrivateKey
;
267 else if(!strcmp("session", typeStr
)) {
268 *itemType
= kSecItemTypeSessionKey
;
270 else if(!strcmp("cert", typeStr
)) {
271 *itemType
= kSecItemTypeCertificate
;
273 else if(!strcmp("agg", typeStr
)) {
274 *itemType
= kSecItemTypeAggregate
;
282 int main(int argc
, char **argv
)
288 const char *inFileName
= argv
[1];
295 SecAccessRef accessRef
= NULL
;
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
;
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
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;
325 while ((arg
= getopt(argc
, argv
, "k:iZz:wet:f:C:K:I:F:T:qnL:p:mMa:dlsv")) != -1) {
328 keychainName
= optarg
;
332 processOutput
= true;
335 securePassphrase
= true;
338 passphrase
= CFStringCreateWithCString(NULL
, optarg
,
339 kCFStringEncodingASCII
);
345 allowClearExtract
= true;
348 if(!itemTypeFromString(optarg
, &itemType
)) {
353 if(!itemTypeFromString(optarg
, &expectItemType
)) {
358 if(!formatFromString(optarg
, &externFormat
)) {
363 if(!formatFromString(optarg
, &expectFormat
)) {
368 expectNumCerts
= atoi(optarg
);
369 processOutput
= true;
372 expectNumKeys
= atoi(optarg
);
373 processOutput
= true;
376 expectNumIds
= atoi(optarg
);
377 processOutput
= true;
381 processOutput
= true;
393 alertPrompt
= optarg
;
396 setAllowOnlyOne
= true;
399 setAllowOnlyOne
= true;
400 expectMultiKeysError
= true;
404 if(trustedAppList
== NULL
) {
405 trustedAppList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
407 SecTrustedApplicationRef appRef
;
408 ortn
= SecTrustedApplicationCreateFromPath(optarg
, &appRef
);
410 cssmPerror("SecTrustedApplicationCreateFromPath", ortn
);
413 CFArrayAppendValue(trustedAppList
, appRef
);
431 /* getopt does not return '?' */
435 switch(externFormat
) {
436 case kSecFormatOpenSSL
:
437 case kSecFormatUnknown
: // i.e., use default
438 externFormat
= kSecFormatWrappedOpenSSL
;
441 externFormat
= kSecFormatWrappedSSH
;
443 case kSecFormatSSHv2
:
444 /* there is no wrappedSSHv2 */
445 externFormat
= kSecFormatWrappedOpenSSL
;
447 case kSecFormatWrappedPKCS8
:
451 printf("Don't know how to wrap in specified format/type.\n");
456 CFArrayRef outArray
= NULL
;
457 CFArrayRef
*outArrayP
= NULL
;
459 outArrayP
= &outArray
;
462 SecKeychainRef kcRef
= NULL
;
464 OSStatus ortn
= SecKeychainOpen(keychainName
, &kcRef
);
466 cssmPerror("SecKeychainOpen", ortn
);
469 /* why is this failing later */
470 CSSM_DL_DB_HANDLE dlDbHandle
;
471 ortn
= SecKeychainGetDLDBHandle(kcRef
, &dlDbHandle
);
473 cssmPerror("SecKeychainGetDLDBHandle", ortn
);
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
);
485 CFDataRef inFileRef
= CFDataCreate(NULL
, inFile
, inFileLen
);
486 CFStringRef fileNameStr
= CFStringCreateWithCString(NULL
, inFileName
,
487 kCFStringEncodingASCII
);
490 SecKeyImportExportParameters keyParams
;
491 SecKeyImportExportParameters
*keyParamPtr
= NULL
;
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
;
501 keyParams
.alertTitle
=
502 CFStringCreateWithCString(NULL
, alertTitle
, kCFStringEncodingASCII
);
505 keyParams
.alertPrompt
=
506 CFStringCreateWithCString(NULL
, alertPrompt
, kCFStringEncodingASCII
);
509 else if(passphrase
) {
510 keyParams
.passphrase
= passphrase
;
513 keyParams
.flags
|= kSecKeyNoAccessControl
;
515 if(setAllowOnlyOne
) {
516 keyParams
.flags
|= kSecKeyImportOnlyOne
;
518 keyParams
.keyAttributes
= ( CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
);
519 if(!allowClearExtract
) {
520 keyParams
.keyAttributes
|= CSSM_KEYATTR_SENSITIVE
;
523 keyParams
.keyAttributes
|= CSSM_KEYATTR_PERMANENT
;
526 keyParams
.keyUsage
= CSSM_KEYUSE_SIGN
;
529 keyParams
.keyUsage
= CSSM_KEYUSE_ANY
;
532 ortn
= SecAccessCreate(CFSTR("Imported Private Key"), trustedAppList
, &accessRef
);
534 cssmPerror("SecAccessCreate", ortn
);
537 keyParams
.accessRef
= accessRef
;
539 /* TBD other stuff - usage? Other? */
543 ortn
= SecKeychainItemImport(inFileRef
,
553 if(expectMultiKeysError
&& (ortn
== errSecMultiplePrivKeys
)) {
555 printf("...errSecMultiplePrivKeys error seen as expected\n");
559 cssmPerror("SecKeychainItemImport", ortn
);
563 else if(expectMultiKeysError
) {
564 printf("***errSecMultiplePrivKeys expected but no error seen\n");
569 printf("...import successful. Returned format %s\n",
570 secExtFormatStr(externFormat
));
572 if(expectFormat
!= kSecFormatUnknown
) {
573 if(expectFormat
!= externFormat
) {
574 printf("***Expected format %s, got %s\n",
575 secExtFormatStr(expectFormat
),
576 secExtFormatStr(externFormat
));
580 if(expectItemType
!= kSecItemTypeUnknown
) {
581 if(expectItemType
!= itemType
) {
582 printf("***Expected itemType %s, got %s\n",
583 secExtItemTypeStr(expectItemType
),
584 secExtItemTypeStr(itemType
));
589 ourRtn
|= processItems(kcRef
, outArray
, expectNumCerts
,
590 expectNumKeys
, expectNumIds
, interactive
, displayItems
, verbose
);
595 printf("Pausing for MallocDebug; CR to continue: ");