]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/p12/p12ImportExport.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12 / p12ImportExport.cpp
1 /*
2 * p12ImportExport.cpp - high-level libnsspkcs12 exerciser
3 */
4
5 #include <security_pkcs12/SecPkcs12.h>
6 #include <security_cdsa_utils/cuFileIo.h>
7 #include <Security/Security.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <security_cdsa_utilities/KeySchema.h>
11 #include <security_cdsa_utils/cuCdsaUtils.h>
12 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
13 #include "p12GetPassKey.h"
14
15 static void printOsError(
16 const char *op,
17 OSStatus ortn)
18 {
19 char *errStr = NULL;
20 switch(ortn) {
21 case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
22 errStr = "CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA"; break;
23 case CSSMERR_DL_DATASTORE_DOESNOT_EXIST:
24 errStr = "CSSMERR_DL_DATASTORE_DOESNOT_EXIST"; break;
25 case errSecDuplicateItem:
26 errStr = "errSecDuplicateItem"; break;
27 case errSecNotAvailable:
28 errStr = "errSecNotAvailable"; break;
29 case errSecAuthFailed:
30 errStr = "errSecAuthFailed"; break;
31 case errSecItemNotFound:
32 errStr = "errSecItemNotFound"; break;
33 case errSecInvalidItemRef:
34 errStr = "errSecInvalidItemRef"; break;
35 default:
36 break;
37 }
38 if(errStr) {
39 printf("%s returned %s\n", op, errStr);
40 }
41 else {
42 printf("%s returned %d\n", op, (int)ortn);
43 }
44 }
45
46 /*
47 * For now we assume "import everything"
48 */
49 int p12Import(
50 const char *pfxFile,
51 const char *kcName,
52 CFStringRef pwd, // explicit passphrase, mutually exclusive with...
53 bool usePassKey, // use SECURE_PASSPHRASE key
54 const char *kcPwd) // optional
55 {
56 OSStatus ortn;
57 unsigned char *pfx;
58 unsigned pfxLen;
59 CSSM_KEY passKey;
60
61 /* get the PFX */
62 if(readFile(pfxFile, &pfx, &pfxLen)) {
63 printf("***Error reading pfx from %s. Aborting.\n", pfxFile);
64 return 1;
65 }
66 CFDataRef cfd = CFDataCreate(NULL, pfx, pfxLen);
67
68 /* import to keychain specified by kcName */
69 SecKeychainRef kcRef = NULL;
70 ortn = SecKeychainOpen(kcName, &kcRef);
71 if(ortn) {
72 printOsError("SecKeychainOpen", ortn);
73 return ortn;
74 }
75
76 if(kcPwd) {
77 ortn = SecKeychainUnlock(kcRef, strlen(kcPwd), (void *)kcPwd, true);
78 if(ortn) {
79 printOsError("SecKeychainUnlock", ortn);
80 }
81 }
82
83 /* set up a pkcs12 coder for import */
84 SecPkcs12CoderRef coder;
85 ortn = SecPkcs12CoderCreate(&coder);
86 if(ortn) {
87 printOsError("SecPkcs12CoderCreate", ortn);
88 return ortn;
89 }
90
91 ortn = SecPkcs12SetKeychain(coder, kcRef);
92 if(ortn) {
93 printOsError("SecPkcs12SetKeychain", ortn);
94 return ortn;
95 }
96
97 if(usePassKey) {
98 CSSM_CSP_HANDLE cspHand;
99 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
100 if(ortn) {
101 printOsError("SecPkcs12SetKeychain", ortn);
102 return ortn;
103 }
104 ortn = p12GetPassKey(cspHand, GPK_Decode, false, &passKey);
105 if(ortn) {
106 return ortn;
107 }
108 ortn = SecPkcs12SetMACPassKey(coder, &passKey);
109 if(ortn) {
110 printOsError("SecPkcs12SetMACPassKey", ortn);
111 return ortn;
112 }
113 }
114 else {
115 ortn = SecPkcs12SetMACPassphrase(coder, pwd);
116 if(ortn) {
117 printOsError("SecPkcs12SetMACPassphrase", ortn);
118 return ortn;
119 }
120 }
121
122 /*
123 * For now we assume "import everything"
124 */
125 ortn = SecPkcs12SetImportToKeychain(coder,
126 kSecImportCertificates |
127 kSecImportCRLs |
128 kSecImportKeys);
129 if(ortn) {
130 printOsError("SecPkcs12SetImportFromKeychain", ortn);
131 return ortn;
132 }
133
134 /* Go! */
135 ortn = SecPkcs12Decode(coder, cfd);
136 if(ortn) {
137 printOsError("SecPkcs12Decode", ortn);
138 return ortn;
139 }
140
141 /* report how many of each item got imported */
142 CFIndex num;
143 SecPkcs12CertificateCount(coder, &num);
144 printf("...%d certs imported\n", (int)num);
145 SecPkcs12CrlCount(coder, &num);
146 printf("...%d CRLs imported\n", (int)num);
147 SecPkcs12PrivateKeyCount(coder, &num);
148 printf("...%d private keys imported\n", (int)num);
149
150 SecPkcs12CoderRelease(coder);
151 CFRelease(cfd);
152 free(pfx); // mallocd by readFile()
153 return 0;
154 }
155
156 /*
157 * Use the kludge from hell to get the name-as-int form of a specified
158 * "known" name-as-string for the Key Schema.
159 */
160 OSStatus attrNameToInt(
161 const char *name,
162 uint32 *attrInt)
163 {
164 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *attrList =
165 KeySchema::KeySchemaAttributeList;
166 unsigned numAttrs = KeySchema::KeySchemaAttributeCount;
167 for(unsigned dex=0; dex<numAttrs; dex++) {
168 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *info = &attrList[dex];
169 if(!strcmp(name, info->AttributeName)) {
170 *attrInt = info->AttributeId;
171 return noErr;
172 }
173 }
174 return paramErr;
175 }
176
177 static int p12AddExportedItem(
178 SecKeychainItemRef item,
179 CFMutableArrayRef itemArray,
180 bool noPrompt)
181 {
182 if(noPrompt) {
183 CFArrayAppendValue(itemArray, item);
184 return 1;
185 }
186
187 CFTypeID itemId = CFGetTypeID(item);
188 OSStatus ortn;
189
190 /* the printable name attr */
191 UInt32 nameAttr = 0;
192 char *itemClass = "";
193 if(itemId == SecCertificateGetTypeID()) {
194 itemClass = "Certificate";
195 nameAttr = kSecLabelItemAttr;
196 }
197 else if(itemId == SecKeyGetTypeID()) {
198 itemClass = "Private Key";
199 ortn = attrNameToInt("PrintName", &nameAttr);
200 if(ortn) {
201 /* out of sync with Sec layer? With KeySchema? */
202 printf("warning: attrNameToInt failure\n");
203 return 0;
204 }
205 }
206 else {
207 /* we don't know how to deal with this */
208 printf("p12AddExportedItem: internal screwup\n");
209 return 0;
210 }
211
212 /* get the printable name attr */
213 SecKeychainAttributeInfo attrInfo;
214 attrInfo.count = 1;
215 attrInfo.tag = &nameAttr;
216 attrInfo.format = NULL; // ???
217
218 /* FIXME header says this is an IN/OUT param, but it's not */
219 SecKeychainAttributeList *attrList = NULL;
220
221 ortn = SecKeychainItemCopyAttributesAndData(
222 item,
223 &attrInfo,
224 NULL, // itemClass
225 &attrList,
226 NULL, // don't need the data
227 NULL);
228 if(ortn) {
229 printOsError("SecKeychainItemCopyAttributesAndData", ortn);
230 return 0;
231 }
232 if(attrList->count != 1) {
233 printf("***Unexpected attribute count (%u) for %s\n",
234 (unsigned)attrList->count, itemClass);
235 return 0;
236 }
237 SecKeychainAttribute *attr = attrList->attr;
238
239 /* it's a UTF8 string: use CFString to convert to C ASCII string */
240 CFStringRef cfStr = CFStringCreateWithBytes(NULL,
241 (UInt8 *)attr->data, attr->length,
242 kCFStringEncodingUTF8, false);
243 SecKeychainItemFreeAttributesAndData(attrList, NULL);
244 if(cfStr == NULL) {
245 printf("***Error converting %s name to UTF CFSTring.\n",
246 itemClass);
247 return 0;
248 }
249
250 CFIndex strLen = CFStringGetLength(cfStr);
251 char *printName = (char *)malloc(strLen + 1);
252 if(!CFStringGetCString(cfStr, printName, strLen + 1, kCFStringEncodingASCII)) {
253 printf("***Error converting %s name to ASCII\n", itemClass);
254 return 0;
255 }
256 CFRelease(cfStr);
257
258 char *aliasCStr = NULL;
259 if((itemId == SecCertificateGetTypeID())) {
260 /* the alias attr, for cert email */
261 CFStringRef aliasCFStr = NULL;
262 nameAttr = kSecAlias;
263 attrInfo.count = 1;
264 attrInfo.tag = &nameAttr;
265 attrInfo.format = NULL; // ???
266 attrList = NULL;
267
268 ortn = SecKeychainItemCopyAttributesAndData(
269 item,
270 &attrInfo,
271 NULL, // itemClass
272 &attrList,
273 NULL, // don't need the data
274 NULL);
275 if(ortn) {
276 printOsError("SecKeychainItemCopyAttributesAndData", ortn);
277 return 0;
278 }
279 if(attrList->count != 1) {
280 printf("***Unexpected attribute count (%u) for Alias\n",
281 (unsigned)attrList->count);
282 return 0;
283 }
284 attr = attrList->attr;
285
286 /* it's a UTF8 string: use CFString to convert to C ASCII string */
287 aliasCFStr = CFStringCreateWithBytes(NULL,
288 (UInt8 *)attr->data, attr->length,
289 kCFStringEncodingUTF8, false);
290 if(aliasCFStr == NULL) {
291 printf("***Error converting Alias name to UTF CFSTring.\n");
292 return 0;
293 }
294
295 strLen = CFStringGetLength(aliasCFStr);
296 aliasCStr = (char *)malloc(strLen + 1);
297 if(!CFStringGetCString(aliasCFStr, aliasCStr, strLen + 1,
298 kCFStringEncodingASCII)) {
299 printf("***Error converting Alias name to ASCII\n");
300 return 0;
301 }
302 CFRelease(aliasCFStr);
303 }
304
305 int ourRtn = 0;
306 fpurge(stdin);
307 printf("Found %s\n", itemClass);
308 printf(" printable name : %s\n", printName);
309 if(aliasCStr != NULL) {
310 printf(" alias : %s\n", aliasCStr);
311 }
312 printf("Export (y/anything)? ");
313 char c = getchar();
314 if(c == 'y') {
315 CFArrayAppendValue(itemArray, item);
316 ourRtn = 1;
317 }
318 free(printName);
319 if(aliasCStr) {
320 free(aliasCStr);
321 }
322 return ourRtn;
323 }
324
325 int p12Export(
326 const char *pfxFile,
327 const char *kcName,
328 CFStringRef pwd, // explicit passphrase, mutually exclusive with...
329 bool usePassKey, // use SECURE_PASSPHRASE key
330 const char *kcPwd, // optional
331 bool noPrompt) // true --> export all
332 {
333 OSStatus ortn;
334 CSSM_KEY passKey;
335
336 /* set up a pkcs12 coder for export */
337 SecPkcs12CoderRef coder;
338 ortn = SecPkcs12CoderCreate(&coder);
339 if(ortn) {
340 printOsError("SecPkcs12CoderCreate", ortn);
341 return ortn;
342 }
343
344 /*
345 Ê* Since we're not providing the SecPkcs12CoderRef with a
346 * keychain, we have to provide the CSPDL handle
347 */
348 CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_FALSE);
349 if(cspHand == 0) {
350 printf("***Error attaching to CSPDL. Aborting.\n");
351 return 1;
352 }
353
354 if(usePassKey) {
355 ortn = p12GetPassKey(cspHand, GPK_Encode, false, &passKey);
356 if(ortn) {
357 return ortn;
358 }
359 ortn = SecPkcs12SetMACPassKey(coder, &passKey);
360 if(ortn) {
361 printOsError("SecPkcs12SetMACPassKey", ortn);
362 return ortn;
363 }
364 }
365 else {
366 ortn = SecPkcs12SetMACPassphrase(coder, pwd);
367 if(ortn) {
368 printOsError("SecPkcs12SetMACPassphrase", ortn);
369 return ortn;
370 }
371 }
372
373 ortn = SecPkcs12SetCspHandle(coder, cspHand);
374 if(ortn) {
375 printOsError("SecPkcs12SetCspHandle", ortn);
376 return ortn;
377 }
378
379 /* the array of things we want to export */
380 CFMutableArrayRef items = CFArrayCreateMutable(NULL, 0, NULL);
381
382 /* export from keychain specified by kcName */
383 SecKeychainRef kcRef = NULL;
384 ortn = SecKeychainOpen(kcName, &kcRef);
385 if(ortn) {
386 printOsError("SecKeychainOpen", ortn);
387 return ortn;
388 }
389
390 if(kcPwd) {
391 ortn = SecKeychainUnlock(kcRef, strlen(kcPwd), (void *)kcPwd, true);
392 if(ortn) {
393 printOsError("SecKeychainUnlock", ortn);
394 }
395 }
396
397 /*
398 * Prompt user for each known item - it would be nice if we
399 * could search for anything, eh?
400 * Certs first...
401 */
402 SecKeychainSearchRef srchRef;
403 ortn = SecKeychainSearchCreateFromAttributes(kcRef,
404 kSecCertificateItemClass,
405 NULL, // no attrs
406 &srchRef);
407 if(ortn) {
408 printOsError("SecKeychainSearchCreateFromAttributes", ortn);
409 return ortn;
410 }
411 int exported = 0;
412 for(;;) {
413 SecKeychainItemRef certRef;
414 ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
415 if(ortn) {
416 break;
417 }
418 exported += p12AddExportedItem(certRef, items, noPrompt);
419 }
420 CFRelease(srchRef);
421
422 /* now private keys */
423 ortn = SecKeychainSearchCreateFromAttributes(kcRef,
424 CSSM_DL_DB_RECORD_PRIVATE_KEY, // undocumented
425 NULL, // no attrs
426 &srchRef);
427 if(ortn) {
428 printOsError("SecKeychainSearchCreateFromAttributes", ortn);
429 return ortn;
430 }
431 for(;;) {
432 SecKeychainItemRef keyRef;
433 ortn = SecKeychainSearchCopyNext(srchRef, &keyRef);
434 if(ortn) {
435 break;
436 }
437 exported += p12AddExportedItem(keyRef, items, noPrompt);
438 }
439
440 if(exported == 0) {
441 printf("...Hmmm, no items to export. Done.\n");
442 return 0;
443 }
444 ortn = SecPkcs12ExportKeychainItems(coder, items);
445 if(ortn) {
446 printOsError("SecPkcs12ExportKeychainItems", ortn);
447 return ortn;
448 }
449
450 /* go */
451 CFDataRef pfx;
452 ortn = SecPkcs12Encode(coder, &pfx);
453 if(ortn) {
454 printOsError("SecPkcs12ExportKeychainItems", ortn);
455 return ortn;
456 }
457
458 if(writeFile(pfxFile, CFDataGetBytePtr(pfx),
459 CFDataGetLength(pfx))) {
460 printf("***Error writing pfx to %s\n", pfxFile);
461 return 1;
462 }
463 printf("...%u items exported; %ld bytes written to %s\n",
464 exported, CFDataGetLength(pfx), pfxFile);
465
466 /* cleanup */
467 SecPkcs12CoderRelease(coder);
468 CFRelease(pfx);
469 CFRelease(srchRef);
470 CFRelease(kcRef);
471 return 0;
472 }