2 * dotMacArchive.cpp - test and demonstrate use of dotmacp_tp.bundle to
3 * manipulate Identity archives ont he .mac server.
5 #include <Security/Security.h>
6 #include <Security/SecImportExport.h>
7 #include <Security/SecCertificateRequest.h>
8 //#include <security_dotmac_tp/dotMacTp.h>
10 #include "identSearch.h"
11 #include "dotMacTpAttach.h"
13 #include <security_cdsa_utils/cuCdsaUtils.h>
14 #include <security_cdsa_utils/cuFileIo.h>
15 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
18 * Defaults for the test setup du jour
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"
35 static void usage(char **argv
)
37 printf("usage: %s op [options]\n", argv
[0]);
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");
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",
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");
57 /* print a string in the form of a CSSM_DATA */
58 static void printString(
61 for(unsigned dex
=0; dex
<str
->Length
; dex
++) {
62 printf("%c", str
->Data
[dex
]);
68 * Post a .mac archive request, with a small number of options.
70 static CSSM_RETURN
dotMacPostArchiveRequest(
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
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
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
;
94 CSSM_DATA refId
= {0, NULL
};
95 CSSM_FIELD policyField
;
96 const CSSM_OID
*opOid
= NULL
;
98 if((tpHand
== 0) || (userName
== NULL
) || (password
== NULL
)) {
99 printf("dotMacPostArchiveRequest: illegal common args\n");
104 if((numArchives
== NULL
) || (archives
== NULL
)) {
105 printf("dotMacPostArchiveRequest: illegal AO_List args\n");
108 opOid
= &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_LIST
;
111 if((archiveName
== NULL
) || (timeString
== NULL
) || (pfxIn
== NULL
)) {
112 printf("dotMacPostArchiveRequest: illegal AO_Store args\n");
115 opOid
= &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_STORE
;
118 if((archiveName
== NULL
) || (pfxOut
== NULL
)) {
119 printf("dotMacPostArchiveRequest: illegal AO_Fetch args\n");
122 opOid
= &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_FETCH
;
125 if(archiveName
== NULL
) {
126 printf("dotMacPostArchiveRequest: illegal AO_Remove args\n");
129 opOid
= &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_REMOVE
;
134 * The main job here is bundling up the arguments into a
135 * CSSM_APPLE_DOTMAC_TP_ARCHIVE_REQUEST
137 memset(&archReq
, 0, sizeof(archReq
));
138 archReq
.version
= CSSM_DOT_MAC_TP_ARCHIVE_REQ_VERSION
;
139 archReq
.userName
= *userName
;
140 archReq
.password
= *password
;
142 archReq
.archiveName
= *archiveName
;
145 archReq
.timeString
= *timeString
;
148 archReq
.pfx
= *pfxIn
;
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
;
160 reqSet
.NumberOfRequests
= 1;
161 reqSet
.Requests
= &archReq
;
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
;
170 crtn
= CSSM_TP_SubmitCredRequest (tpHand
,
172 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
, // CSSM_TP_AUTHORITY_REQUEST_TYPE
173 &reqSet
, // const CSSM_TP_REQUEST_SET *RequestInput,
175 &estTime
, // sint32 *EstimatedTime,
176 &refId
); // CSSM_DATA_PTR ReferenceIdentifier
178 cssmPerror("CSSM_TP_SubmitCredRequest", crtn
);
181 /* success: post-process */
184 *numArchives
= archReq
.numArchives
;
185 *archives
= archReq
.archives
;
190 *pfxOut
= archReq
.pfx
;
199 static void cStringToCssmData(
204 cdata
->Data
= (uint8
*)cstr
;
205 cdata
->Length
= strlen(cstr
);
213 int main(int argc
, char **argv
)
215 SecKeychainRef kcRef
= NULL
;
217 CSSM_TP_HANDLE tpHand
= 0;
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;
230 char *p12Phrase
= NULL
;
256 while ((arg
= getopt(argc
, argv
, "u:Z:n:k:H:Nlo:z:")) != -1) {
268 keychainName
= optarg
;
295 printf("Pausing for MallocDebug attach; CR to continue: ");
299 if(keychainName
!= NULL
) {
300 /* pick a keychain (optional) */
301 ortn
= SecKeychainOpen(keychainName
, &kcRef
);
303 cssmPerror("SecKeychainOpen", ortn
);
307 /* make sure it's there since a successful SecKeychainOpen proves nothing */
308 SecKeychainStatus kcStat
;
309 ortn
= SecKeychainGetStatus(kcRef
, &kcStat
);
311 cssmPerror("SecKeychainGetStatus", ortn
);
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
;
323 cStringToCssmData(userName
, &userNameData
);
324 cStringToCssmData(password
, &passwordData
);
325 cStringToCssmData(hostName
, &hostNameData
);
326 cStringToCssmData(archName
, &archNameData
);
328 /* time in seconds since the epoch, sprintf'd in base 10 */
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
);
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
;
346 /* Store op: get identity in p12 form */
348 CFStringRef cfPhrase
= NULL
;
350 /* Cert attribute - email address - contains the "@mac.com" */
352 strcpy(emailAddr
, userName
);
353 // nope strcat(emailAddr, "@mac.com");
355 /* find an identity for that email address */
356 SecIdentityRef idRef
= NULL
;
357 OSStatus ortn
= findIdentity(emailAddr
, strlen(emailAddr
), kcRef
, &idRef
);
359 printf("***Could not find an identity to store. Aborting.\n");
363 /* convert that identity to p12 */
364 SecKeyImportExportParameters keyParams
;
365 memset(&keyParams
, 0, sizeof(keyParams
));
366 keyParams
.version
= SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
;
368 cfPhrase
= CFStringCreateWithCString(NULL
, p12Phrase
,
369 kCFStringEncodingUTF8
);
370 keyParams
.passphrase
= cfPhrase
;
373 keyParams
.flags
= kSecKeySecurePassphrase
;
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
,
381 cssmPerror("SecKeychainItemExport", crtn
);
382 printf("***Error obtaining .mac identity in PKCS12 format. Aborting.\n");
386 pfxInData
.Data
= (uint8
*)CFDataGetBytePtr(p12
);
387 pfxInData
.Length
= CFDataGetLength(p12
);
388 printf("...preparing to store archive of %lu bytes\n", pfxInData
.Length
);
391 if(writeFile(outFile
, pfxInData
.Data
, pfxInData
.Length
)) {
392 printf("***Error writing P12 to %s\n", outFile
);
395 printf("...wrote %lu bytes to %s\n", pfxInData
.Length
, outFile
);
403 /* attach to the TP */
404 tpHand
= dotMacTpAttach();
406 printf("***Error attaching to .mac TP; aborting.\n");
412 crtn
= dotMacPostArchiveRequest(op
, tpHand
, &userNameData
, &passwordData
,
413 hostName
? &hostNameData
: NULL
,
421 printf("***Error performing archive request; aborting.\n");
425 /* post-request processing */
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
);
435 printString(&dmarch
->archiveName
);
439 printString(&dmarch
->timeString
);
442 /* now free what the TP allocated on our behalf */
443 APP_FREE(dmarch
->archiveName
.Data
);
444 APP_FREE(dmarch
->timeString
.Data
);
451 printf("=== archive \'%s\' backup complete ===\n", archName
);
455 bool didSomething
= false;
456 if(pfxOutData
.Length
== 0) {
457 printf("***Archive fetch claimed to succeed, but no data seen\n");
463 * OK, we have a blob of PKCS12 data. Import to keychain and/or write it
466 printf("=== %lu bytes of archive fetched ===\n", pfxOutData
.Length
);
468 if(writeFile(outFile
, pfxOutData
.Data
, pfxOutData
.Length
)) {
469 printf("***Error writing P12 to %s\n", outFile
);
472 printf("...wrote %lu bytes to %s\n", pfxOutData
.Length
, outFile
);
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
;
486 cfPhrase
= CFStringCreateWithCString(NULL
, p12Phrase
,
487 kCFStringEncodingUTF8
);
488 keyParams
.passphrase
= cfPhrase
;
491 keyParams
.flags
= kSecKeySecurePassphrase
;
493 keyParams
.alertTitle
= CFSTR(".mac Identity Restore");
494 keyParams
.alertPrompt
=
495 CFSTR("Enter passphrase for decrypting your .mac private key");
498 ortn
= SecKeychainItemImport(p12Data
,
499 NULL
, // filename - passing kSecFormatPKCS12 is definitely enough
501 NULL
, // itemType - import'll figure it out
502 0, // SecItemImportExportFlags
505 NULL
); // we don't want any items returned
507 cssmPerror("SecKeychainItemImport", ortn
);
508 printf("***Error importing p12 into keychain %s\n", keychainName
);
511 printf("...archive successfully imported into keychain %s\n",
520 printf("...note we got an archive from the server but didn't have a "
521 "place to put it.\n");
526 printf("=== Archive %s removed ===\n", archName
);
532 printf("Pausing at end of test for MallocDebug attach; CR to continue: ");
542 dotMacTpDetach(tpHand
);