/* * Copyright (c) 2002-2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // // CertificateRequest.cpp // #include #include #include #include #include #include #include #include #include #include /* one top-level prefs file for all of .mac cert requests */ #define DOT_MAC_REQ_PREFS "com.apple.security.certreq" /* * Within that dictionary is a set of per-policy dictionaries; the key in the * top-level prefs for these dictionaries is the raw policy OID data encoded * as an ASCII string. * * Within one per-policy dictionary exists a number of per-user dictionaries, * with the username key as a string. Note that this user name, the one passed to the * .mac server, does NOT have to have any relation to the current Unix user name; one * Unix user can have multiple .mac accounts. * * * Within the per-policy, per user dictionary are these two values, both stored * as raw data (CFData) blobs. */ #define DOT_MAC_REF_ID_KEY "refId" #define DOT_MAC_CERT_KEY "certificate" /* Domain for .mac cert requests */ #define DOT_MAC_DOMAIN_KEY "domain" #define DOT_MAC_DOMAIN "mac.com" /* Hosts for .mac cert requests */ #define DOT_MAC_MGMT_HOST "certmgmt" #define DOT_MAC_INFO_HOST "certinfo" /* * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical. */ static bool nssCompareCssmData( const CSSM_DATA *data1, const CSSM_DATA *data2) { if((data1 == NULL) || (data1->Data == NULL) || (data2 == NULL) || (data2->Data == NULL) || (data1->Length != data2->Length)) { return false; } if(data1->Length != data2->Length) { return false; } if(memcmp(data1->Data, data2->Data, data1->Length) == 0) { return true; } else { return false; } } /* any nonzero value means true */ static bool attrBoolValue( const SecCertificateRequestAttribute *attr) { if((attr->value.Data != NULL) && (attr->value.Length != 0) && (attr->value.Data[0] != 0)) { return true; } else { return false; } } static void tokenizeName( const CSSM_DATA *inName, /* required */ CSSM_DATA *outName, /* required */ CSSM_DATA *outDomain) /* optional */ { if (!inName || !outName) return; CSSM_SIZE idx = 0; CSSM_SIZE stopIdx = inName->Length; uint8 *p = inName->Data; *outName = *inName; if (outDomain) { outDomain->Length = idx; outDomain->Data = p; } if (!p) return; while (idx < stopIdx) { if (*p++ == '@') { outName->Length = idx; if (outDomain) { outDomain->Length = inName->Length - (idx + 1); outDomain->Data = p; } break; } idx++; } } using namespace KeychainCore; CertificateRequest::CertificateRequest(const CSSM_OID &policy, CSSM_CERT_TYPE certificateType, CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, SecKeyRef privateKeyItemRef, SecKeyRef publicKeyItemRef, const SecCertificateRequestAttributeList *attributeList, bool isNew /* = true */) : mAlloc(Allocator::standard()), mTP(gGuidAppleDotMacTP), mCL(gGuidAppleX509CL), mPolicy(mAlloc, policy.Data, policy.Length), mCertType(certificateType), mReqType(requestType), mPrivKey(NULL), mPubKey(NULL), mEstTime(0), mRefId(mAlloc), mCertState(isNew ? CRS_New : CRS_Reconstructed), mCertData(mAlloc), mUserName(mAlloc), mPassword(mAlloc), mHostName(mAlloc), mDomain(mAlloc), mDoRenew(false), mIsAsync(false), mMutex(Mutex::recursive) { StLock_(mMutex); certReqDbg("CertificateRequest construct"); /* Validate policy OID. */ if(!(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_IDENTITY, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_SHARED_SERVICES, &policy))) { certReqDbg("CertificateRequest(): unknown policy oid"); MacOSError::throwMe(errSecParam); } if(privateKeyItemRef) { mPrivKey = privateKeyItemRef; CFRetain(mPrivKey); } if(publicKeyItemRef) { mPubKey = publicKeyItemRef; CFRetain(mPubKey); } /* parse attr array */ if(attributeList == NULL) { return; } bool doPendingRequest = false; for(unsigned dex=0; dexcount; dex++) { const SecCertificateRequestAttribute *attr = &attributeList->attr[dex]; if((attr->oid.Data == NULL) || (attr->value.Data == NULL)) { MacOSError::throwMe(errSecParam); } if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME, &attr->oid)) { CSSM_DATA userName = { 0, NULL }; CSSM_DATA domainName = { 0, NULL }; tokenizeName(&attr->value, &userName, &domainName); if (!domainName.Length || !domainName.Data) { domainName.Length = strlen(DOT_MAC_DOMAIN); domainName.Data = (uint8*) DOT_MAC_DOMAIN; } mUserName.copy(userName); mDomain.copy(domainName); } else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD, &attr->oid)) { mPassword.copy(attr->value); } else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME, &attr->oid)) { mHostName.copy(attr->value); } else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_RENEW, &attr->oid)) { /* * any nonzero value means true * FIXME: this is deprecated, Treadstone doesn't allow this. Reject this * request? Ignore? */ mDoRenew = attrBoolValue(attr); } else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_ASYNC, &attr->oid)) { /* any nonzero value means true */ mIsAsync = attrBoolValue(attr); } else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_IS_PENDING, &attr->oid)) { /* any nonzero value means true */ doPendingRequest = attrBoolValue(attr); } else { certReqDbg("CertificateRequest(): unknown name/value oid"); MacOSError::throwMe(errSecParam); } } if(mCertState == CRS_Reconstructed) { /* see if we have a refId or maybe even a cert in prefs */ retrieveResults(); if(mCertData.data() != NULL) { mCertState = CRS_HaveCert; } else if(mRefId.data() != NULL) { mCertState = CRS_HaveRefId; } else if(doPendingRequest) { /* ask the server if there's a request pending */ postPendingRequest(); /* NOT REACHED - that always throws */ } else { certReqDbg("CertificateRequest(): nothing in prefs"); /* Nothing found in prefs; nothing to go by */ MacOSError::throwMe(errSecItemNotFound); } } } CertificateRequest::~CertificateRequest() throw() { StLock_(mMutex); certReqDbg("CertificateRequest destruct"); if(mPrivKey) { CFRelease(mPrivKey); } if(mPubKey) { CFRelease(mPubKey); } } #pragma mark ----- cert request submit ----- void CertificateRequest::submit( sint32 *estimatedTime) { StLock_(mMutex); CSSM_DATA &policy = mPolicy.get(); if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_IDENTITY, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_SHARED_SERVICES, &policy)) { return submitDotMac(estimatedTime); } else { /* shouldn't be here, we already validated policy in constructor */ assert(0); certReqDbg("CertificateRequest::submit(): bad policy"); MacOSError::throwMe(errSecParam); } } void CertificateRequest::submitDotMac( sint32 *estimatedTime) { StLock_(mMutex); 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; CSSM_TP_CALLERAUTH_CONTEXT callerAuth; CSSM_FIELD policyField; CSSM_DATA refId = {0, NULL}; const CSSM_KEY *privKey; const CSSM_KEY *pubKey; OSStatus ortn; if(mCertState != CRS_New) { certReqDbg("CertificateRequest: can only submit a new request"); MacOSError::throwMe(errSecParam); } if((mUserName.data() == NULL) || (mPassword.data() == NULL)) { certReqDbg("CertificateRequest: user name and password required"); MacOSError::throwMe(errSecParam); } /* get keys and CSP handle in CSSM terms */ if((mPrivKey == NULL) || (mPubKey == NULL)) { certReqDbg("CertificateRequest: pub and priv keys required"); MacOSError::throwMe(errSecParam); } ortn = SecKeyGetCSSMKey(mPrivKey, &privKey); if(ortn) { MacOSError::throwMe(ortn); } ortn = SecKeyGetCSSMKey(mPubKey, &pubKey); if(ortn) { MacOSError::throwMe(ortn); } ortn = SecKeyGetCSPHandle(mPrivKey, &cspHand); if(ortn) { MacOSError::throwMe(ortn); } /* * CSSM_X509_TYPE_VALUE_PAIR_PTR - one pair for now. * Caller passes in user name like "johnsmith"; in the CSR, * we write "johnsmith@mac.com". */ tvp.type = CSSMOID_CommonName; tvp.valueType = BER_TAG_PKIX_UTF8_STRING; CssmAutoData fullUserName(mAlloc); size_t nameLen = mUserName.length(); size_t domainLen = mDomain.length(); fullUserName.malloc(nameLen + 1 + domainLen); tvp.value = fullUserName.get(); memmove(tvp.value.Data, mUserName.data(), nameLen); memmove(tvp.value.Data + nameLen, "@", 1); memmove(tvp.value.Data + nameLen + 1, mDomain.data(), domainLen); /* Fill in the CSSM_APPLE_DOTMAC_TP_CERT_REQUEST */ memset(&certReq, 0, sizeof(certReq)); certReq.version = CSSM_DOT_MAC_TP_REQ_VERSION; certReq.cspHand = cspHand; certReq.clHand = mCL->handle(); certReq.numTypeValuePairs = 1; certReq.typeValuePairs = &tvp; certReq.publicKey = const_cast(pubKey); certReq.privateKey = const_cast(privKey); certReq.userName = mUserName.get(); certReq.password = mPassword.get(); if(mDoRenew) { certReq.flags |= CSSM_DOTMAC_TP_SIGN_RENEW; } /* we don't deal with CSR here, input or output */ /* now the rest of the args for CSSM_TP_SubmitCredRequest() */ reqSet.Requests = &certReq; reqSet.NumberOfRequests = 1; policyField.FieldOid = mPolicy; policyField.FieldValue.Data = NULL; policyField.FieldValue.Length = 0; memset(&callerAuth, 0, sizeof(callerAuth)); callerAuth.Policy.NumberOfPolicyIds = 1; callerAuth.Policy.PolicyIds = &policyField; ortn = SecKeyGetCredentials(mPrivKey, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, const_cast(&callerAuth.CallerCredentials)); if(ortn) { certReqDbg("CertificateRequest: SecKeyGetCredentials error"); MacOSError::throwMe(ortn); } CssmAutoData hostName(mAlloc); tpAuthority.AuthorityCert = NULL; tpAuthority.AuthorityLocation = &tpNetAddrs; tpNetAddrs.AddressType = CSSM_ADDR_NAME; if(mHostName.data() != NULL) { tpNetAddrs.Address = mHostName.get(); } else { unsigned hostLen = strlen(DOT_MAC_MGMT_HOST); hostName.malloc(hostLen + 1 + domainLen); tpNetAddrs.Address = hostName.get(); memmove(tpNetAddrs.Address.Data, DOT_MAC_MGMT_HOST, hostLen); memmove(tpNetAddrs.Address.Data + hostLen, ".", 1); memmove(tpNetAddrs.Address.Data + hostLen + 1, mDomain.data(), domainLen); } tpAuthPtr = &tpAuthority; /* go */ crtn = CSSM_TP_SubmitCredRequest(mTP->handle(), tpAuthPtr, CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuth, &mEstTime, &refId); // CSSM_DATA_PTR ReferenceIdentifier /* handle return, store results */ switch(crtn) { case CSSM_OK: /* refID is a cert, we have to store it in prefs for later retrieval. */ certReqDbg("submitDotMac: full success, storing cert"); if(!mIsAsync) { /* store in prefs if not running in async mode */ ortn = storeResults(NULL, &refId); if(ortn) { crtn = ortn; } } /* but keep a local copy too */ mCertData.copy(refId); mCertState = CRS_HaveCert; if(estimatedTime) { /* it's ready right now */ *estimatedTime = 0; } break; case CSSMERR_APPLE_DOTMAC_REQ_QUEUED: /* refID is the blob we use in CSSM_TP_RetrieveCredResult() */ certReqDbg("submitDotMac: queued, storing refId"); mRefId.copy(refId); /* return success - this crtn is not visible at API */ crtn = CSSM_OK; if(!mIsAsync) { /* store in prefs if not running in async mode */ ortn = storeResults(&refId, NULL); if(ortn) { crtn = ortn; } } mCertState = CRS_HaveRefId; if(estimatedTime) { *estimatedTime = mEstTime; } break; case CSSMERR_APPLE_DOTMAC_REQ_REDIRECT: /* refID is a URL, caller obtains via getReturnData() */ certReqDbg("submitDotMac: redirect"); mRefId.copy(refId); mCertState = CRS_HaveOtherData; break; default: /* all others are fatal errors, thrown below */ break; } if(refId.Data) { /* mallocd on our behalf by TP */ free(refId.Data); } if(crtn) { CssmError::throwMe(crtn); } } #pragma mark ----- cert request get result ----- void CertificateRequest::getResult( sint32 *estimatedTime, // optional CssmData &certData) { StLock_(mMutex); CSSM_DATA &policy = mPolicy.get(); if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_IDENTITY, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT, &policy) || nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_SHARED_SERVICES, &policy)) { return getResultDotMac(estimatedTime, certData); } else { /* shouldn't be here, we already validated policy in constructor */ assert(0); certReqDbg("CertificateRequest::getResult(): bad policy"); MacOSError::throwMe(errSecParam); } } void CertificateRequest::getResultDotMac( sint32 *estimatedTime, // optional CssmData &certData) { StLock_(mMutex); switch(mCertState) { case CRS_HaveCert: /* trivial case, we already have what caller is looking for */ certReqDbg("getResultDotMac: have the cert right now"); assert(mCertData.data() != NULL); certData = mCertData.get(); if(estimatedTime) { *estimatedTime = 0; } break; case CRS_HaveRefId: { /* ping the server */ certReqDbg("getResultDotMac: CRS_HaveRefId; polling server"); assert(mRefId.data() != NULL); CSSM_BOOL ConfirmationRequired; CSSM_TP_RESULT_SET_PTR resultSet = NULL; CSSM_RETURN crtn; crtn = CSSM_TP_RetrieveCredResult(mTP->handle(), &mRefId.get(), NULL, // CallerAuthCredentials &mEstTime, &ConfirmationRequired, &resultSet); switch(crtn) { case CSSM_OK: break; case CSSMERR_TP_CERT_NOT_VALID_YET: /* * By convention, this means "not ready yet". * The dot mac server does not have a way of telling us the * estimated time on a straight lookup like this (we only get * an estimated completion time on the initial request), so we * fake it. */ certReqDbg("getResultDotMac: polled server, not ready yet"); if(estimatedTime) { *estimatedTime = (mEstTime) ? mEstTime : 1; } MacOSError::throwMe(CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING); default: certReqDbg("CSSM_TP_RetrieveCredResult error"); CssmError::throwMe(crtn); } if(resultSet == NULL) { certReqDbg("***CSSM_TP_RetrieveCredResult OK, but no result set"); MacOSError::throwMe(errSecInternalComponent); } if(resultSet->NumberOfResults != 1) { certReqDbg("***CSSM_TP_RetrieveCredResult OK, NumberOfResults (%lu)", (unsigned long)resultSet->NumberOfResults); MacOSError::throwMe(errSecInternalComponent); } if(resultSet->Results == NULL) { certReqDbg("***CSSM_TP_RetrieveCredResult OK, but empty result set"); MacOSError::throwMe(errSecInternalComponent); } certReqDbg("getResultDotMac: polled server, SUCCESS"); CSSM_DATA_PTR result = (CSSM_DATA_PTR)resultSet->Results; if(result->Data == NULL) { certReqDbg("***CSSM_TP_RetrieveCredResult OK, but empty result"); MacOSError::throwMe(errSecInternalComponent); } mCertData.copy(*result); certData = mCertData.get(); mCertState = CRS_HaveCert; if(estimatedTime) { *estimatedTime = 0; } /* * Free the stuff allocated on our behalf by TP. * FIXME - are we sure CssmClient is using alloc, free, etc.? */ free(result->Data); free(result); free(resultSet); break; } default: /* what do we do with this? */ certReqDbg("CertificateRequest::getResultDotMac(): bad state"); MacOSError::throwMe(errSecInternalComponent); } /* * One more thing: once we pass a cert back to caller, we erase * the record of this transaction from prefs. */ assert(mCertData.data() != NULL); assert(mCertData.data() == certData.Data); removeResults(); } /* * Obtain policy/error specific return data blob. We own the data, it's * not copied. */ void CertificateRequest::getReturnData( CssmData &rtnData) { StLock_(mMutex); rtnData = mRefId.get(); } #pragma mark ----- preferences support ----- /* Current user as CFString, for use as key in per-policy dictionary */ CFStringRef CertificateRequest::createUserKey() { StLock_(mMutex); return CFStringCreateWithBytes(NULL, (UInt8 *)mUserName.data(), mUserName.length(), kCFStringEncodingUTF8, false); } #define MAX_OID_LEN 2048 // way big... */ /* current policy as CFString, for use as key in prefs dictionary */ CFStringRef CertificateRequest::createPolicyKey() { StLock_(mMutex); char oidstr[MAX_OID_LEN]; unsigned char *inp = (unsigned char *)mPolicy.data(); char *outp = oidstr; CFIndex len = mPolicy.length(); for(CFIndex dex=0; dex_(mMutex); assert(mPolicy.data() != NULL); assert(mUserName.data() != NULL); assert(mDomain.data() != NULL); bool deleteEntry = ((refId == NULL) && (certData == NULL)); /* get a mutable copy of the existing prefs, or a fresh empty one */ MutableDictionary *prefsDict = MutableDictionary::CreateMutableDictionary(DOT_MAC_REQ_PREFS, Dictionary::US_User); if (prefsDict == NULL) { prefsDict = new MutableDictionary(); } /* get a mutable copy of the dictionary for this policy, or a fresh empty one */ CFStringRef policyKey = createPolicyKey(); MutableDictionary *policyDict = prefsDict->copyMutableDictValue(policyKey); CFStringRef userKey = createUserKey(); if(deleteEntry) { /* remove user dictionary from this policy dictionary */ policyDict->removeValue(userKey); } else { /* get a mutable copy of the dictionary for this user, or a fresh empty one */ MutableDictionary *userDict = policyDict->copyMutableDictValue(userKey); CFStringRef domainKey = CFStringCreateWithBytes(NULL, (UInt8 *)mDomain.data(), mDomain.length(), kCFStringEncodingUTF8, false); userDict->setValue(CFSTR(DOT_MAC_DOMAIN_KEY), domainKey); CFRelease(domainKey); /* write refId and/or cert --> user dictionary */ if(refId) { userDict->setDataValue(CFSTR(DOT_MAC_REF_ID_KEY), refId->Data, refId->Length); } if(certData) { userDict->setDataValue(CFSTR(DOT_MAC_CERT_KEY), certData->Data, certData->Length); } /* new user dictionary --> policy dictionary */ policyDict->setValue(userKey, userDict->dict()); delete userDict; } CFRelease(userKey); /* new policy dictionary to prefs dictionary, or nuke it */ if(policyDict->count() == 0) { prefsDict->removeValue(policyKey); } else { prefsDict->setValue(policyKey, policyDict->dict()); } CFRelease(policyKey); delete policyDict; /* prefs --> disk */ OSStatus ortn = errSecSuccess; if(!prefsDict->writePlistToPrefs(DOT_MAC_REQ_PREFS, Dictionary::US_User)) { certReqDbg("storeResults: error writing prefs to disk"); ortn = errSecIO; } delete prefsDict; return ortn; } /* * Attempt to fetch mCertData or mRefId from preferences. */ void CertificateRequest::retrieveResults() { StLock_(mMutex); assert(mPolicy.data() != NULL); assert(mUserName.data() != NULL); /* get the .mac cert prefs as a dictionary */ Dictionary *pd = Dictionary::CreateDictionary(DOT_MAC_REQ_PREFS, Dictionary::US_User); if (pd == NULL) { certReqDbg("retrieveResults: no prefs found"); return; } auto_ptr prefsDict(pd); /* get dictionary for current policy */ CFStringRef policyKey = createPolicyKey(); Dictionary *policyDict = prefsDict->copyDictValue(policyKey); CFRelease(policyKey); if(policyDict != NULL) { /* dictionary for user */ CFStringRef userKey = createUserKey(); Dictionary *userDict = policyDict->copyDictValue(userKey); if(userDict != NULL) { /* is there a cert in there? */ CFDataRef val = userDict->getDataValue(CFSTR(DOT_MAC_CERT_KEY)); if(val) { mCertData.copy(CFDataGetBytePtr(val), CFDataGetLength(val)); } /* how about refId? */ val = userDict->getDataValue(CFSTR(DOT_MAC_REF_ID_KEY)); if(val) { mRefId.copy(CFDataGetBytePtr(val), CFDataGetLength(val)); } delete userDict; } CFRelease(userKey); delete policyDict; } } /* * Remove all trace of current policy/user. Called when we successfully transferred * the cert back to caller. */ void CertificateRequest::removeResults() { StLock_(mMutex); assert(mPolicy.data() != NULL); assert(mUserName.data() != NULL); storeResults(NULL, NULL); } /* * Have the TP ping the server to see of there's a request pending for the current * user. Always throws: either * CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING -- request pending * CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING -- no request pending * errSecParam -- no user, no password * other gross errors, e.g. errSecIO for server connection failure * * The distinguishing features about this TP request are: * * policy OID = CSSMOID_DOTMAC_CERT_REQ_{IDENTITY,EMAIL_SIGN,EMAIL_ENCRYPT,SHARED_SERVICES} * CSSM_TP_AUTHORITY_REQUEST_TYPE = CSSM_TP_AUTHORITY_REQUEST_CERTLOOKUP * CSSM_APPLE_DOTMAC_TP_CERT_REQUEST.flags = CSSM_DOTMAC_TP_IS_REQ_PENDING * must have userName and password * hostname optional as usual */ void CertificateRequest::postPendingRequest() { StLock_(mMutex); 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_TP_CALLERAUTH_CONTEXT callerAuth; CSSM_FIELD policyField; CSSM_DATA refId = {0, NULL}; assert(mCertState == CRS_Reconstructed); if((mUserName.data() == NULL) || (mPassword.data() == NULL)) { certReqDbg("postPendingRequest: user name and password required"); MacOSError::throwMe(errSecParam); } /* Fill in the CSSM_APPLE_DOTMAC_TP_CERT_REQUEST */ memset(&certReq, 0, sizeof(certReq)); certReq.version = CSSM_DOT_MAC_TP_REQ_VERSION; certReq.userName = mUserName.get(); certReq.password = mPassword.get(); certReq.flags = CSSM_DOTMAC_TP_IS_REQ_PENDING; /* now the rest of the args for CSSM_TP_SubmitCredRequest() */ reqSet.Requests = &certReq; reqSet.NumberOfRequests = 1; /* * This OID actually doesn't matter - right? This RPC doesn't know about * which request we seek... */ policyField.FieldOid = mPolicy; policyField.FieldValue.Data = NULL; policyField.FieldValue.Length = 0; memset(&callerAuth, 0, sizeof(callerAuth)); callerAuth.Policy.NumberOfPolicyIds = 1; callerAuth.Policy.PolicyIds = &policyField; /* no other creds here */ if(mHostName.data() != NULL) { tpAuthority.AuthorityCert = NULL; tpAuthority.AuthorityLocation = &tpNetAddrs; tpNetAddrs.AddressType = CSSM_ADDR_NAME; tpNetAddrs.Address = mHostName.get(); tpAuthPtr = &tpAuthority; } /* go */ crtn = CSSM_TP_SubmitCredRequest(mTP->handle(), tpAuthPtr, CSSM_TP_AUTHORITY_REQUEST_CERTLOOKUP, &reqSet, &callerAuth, &mEstTime, &refId); // CSSM_DATA_PTR ReferenceIdentifier if(refId.Data) { /* shouldn't be any but just in case.... */ free(refId.Data); } switch(crtn) { case CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING: certReqDbg("postPendingRequest: REQ_IS_PENDING"); break; case CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING: certReqDbg("postPendingRequest: NO_REQ_PENDING"); break; case CSSM_OK: /* should never happen */ certReqDbg("postPendingRequest: unexpected success!"); crtn = errSecInternalComponent; break; default: certReqDbg("postPendingRequest: unexpected rtn %lu", (unsigned long)crtn); break; } CssmError::throwMe(crtn); }