]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/dotMacArchive/dotMacArchive.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / dotMacArchive / dotMacArchive.cpp
1 /*
2 * dotMacArchive.cpp - test and demonstrate use of dotmacp_tp.bundle to
3 * manipulate Identity archives ont he .mac server.
4 */
5 #include <Security/Security.h>
6 #include <Security/SecImportExport.h>
7 #include <Security/SecCertificateRequest.h>
8 //#include <security_dotmac_tp/dotMacTp.h>
9 #include <dotMacTp.h>
10 #include "identSearch.h"
11 #include "dotMacTpAttach.h"
12 #include <unistd.h>
13 #include <security_cdsa_utils/cuCdsaUtils.h>
14 #include <security_cdsa_utils/cuFileIo.h>
15 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
16
17 /*
18 * Defaults for the test setup du jour
19 */
20 #define USER_DEFAULT "dmitch_new"
21 #define PWD_DEFAULT "password"
22 #define ARCHIVE_NAME_DEFAULT "dmitch_new"
23 #define HOST_DEFAULT "certmgmt.mac.com"
24
25 /*
26 * Type of archive op
27 */
28 typedef enum {
29 AO_List,
30 AO_Store,
31 AO_Fetch,
32 AO_Remove
33 } ArchiveOp;
34
35 static void usage(char **argv)
36 {
37 printf("usage: %s op [options]\n", argv[0]);
38 printf("Op:\n");
39 printf(" l -- list archive contents\n");
40 printf(" s -- store archive\n");
41 printf(" f -- fetch archive\n");
42 printf(" r -- remove archive(s)\n");
43 printf("Options:\n");
44 printf(" -u username -- Default is %s\n", USER_DEFAULT);
45 printf(" -Z password -- default is %s\n", PWD_DEFAULT);
46 printf(" -n archiveName -- default is %s\n", ARCHIVE_NAME_DEFAULT);
47 printf(" -k keychain -- Source/destination of archive\n");
48 printf(" -H hostname -- Alternate .mac server host name (default %s)\n",
49 HOST_DEFAULT);
50 printf(" -o outFile -- write P12 blob to outFile\n");
51 printf(" -z p12Phrase -- PKCS12 passphrase (default is GUI prompt)\n");
52 printf(" -M -- Pause for MallocDebug\n");
53 printf(" -l -- loop\n");
54 exit(1);
55 }
56
57 /* print a string in the form of a CSSM_DATA */
58 static void printString(
59 const CSSM_DATA *str)
60 {
61 for(unsigned dex=0; dex<str->Length; dex++) {
62 printf("%c", str->Data[dex]);
63 }
64 }
65
66
67 /*
68 * Post a .mac archive request, with a small number of options.
69 */
70 static CSSM_RETURN dotMacPostArchiveRequest(
71 ArchiveOp op,
72 CSSM_TP_HANDLE tpHand,
73 /* required fields for all ops */
74 const CSSM_DATA *userName, // REQUIRED, C string
75 const CSSM_DATA *password, // REQUIRED, C string
76
77 /* optional (per op, that is...) fields */
78 const CSSM_DATA *hostName, // optional alternate host
79 const CSSM_DATA *archiveName, // required for store, fetch, remove
80 const CSSM_DATA *timeString, // required for store
81 const CSSM_DATA *pfxIn, // required for store
82 CSSM_DATA *pfxOut, // required and RETURNED for fetch
83 unsigned *numArchives, // required and RETURNED for list
84 DotMacArchive **archives) // required and RETURNED for list
85 {
86 CSSM_RETURN crtn;
87 CSSM_TP_AUTHORITY_ID tpAuthority;
88 CSSM_TP_AUTHORITY_ID *tpAuthPtr = NULL;
89 CSSM_NET_ADDRESS tpNetAddrs;
90 CSSM_APPLE_DOTMAC_TP_ARCHIVE_REQUEST archReq;
91 CSSM_TP_REQUEST_SET reqSet;
92 CSSM_TP_CALLERAUTH_CONTEXT callerAuth;
93 sint32 estTime;
94 CSSM_DATA refId = {0, NULL};
95 CSSM_FIELD policyField;
96 const CSSM_OID *opOid = NULL;
97
98 if((tpHand == 0) || (userName == NULL) || (password == NULL)) {
99 printf("dotMacPostArchiveRequest: illegal common args\n");
100 return paramErr;
101 }
102 switch(op) {
103 case AO_List:
104 if((numArchives == NULL) || (archives == NULL)) {
105 printf("dotMacPostArchiveRequest: illegal AO_List args\n");
106 return paramErr;
107 }
108 opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_LIST;
109 break;
110 case AO_Store:
111 if((archiveName == NULL) || (timeString == NULL) || (pfxIn == NULL)) {
112 printf("dotMacPostArchiveRequest: illegal AO_Store args\n");
113 return paramErr;
114 }
115 opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_STORE;
116 break;
117 case AO_Fetch:
118 if((archiveName == NULL) || (pfxOut == NULL)) {
119 printf("dotMacPostArchiveRequest: illegal AO_Fetch args\n");
120 return paramErr;
121 }
122 opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_FETCH;
123 break;
124 case AO_Remove:
125 if(archiveName == NULL) {
126 printf("dotMacPostArchiveRequest: illegal AO_Remove args\n");
127 return paramErr;
128 }
129 opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_REMOVE;
130 break;
131 }
132
133 /*
134 * The main job here is bundling up the arguments into a
135 * CSSM_APPLE_DOTMAC_TP_ARCHIVE_REQUEST
136 */
137 memset(&archReq, 0, sizeof(archReq));
138 archReq.version = CSSM_DOT_MAC_TP_ARCHIVE_REQ_VERSION;
139 archReq.userName = *userName;
140 archReq.password = *password;
141 if(archiveName) {
142 archReq.archiveName = *archiveName;
143 }
144 if(timeString) {
145 archReq.timeString = *timeString;
146 }
147 if(pfxIn) {
148 archReq.pfx = *pfxIn;
149 }
150
151 /* remaining arguments for TP call... */
152 if((hostName != NULL) && (hostName->Data != NULL)) {
153 tpAuthority.AuthorityCert = NULL;
154 tpAuthority.AuthorityLocation = &tpNetAddrs;
155 tpNetAddrs.AddressType = CSSM_ADDR_NAME;
156 tpNetAddrs.Address = *hostName;
157 tpAuthPtr = &tpAuthority;
158 }
159
160 reqSet.NumberOfRequests = 1;
161 reqSet.Requests = &archReq;
162
163 policyField.FieldOid = *opOid;
164 policyField.FieldValue.Data = NULL;
165 policyField.FieldValue.Length = 0;
166 memset(&callerAuth, 0, sizeof(callerAuth));
167 callerAuth.Policy.NumberOfPolicyIds = 1;
168 callerAuth.Policy.PolicyIds = &policyField;
169
170 crtn = CSSM_TP_SubmitCredRequest (tpHand,
171 tpAuthPtr,
172 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, // CSSM_TP_AUTHORITY_REQUEST_TYPE
173 &reqSet, // const CSSM_TP_REQUEST_SET *RequestInput,
174 &callerAuth,
175 &estTime, // sint32 *EstimatedTime,
176 &refId); // CSSM_DATA_PTR ReferenceIdentifier
177 if(crtn) {
178 cssmPerror("CSSM_TP_SubmitCredRequest", crtn);
179 }
180
181 /* success: post-process */
182 switch(op) {
183 case AO_List:
184 *numArchives = archReq.numArchives;
185 *archives = archReq.archives;
186 break;
187 case AO_Store:
188 break;
189 case AO_Fetch:
190 *pfxOut = archReq.pfx;
191 break;
192 case AO_Remove:
193 break;
194 }
195
196 return CSSM_OK;
197 }
198
199 static void cStringToCssmData(
200 const char *cstr,
201 CSSM_DATA *cdata)
202 {
203 if(cstr) {
204 cdata->Data = (uint8 *)cstr;
205 cdata->Length = strlen(cstr);
206 }
207 else {
208 cdata->Data = NULL;
209 cdata->Length = 0;
210 }
211 }
212
213 int main(int argc, char **argv)
214 {
215 SecKeychainRef kcRef = NULL;
216 CSSM_RETURN crtn;
217 CSSM_TP_HANDLE tpHand = 0;
218 OSStatus ortn;
219
220 /* user-spec'd variables */
221 ArchiveOp op = AO_List;
222 char *keychainName = NULL;
223 const char *userName = USER_DEFAULT;
224 const char *password = PWD_DEFAULT;
225 const char *archName = ARCHIVE_NAME_DEFAULT;
226 const char *hostName = HOST_DEFAULT;
227 char *outFile = NULL;
228 bool doPause = false;
229 bool loop = false;
230 char *p12Phrase = NULL;
231
232 if(argc < 2) {
233 usage(argv);
234 }
235 switch(argv[1][0]) {
236 case 'l':
237 op = AO_List;
238 break;
239 case 's':
240 op = AO_Store;
241 break;
242 case 'f':
243 op = AO_Fetch;
244 break;
245 case 'r':
246 op = AO_Remove;
247 break;
248 default:
249 usage(argv);
250 }
251
252 extern char *optarg;
253 extern int optind;
254 optind = 2;
255 int arg;
256 while ((arg = getopt(argc, argv, "u:Z:n:k:H:Nlo:z:")) != -1) {
257 switch (arg) {
258 case 'u':
259 userName = optarg;
260 break;
261 case 'Z':
262 password = optarg;
263 break;
264 case 'n':
265 archName = optarg;
266 break;
267 case 'k':
268 keychainName = optarg;
269 break;
270 case 'M':
271 doPause = true;
272 break;
273 case 'H':
274 hostName = optarg;
275 break;
276 case 'l':
277 loop = true;
278 break;
279 case 'o':
280 outFile = optarg;
281 break;
282 case 'z':
283 p12Phrase = optarg;
284 break;
285 case 'h':
286 usage(argv);
287 }
288 }
289 if(optind != argc) {
290 usage(argv);
291 }
292
293 if(doPause) {
294 fpurge(stdin);
295 printf("Pausing for MallocDebug attach; CR to continue: ");
296 getchar();
297 }
298
299 if(keychainName != NULL) {
300 /* pick a keychain (optional) */
301 ortn = SecKeychainOpen(keychainName, &kcRef);
302 if(ortn) {
303 cssmPerror("SecKeychainOpen", ortn);
304 exit(1);
305 }
306
307 /* make sure it's there since a successful SecKeychainOpen proves nothing */
308 SecKeychainStatus kcStat;
309 ortn = SecKeychainGetStatus(kcRef, &kcStat);
310 if(ortn) {
311 cssmPerror("SecKeychainGetStatus", ortn);
312 exit(1);
313 }
314 }
315
316 /* bundle up our crufty C string args into CSSM_DATAs needed at the TP SPI */
317 CSSM_DATA userNameData;
318 CSSM_DATA passwordData;
319 CSSM_DATA hostNameData;
320 CSSM_DATA archNameData;
321 CSSM_DATA timeStringData;
322
323 cStringToCssmData(userName, &userNameData);
324 cStringToCssmData(password, &passwordData);
325 cStringToCssmData(hostName, &hostNameData);
326 cStringToCssmData(archName, &archNameData);
327
328 /* time in seconds since the epoch, sprintf'd in base 10 */
329 char timeStr[20];
330 time_t nowTime = time(NULL);
331 printf("...nowTime = %lu\n", nowTime);
332 //nowTime += (60 * 60 * 24 * 26); // fails
333 nowTime += (60 * 60 * 24 * 25); // works
334 printf("...expirationTime = %lu\n", nowTime);
335 sprintf(timeStr, "%lu", nowTime);
336 timeStringData.Data = (uint8 *)timeStr;
337 timeStringData.Length = strlen(timeStr);
338
339 /* other data needed by dotMacPostArchiveRequest() */
340 CFDataRef p12 = NULL;
341 CSSM_DATA pfxInData = {0, NULL};
342 CSSM_DATA pfxOutData = {0, NULL};
343 unsigned numArchives = 0;
344 DotMacArchive *archives = NULL;
345
346 /* Store op: get identity in p12 form */
347 if(op == AO_Store) {
348 CFStringRef cfPhrase = NULL;
349
350 /* Cert attribute - email address - contains the "@mac.com" */
351 char emailAddr[500];
352 strcpy(emailAddr, userName);
353 // nope strcat(emailAddr, "@mac.com");
354
355 /* find an identity for that email address */
356 SecIdentityRef idRef = NULL;
357 OSStatus ortn = findIdentity(emailAddr, strlen(emailAddr), kcRef, &idRef);
358 if(ortn) {
359 printf("***Could not find an identity to store. Aborting.\n");
360 goto errOut;
361 }
362
363 /* convert that identity to p12 */
364 SecKeyImportExportParameters keyParams;
365 memset(&keyParams, 0, sizeof(keyParams));
366 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
367 if(p12Phrase) {
368 cfPhrase = CFStringCreateWithCString(NULL, p12Phrase,
369 kCFStringEncodingUTF8);
370 keyParams.passphrase = cfPhrase;
371 }
372 else {
373 keyParams.flags = kSecKeySecurePassphrase;
374 }
375 keyParams.alertTitle = CFSTR(".mac Identity Backup");
376 keyParams.alertPrompt =
377 CFSTR("Enter passphrase for encrypting your .mac private key");
378 ortn = SecKeychainItemExport(idRef, kSecFormatPKCS12, kSecItemPemArmour,
379 &keyParams, &p12);
380 if(ortn) {
381 cssmPerror("SecKeychainItemExport", crtn);
382 printf("***Error obtaining .mac identity in PKCS12 format. Aborting.\n");
383 goto errOut;
384 }
385
386 pfxInData.Data = (uint8 *)CFDataGetBytePtr(p12);
387 pfxInData.Length = CFDataGetLength(p12);
388 printf("...preparing to store archive of %lu bytes\n", pfxInData.Length);
389
390 if(outFile) {
391 if(writeFile(outFile, pfxInData.Data, pfxInData.Length)) {
392 printf("***Error writing P12 to %s\n", outFile);
393 }
394 else {
395 printf("...wrote %lu bytes to %s\n", pfxInData.Length, outFile);
396 }
397 }
398 if(cfPhrase) {
399 CFRelease(cfPhrase);
400 }
401 }
402
403 /* attach to the TP */
404 tpHand = dotMacTpAttach();
405 if(tpHand == 0) {
406 printf("***Error attaching to .mac TP; aborting.\n");
407 ortn = -1;
408 goto errOut;
409 }
410
411 /* go */
412 crtn = dotMacPostArchiveRequest(op, tpHand, &userNameData, &passwordData,
413 hostName ? &hostNameData : NULL,
414 &archNameData,
415 &timeStringData,
416 &pfxInData,
417 &pfxOutData,
418 &numArchives,
419 &archives);
420 if(crtn) {
421 printf("***Error performing archive request; aborting.\n");
422 goto errOut;
423 }
424
425 /* post-request processing */
426
427 switch(op) {
428 case AO_List:
429 {
430 printf("=== List request complete; numArchives = %u ===\n", numArchives);
431 for(unsigned dex=0; dex<numArchives; dex++) {
432 DotMacArchive *dmarch = &archives[dex];
433 printf("Archive %u:\n", dex);
434 printf(" name : ");
435 printString(&dmarch->archiveName);
436 printf("\n");
437
438 printf(" time : ");
439 printString(&dmarch->timeString);
440 printf("\n");
441
442 /* now free what the TP allocated on our behalf */
443 APP_FREE(dmarch->archiveName.Data);
444 APP_FREE(dmarch->timeString.Data);
445 }
446 APP_FREE(archives);
447 break;
448 }
449
450 case AO_Store:
451 printf("=== archive \'%s\' backup complete ===\n", archName);
452 break;
453 case AO_Fetch:
454 {
455 bool didSomething = false;
456 if(pfxOutData.Length == 0) {
457 printf("***Archive fetch claimed to succeed, but no data seen\n");
458 ortn = -1;
459 goto errOut;
460 }
461
462 /*
463 * OK, we have a blob of PKCS12 data. Import to keychain and/or write it
464 * to a file.
465 */
466 printf("=== %lu bytes of archive fetched ===\n", pfxOutData.Length);
467 if(outFile) {
468 if(writeFile(outFile, pfxOutData.Data, pfxOutData.Length)) {
469 printf("***Error writing P12 to %s\n", outFile);
470 }
471 else {
472 printf("...wrote %lu bytes to %s\n", pfxOutData.Length, outFile);
473 didSomething = true;
474 }
475 }
476 if(kcRef) {
477 /* Note we avoid importing to default keychain - user must really want
478 * to perform this step */
479 CFDataRef p12Data = CFDataCreate(NULL, pfxOutData.Data, pfxOutData.Length);
480 SecExternalFormat extForm = kSecFormatPKCS12;
481 SecKeyImportExportParameters keyParams;
482 memset(&keyParams, 0, sizeof(keyParams));
483 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
484 CFStringRef cfPhrase = NULL;
485 if(p12Phrase) {
486 cfPhrase = CFStringCreateWithCString(NULL, p12Phrase,
487 kCFStringEncodingUTF8);
488 keyParams.passphrase = cfPhrase;
489 }
490 else {
491 keyParams.flags = kSecKeySecurePassphrase;
492 }
493 keyParams.alertTitle = CFSTR(".mac Identity Restore");
494 keyParams.alertPrompt =
495 CFSTR("Enter passphrase for decrypting your .mac private key");
496
497 /* go... */
498 ortn = SecKeychainItemImport(p12Data,
499 NULL, // filename - passing kSecFormatPKCS12 is definitely enough
500 &extForm,
501 NULL, // itemType - import'll figure it out
502 0, // SecItemImportExportFlags
503 &keyParams,
504 kcRef,
505 NULL); // we don't want any items returned
506 if(ortn) {
507 cssmPerror("SecKeychainItemImport", ortn);
508 printf("***Error importing p12 into keychain %s\n", keychainName);
509 }
510 else {
511 printf("...archive successfully imported into keychain %s\n",
512 keychainName);
513 didSomething = true;
514 }
515 if(cfPhrase) {
516 CFRelease(cfPhrase);
517 }
518 }
519 if(!didSomething) {
520 printf("...note we got an archive from the server but didn't have a "
521 "place to put it.\n");
522 }
523 break;
524 }
525 case AO_Remove:
526 printf("=== Archive %s removed ===\n", archName);
527 break;
528 }
529
530 if(doPause) {
531 fpurge(stdin);
532 printf("Pausing at end of test for MallocDebug attach; CR to continue: ");
533 getchar();
534 }
535
536 errOut:
537 if(kcRef) {
538 CFRelease(kcRef);
539 }
540
541 if(tpHand) {
542 dotMacTpDetach(tpHand);
543 }
544 return ortn;
545 }
546