]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/dotMacArchive/dotMacArchive.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / dotMacArchive / dotMacArchive.cpp
diff --git a/SecurityTests/clxutils/dotMacArchive/dotMacArchive.cpp b/SecurityTests/clxutils/dotMacArchive/dotMacArchive.cpp
new file mode 100644 (file)
index 0000000..2b46fd4
--- /dev/null
@@ -0,0 +1,546 @@
+/* 
+ * dotMacArchive.cpp - test and demonstrate use of dotmacp_tp.bundle to
+ * manipulate Identity archives ont he .mac server. 
+ */
+#include <Security/Security.h>
+#include <Security/SecImportExport.h>
+#include <Security/SecCertificateRequest.h>
+//#include <security_dotmac_tp/dotMacTp.h>
+#include <dotMacTp.h>
+#include "identSearch.h"
+#include "dotMacTpAttach.h"
+#include <unistd.h>
+#include <security_cdsa_utils/cuCdsaUtils.h>
+#include <security_cdsa_utils/cuFileIo.h>
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+
+/*
+ * Defaults for the test setup du jour 
+ */
+#define USER_DEFAULT                   "dmitch_new"
+#define PWD_DEFAULT                            "password"
+#define ARCHIVE_NAME_DEFAULT   "dmitch_new"
+#define HOST_DEFAULT                   "certmgmt.mac.com"
+
+/* 
+ * Type of archive op
+ */
+typedef enum {
+       AO_List,
+       AO_Store,
+       AO_Fetch,
+       AO_Remove
+} ArchiveOp;
+
+static void usage(char **argv)
+{
+       printf("usage: %s op [options]\n", argv[0]);
+       printf("Op:\n");
+       printf("    l              -- list archive contents\n");
+       printf("    s              -- store archive\n");
+       printf("    f              -- fetch archive\n");
+       printf("    r              -- remove archive(s)\n");
+       printf("Options:\n");
+       printf("   -u username     -- Default is %s\n", USER_DEFAULT);
+       printf("   -Z password     -- default is %s\n", PWD_DEFAULT);
+       printf("   -n archiveName  -- default is %s\n", ARCHIVE_NAME_DEFAULT);
+       printf("   -k keychain     -- Source/destination of archive\n");
+       printf("   -H hostname     -- Alternate .mac server host name (default %s)\n",
+                                                                       HOST_DEFAULT);
+       printf("   -o outFile      -- write P12 blob to outFile\n");
+       printf("   -z p12Phrase    -- PKCS12 passphrase (default is GUI prompt)\n");
+       printf("   -M              -- Pause for MallocDebug\n");
+       printf("   -l              -- loop\n");
+       exit(1);
+}
+
+/* print a string in the form of a CSSM_DATA */
+static void printString(
+       const CSSM_DATA *str)
+{
+       for(unsigned dex=0; dex<str->Length; dex++) {
+               printf("%c", str->Data[dex]);
+       }
+}
+
+
+/* 
+ * Post a .mac archive request, with a small number of options. 
+ */
+static CSSM_RETURN dotMacPostArchiveRequest(
+       ArchiveOp                       op,
+       CSSM_TP_HANDLE          tpHand,
+       /* required fields for all ops */
+       const CSSM_DATA         *userName,              // REQUIRED, C string
+       const CSSM_DATA         *password,              // REQUIRED, C string
+       
+       /* optional (per op, that is...) fields */
+       const CSSM_DATA         *hostName,              // optional alternate host 
+       const CSSM_DATA         *archiveName,   // required for store, fetch, remove
+       const CSSM_DATA         *timeString,    // required for store
+       const CSSM_DATA         *pfxIn,                 // required for store
+       CSSM_DATA                       *pfxOut,                // required and RETURNED for fetch
+       unsigned                        *numArchives,   // required and RETURNED for list
+       DotMacArchive           **archives)             // required and RETURNED for list
+{
+       CSSM_RETURN                                     crtn;
+       CSSM_TP_AUTHORITY_ID            tpAuthority;
+       CSSM_TP_AUTHORITY_ID            *tpAuthPtr = NULL;
+       CSSM_NET_ADDRESS                        tpNetAddrs;
+       CSSM_APPLE_DOTMAC_TP_ARCHIVE_REQUEST    archReq;
+       CSSM_TP_REQUEST_SET                     reqSet;
+       CSSM_TP_CALLERAUTH_CONTEXT      callerAuth;
+       sint32                                          estTime;
+       CSSM_DATA                                       refId = {0, NULL};
+       CSSM_FIELD                                      policyField;
+       const CSSM_OID                          *opOid = NULL;
+       
+       if((tpHand == 0) || (userName == NULL) || (password == NULL)) {
+               printf("dotMacPostArchiveRequest: illegal common args\n");
+               return paramErr;
+       }
+       switch(op) {
+               case AO_List:
+                       if((numArchives == NULL) || (archives == NULL)) {
+                               printf("dotMacPostArchiveRequest: illegal AO_List args\n");
+                               return paramErr;
+                       }
+                       opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_LIST;
+                       break;
+               case AO_Store:
+                       if((archiveName == NULL) || (timeString == NULL) || (pfxIn == NULL)) {
+                               printf("dotMacPostArchiveRequest: illegal AO_Store args\n");
+                               return paramErr;
+                       }
+                       opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_STORE;
+                       break;
+               case AO_Fetch:
+                       if((archiveName == NULL) || (pfxOut == NULL)) {
+                               printf("dotMacPostArchiveRequest: illegal AO_Fetch args\n");
+                               return paramErr;
+                       }
+                       opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_FETCH;
+                       break;
+               case AO_Remove:
+                       if(archiveName == NULL) {
+                               printf("dotMacPostArchiveRequest: illegal AO_Remove args\n");
+                               return paramErr;
+                       }
+                       opOid = &CSSMOID_DOTMAC_CERT_REQ_ARCHIVE_REMOVE;
+                       break;
+       }
+       
+       /* 
+        * The main job here is bundling up the arguments into a
+        * CSSM_APPLE_DOTMAC_TP_ARCHIVE_REQUEST 
+        */
+       memset(&archReq, 0, sizeof(archReq));
+       archReq.version = CSSM_DOT_MAC_TP_ARCHIVE_REQ_VERSION;
+       archReq.userName = *userName;
+       archReq.password = *password;
+       if(archiveName) {
+               archReq.archiveName = *archiveName;
+       }
+       if(timeString) {
+               archReq.timeString = *timeString;
+       }
+       if(pfxIn) {
+               archReq.pfx = *pfxIn;
+       }
+       
+       /* remaining arguments for TP call... */
+       if((hostName != NULL) && (hostName->Data != NULL)) {
+               tpAuthority.AuthorityCert = NULL;
+               tpAuthority.AuthorityLocation = &tpNetAddrs;
+               tpNetAddrs.AddressType = CSSM_ADDR_NAME;
+               tpNetAddrs.Address = *hostName;
+               tpAuthPtr = &tpAuthority;
+       }
+
+       reqSet.NumberOfRequests = 1;
+       reqSet.Requests = &archReq;
+       
+       policyField.FieldOid = *opOid;
+       policyField.FieldValue.Data = NULL;
+       policyField.FieldValue.Length = 0;
+       memset(&callerAuth, 0, sizeof(callerAuth));
+       callerAuth.Policy.NumberOfPolicyIds = 1;
+       callerAuth.Policy.PolicyIds = &policyField;
+
+       crtn = CSSM_TP_SubmitCredRequest (tpHand,
+               tpAuthPtr,              
+               CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,    // CSSM_TP_AUTHORITY_REQUEST_TYPE 
+               &reqSet,        // const CSSM_TP_REQUEST_SET *RequestInput,
+               &callerAuth,
+               &estTime,   // sint32 *EstimatedTime,
+               &refId);        // CSSM_DATA_PTR ReferenceIdentifier
+       if(crtn) {
+               cssmPerror("CSSM_TP_SubmitCredRequest", crtn);
+       }
+       
+       /* success: post-process */
+       switch(op) {
+               case AO_List:
+                       *numArchives = archReq.numArchives;
+                       *archives = archReq.archives;
+                       break;
+               case AO_Store:
+                       break;
+               case AO_Fetch:
+                       *pfxOut = archReq.pfx;
+                       break;
+               case AO_Remove:
+                       break;
+       }
+
+       return CSSM_OK;
+}
+
+static void cStringToCssmData(
+       const char      *cstr,
+       CSSM_DATA       *cdata)
+{
+       if(cstr) {
+               cdata->Data = (uint8 *)cstr;
+               cdata->Length = strlen(cstr);
+       }
+       else {
+               cdata->Data = NULL;
+               cdata->Length = 0;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       SecKeychainRef  kcRef = NULL;
+       CSSM_RETURN             crtn;
+       CSSM_TP_HANDLE  tpHand = 0;
+       OSStatus                ortn;
+       
+       /* user-spec'd variables */
+       ArchiveOp               op = AO_List;
+       char                    *keychainName = NULL;
+       const char              *userName = USER_DEFAULT;
+       const char              *password = PWD_DEFAULT;
+       const char              *archName = ARCHIVE_NAME_DEFAULT;
+       const char              *hostName = HOST_DEFAULT;
+       char                    *outFile = NULL;
+       bool                    doPause = false;
+       bool                    loop = false;
+       char                    *p12Phrase = NULL;
+       
+       if(argc < 2) {
+               usage(argv);
+       }
+       switch(argv[1][0]) {
+               case 'l':
+                       op = AO_List;
+                       break;
+               case 's':
+                       op = AO_Store;
+                       break;
+               case 'f':
+                       op = AO_Fetch;
+                       break;
+               case 'r':
+                       op = AO_Remove;
+                       break;
+               default:
+                       usage(argv);
+       }
+
+       extern char *optarg;
+       extern int optind;
+       optind = 2;
+       int arg;
+       while ((arg = getopt(argc, argv, "u:Z:n:k:H:Nlo:z:")) != -1) {
+               switch (arg) {
+                       case 'u':
+                               userName = optarg;
+                               break;
+                       case 'Z':
+                               password = optarg;
+                               break;
+                       case 'n':
+                               archName = optarg;
+                               break;
+                       case 'k':
+                               keychainName = optarg;
+                               break;
+                       case 'M':
+                               doPause = true;
+                               break;
+                       case 'H':
+                               hostName = optarg;
+                               break;
+                       case 'l':
+                               loop = true;
+                               break;
+                       case 'o':
+                               outFile = optarg;
+                               break;
+                       case 'z':
+                               p12Phrase = optarg;
+                               break;
+                       case 'h':
+                               usage(argv);
+               }
+       }
+       if(optind != argc) {
+               usage(argv);
+       }
+       
+       if(doPause) {
+               fpurge(stdin);
+               printf("Pausing for MallocDebug attach; CR to continue: ");
+               getchar();
+       }
+       
+       if(keychainName != NULL) {
+               /* pick a keychain (optional) */
+               ortn = SecKeychainOpen(keychainName, &kcRef);
+               if(ortn) {
+                       cssmPerror("SecKeychainOpen", ortn);
+                       exit(1);
+               }
+               
+               /* make sure it's there since a successful SecKeychainOpen proves nothing */
+               SecKeychainStatus kcStat;
+               ortn = SecKeychainGetStatus(kcRef, &kcStat);
+               if(ortn) {
+                       cssmPerror("SecKeychainGetStatus", ortn);
+                       exit(1);
+               }
+       }
+       
+       /* bundle up our crufty C string args into CSSM_DATAs needed at the TP SPI */
+       CSSM_DATA userNameData;
+       CSSM_DATA passwordData;
+       CSSM_DATA hostNameData;
+       CSSM_DATA archNameData;
+       CSSM_DATA timeStringData;
+       
+       cStringToCssmData(userName, &userNameData);
+       cStringToCssmData(password, &passwordData);
+       cStringToCssmData(hostName, &hostNameData);
+       cStringToCssmData(archName, &archNameData);
+       
+       /* time in seconds since the epoch, sprintf'd in base 10 */
+       char timeStr[20];
+       time_t nowTime = time(NULL);
+       printf("...nowTime = %lu\n", nowTime);
+       //nowTime += (60 * 60 * 24 * 26);       // fails
+       nowTime += (60 * 60 * 24 * 25);         // works
+       printf("...expirationTime = %lu\n", nowTime);
+       sprintf(timeStr, "%lu", nowTime);
+       timeStringData.Data = (uint8 *)timeStr;
+       timeStringData.Length = strlen(timeStr);
+       
+       /* other data needed by dotMacPostArchiveRequest() */
+       CFDataRef               p12 = NULL;
+       CSSM_DATA               pfxInData = {0, NULL};
+       CSSM_DATA               pfxOutData = {0, NULL};
+       unsigned                numArchives = 0;
+       DotMacArchive   *archives = NULL;       
+       
+       /* Store op: get identity in p12 form */
+       if(op == AO_Store) {
+               CFStringRef cfPhrase = NULL;
+
+               /* Cert attribute - email address - contains the "@mac.com" */
+               char emailAddr[500];
+               strcpy(emailAddr, userName);
+               // nope strcat(emailAddr, "@mac.com");
+               
+               /* find an identity for that email address */
+               SecIdentityRef idRef = NULL;
+               OSStatus ortn = findIdentity(emailAddr, strlen(emailAddr), kcRef, &idRef);
+               if(ortn) {
+                       printf("***Could not find an identity to store. Aborting.\n");
+                       goto errOut;
+               }
+               
+               /* convert that identity to p12 */
+               SecKeyImportExportParameters keyParams;
+               memset(&keyParams, 0, sizeof(keyParams));
+               keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+               if(p12Phrase) {
+                       cfPhrase = CFStringCreateWithCString(NULL, p12Phrase, 
+                               kCFStringEncodingUTF8);
+                       keyParams.passphrase = cfPhrase;
+               }
+               else {
+                       keyParams.flags = kSecKeySecurePassphrase;
+               }
+               keyParams.alertTitle = CFSTR(".mac Identity Backup");
+               keyParams.alertPrompt = 
+                       CFSTR("Enter passphrase for encrypting your .mac private key");
+               ortn = SecKeychainItemExport(idRef, kSecFormatPKCS12, kSecItemPemArmour, 
+                       &keyParams, &p12);
+               if(ortn) {
+                       cssmPerror("SecKeychainItemExport", crtn);
+                       printf("***Error obtaining .mac identity in PKCS12 format. Aborting.\n");
+                       goto errOut;
+               }
+               
+               pfxInData.Data = (uint8 *)CFDataGetBytePtr(p12);
+               pfxInData.Length = CFDataGetLength(p12);
+               printf("...preparing to store archive of %lu bytes\n", pfxInData.Length);
+               
+               if(outFile) {
+                       if(writeFile(outFile, pfxInData.Data, pfxInData.Length)) {
+                               printf("***Error writing P12 to %s\n", outFile);
+                       }
+                       else {
+                               printf("...wrote %lu bytes to %s\n", pfxInData.Length, outFile);
+                       }
+               }
+               if(cfPhrase) {
+                       CFRelease(cfPhrase);
+               }
+       }
+       
+       /* attach to the TP */
+       tpHand = dotMacTpAttach();
+       if(tpHand == 0) {
+               printf("***Error attaching to .mac TP; aborting.\n");
+               ortn = -1;
+               goto errOut;
+       }
+       
+       /* go */
+       crtn = dotMacPostArchiveRequest(op, tpHand, &userNameData, &passwordData,
+               hostName ? &hostNameData : NULL,
+               &archNameData,
+               &timeStringData,
+               &pfxInData,
+               &pfxOutData,
+               &numArchives,
+               &archives);
+       if(crtn) {
+               printf("***Error performing archive request; aborting.\n");
+               goto errOut;
+       }
+       
+       /* post-request processing */
+       
+       switch(op) {
+               case AO_List:
+               {
+                       printf("=== List request complete; numArchives = %u ===\n", numArchives);
+                       for(unsigned dex=0; dex<numArchives; dex++) {
+                               DotMacArchive *dmarch = &archives[dex];
+                               printf("Archive %u:\n", dex);
+                               printf("   name : "); 
+                               printString(&dmarch->archiveName); 
+                               printf("\n");
+                               
+                               printf("   time : "); 
+                               printString(&dmarch->timeString); 
+                               printf("\n");
+                               
+                               /* now free what the TP allocated on our behalf */
+                               APP_FREE(dmarch->archiveName.Data);
+                               APP_FREE(dmarch->timeString.Data);
+                       }
+                       APP_FREE(archives);
+                       break;
+               }
+
+               case AO_Store:
+                       printf("=== archive \'%s\' backup complete ===\n", archName);
+                       break;
+               case AO_Fetch:
+               {
+                       bool didSomething = false;
+                       if(pfxOutData.Length == 0) {
+                               printf("***Archive fetch claimed to succeed, but no data seen\n");
+                               ortn = -1;
+                               goto errOut;
+                       }
+                       
+                       /* 
+                        * OK, we have a blob of PKCS12 data. Import to keychain and/or write it 
+                        * to a file.
+                        */
+                       printf("=== %lu bytes of archive fetched ===\n", pfxOutData.Length);
+                       if(outFile) {
+                               if(writeFile(outFile, pfxOutData.Data, pfxOutData.Length)) {
+                                       printf("***Error writing P12 to %s\n", outFile);
+                               }
+                               else {
+                                       printf("...wrote %lu bytes to %s\n", pfxOutData.Length, outFile);
+                                       didSomething = true;
+                               }
+                       }
+                       if(kcRef) {
+                               /* Note we avoid importing to default keychain - user must really want 
+                                * to perform this step */
+                               CFDataRef p12Data = CFDataCreate(NULL, pfxOutData.Data, pfxOutData.Length);
+                               SecExternalFormat extForm = kSecFormatPKCS12;
+                               SecKeyImportExportParameters keyParams;
+                               memset(&keyParams, 0, sizeof(keyParams));
+                               keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+                               CFStringRef cfPhrase = NULL;
+                               if(p12Phrase) {
+                                       cfPhrase = CFStringCreateWithCString(NULL, p12Phrase, 
+                                               kCFStringEncodingUTF8);
+                                       keyParams.passphrase = cfPhrase;
+                               }
+                               else {
+                                       keyParams.flags = kSecKeySecurePassphrase;
+                               }
+                               keyParams.alertTitle = CFSTR(".mac Identity Restore");
+                               keyParams.alertPrompt = 
+                                       CFSTR("Enter passphrase for decrypting your .mac private key");
+                                       
+                               /* go... */
+                               ortn = SecKeychainItemImport(p12Data, 
+                                       NULL,           // filename - passing kSecFormatPKCS12 is definitely enough
+                                       &extForm,
+                                       NULL,           // itemType - import'll figure it out
+                                       0,                      // SecItemImportExportFlags
+                                       &keyParams,
+                                       kcRef,
+                                       NULL);          // we don't want any items returned
+                               if(ortn) {
+                                       cssmPerror("SecKeychainItemImport", ortn);
+                                       printf("***Error importing p12 into keychain %s\n", keychainName);
+                               }
+                               else {
+                                       printf("...archive successfully imported into keychain %s\n",
+                                               keychainName);
+                                       didSomething = true;
+                               }
+                               if(cfPhrase) {
+                                       CFRelease(cfPhrase);
+                               }
+                       }
+                       if(!didSomething) {
+                               printf("...note we got an archive from the server but didn't have a "
+                                       "place to put it.\n");
+                       }
+                       break;
+               }
+               case AO_Remove:
+                       printf("=== Archive %s removed ===\n", archName);
+                       break;
+       }
+
+       if(doPause) {
+               fpurge(stdin);
+               printf("Pausing at end of test for MallocDebug attach; CR to continue: ");
+               getchar();
+       }
+
+errOut:
+       if(kcRef) {
+               CFRelease(kcRef);
+       }
+
+       if(tpHand) {
+               dotMacTpDetach(tpHand);
+       }
+       return ortn;
+}
+