--- /dev/null
+/*
+ * dotMacTool.cpp - .mac TP exerciser
+ */
+
+#include <Security/Security.h>
+#include <Security/SecKeyPriv.h>
+#include <security_cdsa_utils/cuCdsaUtils.h>
+#include <security_cdsa_utils/cuFileIo.h>
+#include <security_cdsa_utils/cuPem.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+//#include <security_dotmac_tp/dotMacTp.h>
+#include <dotMacTp.h>
+#include <security_cdsa_utils/cuPrintCert.h>
+
+#include "keyPicker.h"
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+
+#define USER_DEFAULT "dmitchtest@mac.com"
+#define PWD_DEF "123456"
+
+static void usage(char **argv)
+{
+ printf("usage: %s op [options]\n", argv[0]);
+ printf("Op:\n");
+ printf(" g generate identity cert\n");
+ printf(" G generate email signing cert\n");
+ printf(" e generate email encrypting cert\n");
+ printf(" l lookup cert (requires -f)\n");
+ printf(" L lookup identity cert (via -u)\n");
+ printf(" M lookup email signing cert (via -u)\n");
+ printf(" N lookup encrypting cert (via -u)\n");
+ printf("Options:\n");
+ printf(" -g Generate keypair\n");
+ printf(" -p pick key pair from existing\n");
+ printf(" -u username Default = %s\n", USER_DEFAULT);
+ printf(" -Z password Specify password immediately\n");
+ printf(" -z Use default password %s\n", PWD_DEF);
+ printf(" -k keychain Source/destination of keys and certs\n");
+ printf(" -c filename Write CSR to filename\n");
+ printf(" -C filename Use existing CSR (no keygen)\n");
+ printf(" -f refIdFile RefId file for cert lookup\n");
+ printf(" -n Do NOT post the CSR to the .mac server\n");
+ printf(" -H hostname Alternate .mac server host name (default %s)\n",
+ DOT_MAC_SIGN_HOST_NAME);
+ printf(" -o outFile Write output cert or refId (if any) to outFile\n");
+ printf(" -r Renew (default is new)\n");
+ printf(" -M Pause for MallocDebug\n");
+ printf(" -q Quiet\n");
+ printf(" -v Verbose\n");
+ printf(" -h Usage\n");
+ exit(1);
+}
+
+static CSSM_VERSION vers = {2, 0};
+
+static CSSM_API_MEMORY_FUNCS memFuncs = {
+ cuAppMalloc,
+ cuAppFree,
+ cuAppRealloc,
+ cuAppCalloc,
+ NULL
+ };
+
+static CSSM_TP_HANDLE dotMacStartup()
+{
+ CSSM_TP_HANDLE tpHand;
+ CSSM_RETURN crtn;
+
+ if(cuCssmStartup() == CSSM_FALSE) {
+ return 0;
+ }
+ crtn = CSSM_ModuleLoad(&gGuidAppleDotMacTP,
+ CSSM_KEY_HIERARCHY_NONE,
+ NULL, // eventHandler
+ NULL); // AppNotifyCallbackCtx
+ if(crtn) {
+ cuPrintError("CSSM_ModuleLoad(DotMacTP)", crtn);
+ return 0;
+ }
+ crtn = CSSM_ModuleAttach (&gGuidAppleDotMacTP,
+ &vers,
+ &memFuncs, // memFuncs
+ 0, // SubserviceID
+ CSSM_SERVICE_TP, // SubserviceFlags
+ 0, // AttachFlags
+ CSSM_KEY_HIERARCHY_NONE,
+ NULL, // FunctionTable
+ 0, // NumFuncTable
+ NULL, // reserved
+ &tpHand);
+ if(crtn) {
+ cuPrintError("CSSM_ModuleAttach(DotMacTP)", crtn);
+ return 0;
+ }
+ else {
+ return tpHand;
+ }
+}
+
+/* print text, safely */
+static void snDumpText(
+ const unsigned char *rcvBuf,
+ unsigned len)
+{
+ char *cp = (char *)rcvBuf;
+ unsigned i;
+ char c;
+
+ for(i=0; i<len; i++) {
+ c = *cp++;
+ if(c == '\0') {
+ break;
+ }
+ switch(c) {
+ case '\n':
+ printf("\\n\n"); // graphic and liternal newline
+ break;
+ case '\r':
+ printf("\\r\n");
+ break;
+ default:
+ if(isprint(c) && (c != '\n')) {
+ printf("%c", c);
+ }
+ else {
+ printf("<%02X>", ((unsigned)c) & 0xff);
+ }
+ break;
+ }
+
+ }
+}
+
+static OSStatus genKeyPair(
+ SecKeychainRef kcRef, // NULL means the default list
+ SecKeyRef *pubKey, // RETURNED
+ SecKeyRef *privKey) // RETURNED
+{
+ OSStatus ortn;
+
+ ortn = SecKeyCreatePair(kcRef,
+ DOT_MAC_KEY_ALG,
+ DOT_MAC_KEY_SIZE,
+ 0, // context handle
+ /* public key usage and attrs */
+ CSSM_KEYUSE_ANY,
+ CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE,
+ /* private key usage and attrs */
+ CSSM_KEYUSE_ANY,
+ CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE |
+ CSSM_KEYATTR_SENSITIVE,
+ NULL, // initial access
+ pubKey,
+ privKey);
+ if(ortn) {
+ cssmPerror("SecKeyCreatePair", ortn);
+ }
+ return ortn;
+}
+
+/* Lookup via ReferenceID, obtained from CSSM_TP_SubmitCredRequest() */
+OSStatus doLookupViaRefId(
+ CSSM_TP_HANDLE tpHand,
+ unsigned char *refId,
+ unsigned refIdLen,
+ char *outFile,
+ bool verbose)
+{
+ CSSM_DATA refIdData = { refIdLen, refId };
+ sint32 EstimatedTime;
+ CSSM_BOOL ConfirmationRequired;
+ CSSM_TP_RESULT_SET_PTR resultSet = NULL;
+ CSSM_RETURN crtn;
+
+ crtn = CSSM_TP_RetrieveCredResult(tpHand, &refIdData, NULL,
+ &EstimatedTime, &ConfirmationRequired, &resultSet);
+ if(crtn) {
+ cssmPerror("CSSM_TP_RetrieveCredResult", crtn);
+ return crtn;
+ }
+ if(resultSet == NULL) {
+ printf("***CSSM_TP_RetrieveCredResult OK, but no result set\n");
+ return -1;
+ }
+ if(resultSet->NumberOfResults != 1) {
+ printf("***CSSM_TP_RetrieveCredResult OK, NumberOfResults (%u)\n",
+ (unsigned)resultSet->NumberOfResults);
+ return -1;
+ }
+ if(resultSet->Results == NULL) {
+ printf("***CSSM_TP_RetrieveCredResult OK, but empty result set\n");
+ return -1;
+ }
+ CSSM_DATA_PTR certData = (CSSM_DATA_PTR)resultSet->Results;
+
+ printf("...cert retrieval complete\n");
+ if(outFile) {
+ if(!writeFile(outFile, certData->Data, certData->Length)) {
+ printf("...%lu bytes of cert data written to %s\n",
+ certData->Length, outFile);
+ }
+ else {
+ printf("***Error writing cert to %s\n", outFile);
+ crtn = ioErr;
+ }
+ }
+ else if(verbose) {
+ unsigned char *der;
+ unsigned derLen;
+ if(pemDecode(certData->Data, certData->Length, &der, &derLen)) {
+ printf("***Error PEM decoding returned cert\n");
+ }
+ else {
+ printCert(der, derLen, CSSM_FALSE);
+ free(der);
+ }
+ }
+ return noErr;
+}
+
+/*
+* Lookup via user name, a greatly simplified form of CSSM_TP_SubmitCredRequest()
+*/
+OSStatus doLookupViaUserName(
+ CSSM_TP_HANDLE tpHand,
+ const CSSM_OID *opOid,
+ const char *userName,
+ const char *hostName, // optional
+ char *outFile,
+ bool verbose)
+{
+ CSSM_APPLE_DOTMAC_TP_CERT_REQUEST certReq;
+ CSSM_TP_AUTHORITY_ID tpAuthority;
+ CSSM_TP_AUTHORITY_ID *tpAuthPtr = NULL;
+ CSSM_NET_ADDRESS tpNetAddrs;
+ CSSM_TP_REQUEST_SET reqSet;
+ CSSM_FIELD policyField;
+ CSSM_DATA certData = {0, NULL};
+ sint32 estTime;
+ CSSM_TP_CALLERAUTH_CONTEXT callerAuth;
+
+ memset(&certReq, 0, sizeof(certReq));
+ certReq.userName.Data = (uint8 *)userName;
+ certReq.userName.Length = strlen(userName);
+ if(hostName != NULL) {
+ tpAuthority.AuthorityCert = NULL;
+ tpAuthority.AuthorityLocation = &tpNetAddrs;
+ tpNetAddrs.AddressType = CSSM_ADDR_NAME;
+ tpNetAddrs.Address.Data = (uint8 *)hostName;
+ tpNetAddrs.Address.Length = strlen(hostName);
+ tpAuthPtr = &tpAuthority;
+ };
+
+ certReq.version = CSSM_DOT_MAC_TP_REQ_VERSION;
+ reqSet.NumberOfRequests = 1;
+ reqSet.Requests = &certReq;
+ policyField.FieldOid = *opOid;
+ policyField.FieldValue.Data = NULL;
+ policyField.FieldValue.Length = 0;
+ memset(&callerAuth, 0, sizeof(callerAuth));
+ callerAuth.Policy.NumberOfPolicyIds = 1;
+ callerAuth.Policy.PolicyIds = &policyField;
+
+ CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest (tpHand,
+ tpAuthPtr,
+ CSSM_TP_AUTHORITY_REQUEST_CERTLOOKUP,
+ &reqSet, // const CSSM_TP_REQUEST_SET *RequestInput,
+ &callerAuth,
+ &estTime, // sint32 *EstimatedTime,
+ &certData); // CSSM_DATA_PTR ReferenceIdentifier
+
+ if(crtn) {
+ cssmPerror("CSSM_TP_SubmitCredRequest(lookup)", crtn);
+ return crtn;
+ }
+
+ printf("...cert lookup complete\n");
+ if(outFile) {
+ if(!writeFile(outFile, certData.Data, certData.Length)) {
+ printf("...%lu bytes of cert data written to %s\n",
+ certData.Length, outFile);
+ }
+ else {
+ printf("***Error writing cert to %s\n", outFile);
+ crtn = ioErr;
+ }
+ }
+ if(verbose) {
+ /* This one returns the cert in DER format, we might revisit that */
+ printCert(certData.Data, certData.Length, CSSM_FALSE);
+ }
+ return crtn;
+}
+
+#define FULL_EMAIL_ADDRESS 1
+
+int main(int argc, char **argv)
+{
+ CSSM_RETURN crtn;
+ CSSM_TP_AUTHORITY_ID tpAuthority;
+ CSSM_TP_AUTHORITY_ID *tpAuthPtr = NULL;
+ CSSM_NET_ADDRESS tpNetAddrs;
+ CSSM_APPLE_DOTMAC_TP_CERT_REQUEST certReq;
+ CSSM_TP_REQUEST_SET reqSet;
+ CSSM_CSP_HANDLE cspHand = 0;
+ CSSM_X509_TYPE_VALUE_PAIR tvp;
+ char pwdBuf[1000];
+ CSSM_TP_CALLERAUTH_CONTEXT callerAuth;
+ sint32 estTime;
+ CSSM_DATA refId = {0, NULL};
+ OSStatus ortn;
+ SecKeyRef pubKeyRef = NULL;
+ SecKeyRef privKeyRef = NULL;
+ const CSSM_KEY *privKey = NULL;
+ const CSSM_KEY *pubKey = NULL;
+ SecKeychainRef kcRef = NULL;
+ CSSM_FIELD policyField;
+
+ /* user-spec'd variables */
+ bool genKeys = false;
+ bool pickKeys = false;
+ char *keychainName = NULL;
+ char *csrOutName = NULL;
+ char *csrInName = NULL;
+ const char *userName = USER_DEFAULT;
+ char *password = NULL;
+ char *hostName = NULL;
+ bool doNotPost = false;
+ bool doRenew = false;
+ const CSSM_OID *opOid = NULL;
+ char *outFile = NULL;
+ bool quiet = false;
+ bool verbose = false;
+ bool lookupViaRefId = false;
+ bool lookupViaUserName = false;
+ char *refIdFile = NULL;
+ bool doPause = false;
+
+ if(argc < 2) {
+ usage(argv);
+ }
+ switch(argv[1][0]) {
+ case 'L':
+ lookupViaUserName = true;
+ /* drop thru */
+ case 'g':
+ opOid = &CSSMOID_DOTMAC_CERT_REQ_IDENTITY;
+ break;
+
+ case 'M':
+ lookupViaUserName = true;
+ /* drop thru */
+ case 'G':
+ opOid = &CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN;
+ break;
+
+ case 'N':
+ lookupViaUserName = true;
+ /* drop thru */
+ case 'e':
+ opOid = &CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT;
+ break;
+
+ case 'l':
+ lookupViaRefId = true;
+ break;
+ default:
+ usage(argv);
+ }
+
+ extern char *optarg;
+ extern int optind;
+ optind = 2;
+ int arg;
+ while ((arg = getopt(argc, argv, "gpk:c:u:Z:H:nzrC:o:hf:Mqv")) != -1) {
+ switch (arg) {
+ case 'g':
+ genKeys = true;
+ break;
+ case 'p':
+ pickKeys = true;
+ break;
+ case 'u':
+ userName = optarg;
+ break;
+ case 'Z':
+ password = optarg;
+ break;
+ case 'z':
+ password = (char *)PWD_DEF;
+ break;
+ case 'k':
+ keychainName = optarg;
+ break;
+ case 'c':
+ csrOutName = optarg;
+ break;
+ case 'C':
+ csrInName = optarg;
+ break;
+ case 'H':
+ hostName = optarg;
+ break;
+ case 'n':
+ doNotPost = true;
+ break;
+ case 'r':
+ doRenew = true;
+ break;
+ case 'o':
+ outFile = optarg;
+ break;
+ case 'f':
+ refIdFile = optarg;
+ break;
+ case 'M':
+ doPause = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case 'h':
+ usage(argv);
+ }
+ }
+
+ if(doPause) {
+ fpurge(stdin);
+ printf("Pausing for MallocDebug attach; CR to continue: ");
+ getchar();
+ }
+
+ CSSM_TP_HANDLE tpHand = dotMacStartup();
+ if(tpHand == 0) {
+ printf("Error attaching to the .mac TP. Check your MDS file.\n");
+ exit(1);
+ }
+
+ if(lookupViaRefId) {
+ if(refIdFile == NULL) {
+ printf("I need a refIdFile to do a lookup.\n");
+ usage(argv);
+ }
+ unsigned char *refId;
+ unsigned refIdLen;
+ int irtn = readFile(refIdFile, &refId, &refIdLen);
+ if(irtn) {
+ printf("***Error reading refId from %s. Aborting.\n", refIdFile);
+ exit(1);
+ }
+ ortn = doLookupViaRefId(tpHand, refId, refIdLen, outFile, verbose);
+ free(refId);
+ goto done;
+ }
+ if(lookupViaUserName) {
+ ortn = doLookupViaUserName(tpHand, opOid, userName, hostName, outFile, verbose);
+ goto done;
+ }
+ if(!pickKeys && !genKeys && (csrInName == NULL)) {
+ printf("***You must specify either the -p (pick keys) or -g (generate keys)"
+ " arguments, or provide a CSR (-C).\n");
+ exit(1);
+ }
+
+ memset(&certReq, 0, sizeof(certReq));
+
+ /* all of the subsequest argument are superfluous for lookupViaUserName, except for
+ * the user name itself, which has a default */
+ 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);
+ goto done;
+ }
+ }
+
+ if(password == NULL) {
+ const char *pwdp = getpass("Enter .mac password: ");
+ if(pwdp == NULL) {
+ printf("Aboerting.\n");
+ ortn = paramErr;
+ goto done;
+ }
+ memmove(pwdBuf, pwdp, strlen(pwdp) + 1);
+ password = pwdBuf;
+ }
+ certReq.password.Data = (uint8 *)password;
+ certReq.password.Length = strlen(password);
+ certReq.userName.Data = (uint8 *)userName;
+ certReq.userName.Length = strlen(userName);
+
+ if(csrInName) {
+ unsigned len;
+ if(readFile(csrInName, &certReq.csr.Data, &len)) {
+ printf("***Error reading CSR from %s. Aborting.\n", csrInName);
+ exit(1);
+ }
+ certReq.csr.Length = len;
+ certReq.flags |= CSSM_DOTMAC_TP_EXIST_CSR;
+ }
+ else {
+ /*
+ * All the stuff the TP needs to actually generate a CSR.
+ *
+ * Get a key pair, somehow.
+ */
+ if(genKeys) {
+ ortn = genKeyPair(kcRef, &pubKeyRef, &privKeyRef);
+ }
+ else {
+ ortn = keyPicker(kcRef, &pubKeyRef, &privKeyRef);
+ }
+ if(ortn) {
+ printf("Can't proceed without a keypair. Aborting.\n");
+ exit(1);
+ }
+ ortn = SecKeyGetCSSMKey(pubKeyRef, &pubKey);
+ if(ortn) {
+ cssmPerror("SecKeyGetCSSMKey", ortn);
+ goto done;
+ }
+ ortn = SecKeyGetCSSMKey(privKeyRef, &privKey);
+ if(ortn) {
+ cssmPerror("SecKeyGetCSSMKey", ortn);
+ goto done;
+ }
+ ortn = SecKeyGetCSPHandle(privKeyRef, &cspHand);
+ if(ortn) {
+ cssmPerror("SecKeyGetCSPHandle", ortn);
+ goto done;
+ }
+
+ /* CSSM_X509_TYPE_VALUE_PAIR - one pair for now */
+ // tvp.type = CSSMOID_EmailAddress;
+ tvp.type = CSSMOID_CommonName;
+ tvp.valueType = BER_TAG_PRINTABLE_STRING;
+ #if FULL_EMAIL_ADDRESS
+ {
+ unsigned nameLen = strlen(userName);
+ tvp.value.Data = (uint8 *)malloc(nameLen + strlen("@mac.com") + 1);
+ strcpy((char *)tvp.value.Data, userName);
+ strcpy((char *)tvp.value.Data + nameLen, "@mac.com");
+ tvp.value.Length = strlen((char *)tvp.value.Data);
+ }
+ #else
+ tvp.value.Data = (uint8 *)userName;
+ tvp.value.Length = strlen(userName);
+ #endif
+ }
+ /* set up args for CSSM_TP_SubmitCredRequest */
+ if(hostName != NULL) {
+ tpAuthority.AuthorityCert = NULL;
+ tpAuthority.AuthorityLocation = &tpNetAddrs;
+ tpNetAddrs.AddressType = CSSM_ADDR_NAME;
+ tpNetAddrs.Address.Data = (uint8 *)hostName;
+ tpNetAddrs.Address.Length = strlen(hostName);
+ tpAuthPtr = &tpAuthority;
+ };
+
+ certReq.version = CSSM_DOT_MAC_TP_REQ_VERSION;
+ if(!csrInName) {
+ certReq.cspHand = cspHand;
+ certReq.clHand = cuClStartup();
+ certReq.numTypeValuePairs = 1;
+ certReq.typeValuePairs = &tvp;
+ certReq.publicKey = (CSSM_KEY_PTR)pubKey;
+ certReq.privateKey = (CSSM_KEY_PTR)privKey;
+ }
+ if(doNotPost) {
+ certReq.flags |= CSSM_DOTMAC_TP_DO_NOT_POST;
+ }
+ if(csrOutName != NULL) {
+ certReq.flags |= CSSM_DOTMAC_TP_RETURN_CSR;
+ }
+ if(doRenew) {
+ certReq.flags |= CSSM_DOTMAC_TP_SIGN_RENEW;
+ }
+
+ reqSet.NumberOfRequests = 1;
+ reqSet.Requests = &certReq;
+
+ policyField.FieldOid = *opOid;
+ policyField.FieldValue.Data = NULL;
+ policyField.FieldValue.Length = 0;
+ memset(&callerAuth, 0, sizeof(callerAuth));
+ callerAuth.Policy.NumberOfPolicyIds = 1;
+ callerAuth.Policy.PolicyIds = &policyField;
+ if(!csrInName) {
+ ortn = SecKeyGetCredentials(privKeyRef,
+ CSSM_ACL_AUTHORIZATION_SIGN,
+ kSecCredentialTypeDefault,
+ const_cast<const CSSM_ACCESS_CREDENTIALS **>(&callerAuth.CallerCredentials));
+ if(ortn) {
+ cssmPerror("SecKeyGetCredentials", crtn);
+ goto done;
+ }
+ }
+
+ 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
+ switch(crtn) {
+ case CSSM_OK:
+ case CSSMERR_APPLE_DOTMAC_REQ_QUEUED:
+ {
+ /*
+ * refId should be a cert or RefId
+ */
+ const char *itemType = "Cert";
+ const char *statStr = "OK";
+ if(crtn != CSSM_OK) {
+ itemType = "RefId";
+ statStr = "Cert";
+ }
+ if((refId.Data == NULL) || (refId.Length == 0)) {
+ printf("CSSM_TP_SubmitCredRequest returned %s but no data\n", statStr);
+ break;
+ }
+ if(crtn == CSSM_OK) {
+ printf("...cert acquisition complete\n");
+ }
+ else {
+ printf("...Cert request QUEUED\n");
+ }
+ if(outFile) {
+ if(!writeFile(outFile, refId.Data, refId.Length)) {
+ if(!quiet) {
+ printf("...%lu bytes of %s written to %s\n",
+ refId.Length, itemType, outFile);
+ }
+ }
+ else {
+ printf("***Error writing %s to %s\n", itemType, outFile);
+ crtn = ioErr;
+ }
+ }
+ else if(verbose) {
+ if(crtn == CSSM_OK) {
+ unsigned char *der;
+ unsigned derLen;
+ if(pemDecode(refId.Data, refId.Length, &der, &derLen)) {
+ printf("***Error PEM decoding returned cert\n");
+ }
+ else {
+ printCert(der, derLen, CSSM_FALSE);
+ free(der);
+ }
+ }
+ else {
+ printf("RefId data:\n");
+ snDumpText(refId.Data, refId.Length);
+ }
+ }
+ break;
+ }
+ case CSSMERR_APPLE_DOTMAC_REQ_REDIRECT:
+ if((refId.Data == NULL) || (refId.Length == 0)) {
+ printf("CSSM_TP_SubmitCredRequest returned REDIRECT but no data\n");
+ break;
+ }
+ printf("...cert acquisition : REDIRECTED to: ");
+ snDumpText(refId.Data, refId.Length);
+ printf("\n");
+ break;
+ default:
+ cssmPerror("CSSM_TP_SubmitCredRequest", crtn);
+ break;
+ }
+ if(csrOutName) {
+ if((certReq.csr.Data == NULL) || (certReq.csr.Length == 0)) {
+ printf("***Asked for CSR but didn't get one\n");
+ ortn = paramErr;
+ goto done;
+ }
+ if(writeFile(csrOutName, certReq.csr.Data, certReq.csr.Length)) {
+ printf("***Error writing CSR to %s.\n", csrOutName);
+ }
+ else {
+ printf("...%lu bytes written as CSR to %s\n", certReq.csr.Length, csrOutName);
+ }
+ }
+done:
+ /* cleanup */
+ CSSM_ModuleDetach(tpHand);
+ if(certReq.clHand) {
+ CSSM_ModuleDetach(certReq.clHand);
+ }
+ if(kcRef) {
+ CFRelease(kcRef);
+ }
+ if(csrInName) {
+ free(certReq.csr.Data);
+ }
+ if(privKeyRef) {
+ CFRelease(privKeyRef);
+ }
+ if(pubKeyRef) {
+ CFRelease(pubKeyRef);
+ }
+ if(refId.Data) {
+ cuAppFree(refId.Data, NULL);
+ }
+ if(doPause) {
+ fpurge(stdin);
+ printf("Pausing for MallocDebug measurement; CR to continue: ");
+ getchar();
+ }
+
+ return ortn;
+}