X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_apple_x509_tp/lib/tpCredRequest.cpp?ds=sidebyside diff --git a/OSX/libsecurity_apple_x509_tp/lib/tpCredRequest.cpp b/OSX/libsecurity_apple_x509_tp/lib/tpCredRequest.cpp new file mode 100644 index 00000000..be25daea --- /dev/null +++ b/OSX/libsecurity_apple_x509_tp/lib/tpCredRequest.cpp @@ -0,0 +1,853 @@ +/* + * Copyright (c) 2002,2011,2014 Apple Inc. All Rights Reserved. + * + * The contents of this file constitute Original Code as defined in and are + * subject to the Apple Public Source License Version 1.2 (the 'License'). + * You may not use this file except in compliance with the License. Please obtain + * a copy of the License at http://www.apple.com/publicsource and read it before + * using this file. + * + * This 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. + */ + + +/* + * tpCredRequest.cpp - credential request functions SubmitCredRequest, + * RetrieveCredResult + * + */ + +#include "AppleTPSession.h" +#include "certGroupUtils.h" +#include "tpdebugging.h" +#include "tpTime.h" +#include +#include +#include +#include +#include +#include +#include + +#define tpCredDebug(args...) secdebug("tpCred", ## args) + +/* + * Build up a CSSM_X509_NAME from an arbitrary list of name/OID pairs. + * We do one a/v pair per RDN. + */ +CSSM_X509_NAME * AppleTPSession::buildX509Name( + const CSSM_APPLE_TP_NAME_OID *nameArray, + unsigned numNames) +{ + CSSM_X509_NAME *top = (CSSM_X509_NAME *)malloc(sizeof(CSSM_X509_NAME)); + top->numberOfRDNs = numNames; + if(numNames == 0) { + /* legal! */ + top->RelativeDistinguishedName = NULL; + return top; + } + top->RelativeDistinguishedName = + (CSSM_X509_RDN_PTR)malloc(sizeof(CSSM_X509_RDN) * numNames); + CSSM_X509_RDN_PTR rdn; + const CSSM_APPLE_TP_NAME_OID *nameOid; + unsigned nameDex; + for(nameDex=0; nameDexRelativeDistinguishedName[nameDex]; + nameOid = &nameArray[nameDex]; + rdn->numberOfPairs = 1; + rdn->AttributeTypeAndValue = (CSSM_X509_TYPE_VALUE_PAIR_PTR) + malloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR)); + CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = rdn->AttributeTypeAndValue; + tpCopyCssmData(*this, nameOid->oid, &atvp->type); + atvp->value.Length = strlen(nameOid->string); + if(tpCompareOids(&CSSMOID_CountryName, nameOid->oid)) { + /* + * Country handled differently per RFC 3280 - must be printable, + * max of two characters in length + */ + if(atvp->value.Length > 2) { + CssmError::throwMe(CSSMERR_TP_INVALID_DATA); + } + for(unsigned dex=0; dexvalue.Length; dex++) { + int c = nameOid->string[dex]; + if(!isprint(c) || (c == EOF)) { + CssmError::throwMe(CSSMERR_TP_INVALID_DATA); + } + } + atvp->valueType = BER_TAG_PRINTABLE_STRING; + } + /* other special cases per RFC 3280 */ + else if(tpCompareOids(&CSSMOID_DNQualifier, nameOid->oid)) { + atvp->valueType = BER_TAG_PRINTABLE_STRING; + } + else if(tpCompareOids(&CSSMOID_SerialNumber, nameOid->oid)) { + atvp->valueType = BER_TAG_PRINTABLE_STRING; + } + else if(tpCompareOids(&CSSMOID_EmailAddress, nameOid->oid)) { + atvp->valueType = BER_TAG_IA5_STRING; + } + else { + /* Default type */ + atvp->valueType = BER_TAG_PKIX_UTF8_STRING; + } + atvp->value.Data = (uint8 *)malloc(atvp->value.Length); + memmove(atvp->value.Data, nameOid->string, atvp->value.Length); + } + return top; +} + +/* free the CSSM_X509_NAME obtained from buildX509Name */ +void AppleTPSession::freeX509Name( + CSSM_X509_NAME *top) +{ + if(top == NULL) { + return; + } + unsigned nameDex; + CSSM_X509_RDN_PTR rdn; + for(nameDex=0; nameDexnumberOfRDNs; nameDex++) { + rdn = &top->RelativeDistinguishedName[nameDex]; + if(rdn->AttributeTypeAndValue) { + for(unsigned aDex=0; aDexnumberOfPairs; aDex++) { + CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = + &rdn->AttributeTypeAndValue[aDex]; + free(atvp->type.Data); + free(atvp->value.Data); + } + free(rdn->AttributeTypeAndValue); + } + } + free(top->RelativeDistinguishedName); + free(top); +} + +/* Obtain a CSSM_X509_TIME representing "now" plus specified seconds */ + +/* + * Although RFC 2459, *the* spec for X509 certs, allows for not before/after + * times to be expressed in ther generalized (4-digit year) or UTC (2-digit year + * with implied century rollover), IE 5 on Mac will not accept the generalized + * format. + */ +#define TP_FOUR_DIGIT_YEAR 0 +#if TP_FOUR_DIGIT_YEAR +#define TP_TIME_FORMAT TIME_GEN +#define TP_TIME_TAG BER_TAG_GENERALIZED_TIME +#else +#define TP_TIME_FORMAT TIME_UTC +#define TP_TIME_TAG BER_TAG_UTC_TIME +#endif /* TP_FOUR_DIGIT_YEAR */ + +CSSM_X509_TIME * AppleTPSession::buildX509Time( + unsigned secondsFromNow) +{ + CSSM_X509_TIME *xtime = (CSSM_X509_TIME *)malloc(sizeof(CSSM_X509_TIME)); + xtime->timeType = TP_TIME_TAG; + char *ts = (char *)malloc(GENERALIZED_TIME_STRLEN + 1); + { + StLock _(tpTimeLock()); + timeAtNowPlus(secondsFromNow, TP_TIME_FORMAT, ts); + } + xtime->time.Data = (uint8 *)ts; + xtime->time.Length = strlen(ts); + return xtime; +} + +/* Free CSSM_X509_TIME obtained in buildX509Time */ +void AppleTPSession::freeX509Time( + CSSM_X509_TIME *xtime) +{ + if(xtime == NULL) { + return; + } + free((char *)xtime->time.Data); + free(xtime); +} + +/* + * Cook up a CSSM_DATA with specified integer, DER style (minimum number of + * bytes, big-endian). + */ +static void intToDER( + CSSM_INTPTR theInt, + CSSM_DATA &DER_Data, + Allocator &alloc) +{ + /* + * Calculate length in bytes of encoded integer, minimum length of 1. + */ + DER_Data.Length = 1; + uintptr_t unsignedInt = (uintptr_t)theInt; + while(unsignedInt > 0xff) { + DER_Data.Length++; + unsignedInt >>= 8; + } + + /* + * DER encoding requires top bit to be zero, else it's a negative number. + * Even though we're passing around integers as CSSM_INTPTR, they really are + * always unsigned. + * unsignedInt contains the m.s. byte of theInt in its l.s. byte. + */ + if(unsignedInt & 0x80) { + DER_Data.Length++; + } + + DER_Data.Data = (uint8 *)alloc.malloc(DER_Data.Length); + uint8 *dst = DER_Data.Data + DER_Data.Length - 1; + unsignedInt = (uintptr_t)theInt; + for(unsigned dex=0; dex>= 8; + } +} + +/* The reverse of the above. */ +static CSSM_INTPTR DERToInt( + const CSSM_DATA &DER_Data) +{ + CSSM_INTPTR rtn = 0; + uint8 *bp = DER_Data.Data; + for(unsigned dex=0; dexKeyHeader.BlobType) { + case CSSM_KEYBLOB_RAW: + actPubKey = subjectPubKey; + break; + case CSSM_KEYBLOB_REFERENCE: + refKeyToRaw(cspHand, subjectPubKey, &rawPubKey); + actPubKey = &rawPubKey; + freeRawKey = CSSM_TRUE; + break; + default: + tpCredDebug("CSSM_CL_CertCreateTemplate: bad key blob type (%u)", + (unsigned)subjectPubKey->KeyHeader.BlobType); + CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); + } + + + /* + * version, always 2 (X509v3) + * serialNumber thru subjectPubKey + */ + unsigned numFields = 8 + numExtensions; + if(subjectUniqueId) { + numFields++; + } + if(issuerUniqueId) { + numFields++; + } + + certTemp = (CSSM_FIELD *)malloc(sizeof(CSSM_FIELD) * numFields); + + + /* version */ + intToDER(2, versionDER, *this); + certTemp[fieldDex].FieldOid = CSSMOID_X509V1Version; + certTemp[fieldDex++].FieldValue = versionDER; + + /* serial number */ + intToDER(serialNumber, serialDER, *this); + certTemp[fieldDex].FieldOid = CSSMOID_X509V1SerialNumber; + certTemp[fieldDex++].FieldValue = serialDER; + + /* subject and issuer name */ + certTemp[fieldDex].FieldOid = CSSMOID_X509V1IssuerNameCStruct; + certTemp[fieldDex].FieldValue.Data = (uint8 *)issuerName; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME); + + certTemp[fieldDex].FieldOid = CSSMOID_X509V1SubjectNameCStruct; + certTemp[fieldDex].FieldValue.Data = (uint8 *)subjectName; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME); + + /* not before/after */ + certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotBefore; + certTemp[fieldDex].FieldValue.Data = (uint8 *)notBefore; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME); + + certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotAfter; + certTemp[fieldDex].FieldValue.Data = (uint8 *)notAfter; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME); + + /* the subject key */ + certTemp[fieldDex].FieldOid = CSSMOID_CSSMKeyStruct; + certTemp[fieldDex].FieldValue.Data = (uint8 *)actPubKey; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_KEY); + + /* signature algorithm */ + certTemp[fieldDex].FieldOid = CSSMOID_X509V1SignatureAlgorithmTBS; + certTemp[fieldDex].FieldValue.Data = (uint8 *)&algId; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_ALGORITHM_IDENTIFIER); + + /* subject/issuer unique IDs */ + if(subjectUniqueId != 0) { + certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateSubjectUniqueId; + certTemp[fieldDex++].FieldValue = *subjectUniqueId; + } + if(issuerUniqueId != 0) { + certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateIssuerUniqueId; + certTemp[fieldDex++].FieldValue = *issuerUniqueId; + } + + for(extNum=0; extNumformat == CSSM_X509_DATAFORMAT_PARSED) { + certTemp[fieldDex].FieldOid = ext->extnId; + } + else { + certTemp[fieldDex].FieldOid = CSSMOID_X509V3CertificateExtensionCStruct; + } + certTemp[fieldDex].FieldValue.Data = (uint8 *)ext; + certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_EXTENSION); + } + assert(fieldDex == numFields); + + /* + * OK, here we go + */ + rawCert = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); + rawCert->Data = NULL; + rawCert->Length = 0; + CSSM_RETURN crtn = CSSM_CL_CertCreateTemplate(clHand, + fieldDex, + certTemp, + rawCert); + if(crtn) { + tpCredDebug("CSSM_CL_CertCreateTemplate returned %ld", (long)crtn); + free(rawCert->Data); + free(rawCert); + rawCert = NULL; + } + + /* free the stuff we mallocd to get here */ + free(serialDER.Data); + free(versionDER.Data); + free(certTemp); + if(freeRawKey) { + tpFreeCssmData(*this, &rawPubKey.KeyData, CSSM_FALSE); + } + if(crtn) { + CssmError::throwMe(crtn); + } +} + +/* given a cert and a ReferenceIdentifier, fill in ReferenceIdentifier and + * add it and the cert to tpCredMap. */ +void AppleTPSession::addCertToMap( + const CSSM_DATA *cert, + CSSM_DATA_PTR refId) +{ + StLock _(tpCredMapLock); + + TpCredHandle hand = reinterpret_cast(cert); + intToDER(hand, *refId, *this); + tpCredMap[hand] = cert; +} + +/* given a ReferenceIdentifier, obtain associated cert and remove from the map */ +CSSM_DATA_PTR AppleTPSession::getCertFromMap( + const CSSM_DATA *refId) +{ + StLock _(tpCredMapLock); + CSSM_DATA_PTR rtn = NULL; + + if((refId == NULL) || (refId->Data == NULL)) { + return NULL; + } + TpCredHandle hand = DERToInt(*refId); + credMap::iterator it = tpCredMap.find(hand); + if(it == tpCredMap.end()) { + return NULL; + } + rtn = const_cast(it->second); + tpCredMap.erase(hand); + return rtn; +} + +/* + * SubmitCredRequest, CSR form. + */ +void AppleTPSession::SubmitCsrRequest( + const CSSM_TP_REQUEST_SET &RequestInput, + const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext, + sint32 &EstimatedTime, // RETURNED + CssmData &ReferenceIdentifier) // RETURNED +{ + CSSM_DATA_PTR csrPtr = NULL; + CSSM_CC_HANDLE sigHand = 0; + CSSM_APPLE_CL_CSR_REQUEST csrReq; + + memset(&csrReq, 0, sizeof(csrReq)); + + /* for now we're using the same struct for input as the the normal + * X509 cert request. */ + CSSM_APPLE_TP_CERT_REQUEST *certReq = + (CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests; + if((certReq->cspHand == 0) || + (certReq->clHand == 0) || + (certReq->certPublicKey == NULL) || + (certReq->issuerPrivateKey == NULL) || + (certReq->signatureOid.Data == NULL)) { + CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); + } + + /* convert ref public key to raw per CL requirements */ + const CSSM_KEY *subjectPubKey = certReq->certPublicKey; + const CSSM_KEY *actPubKey = NULL; + CSSM_BOOL freeRawKey = CSSM_FALSE; + CSSM_KEY rawPubKey; + + switch(subjectPubKey->KeyHeader.BlobType) { + case CSSM_KEYBLOB_RAW: + actPubKey = subjectPubKey; + break; + case CSSM_KEYBLOB_REFERENCE: + refKeyToRaw(certReq->cspHand, subjectPubKey, &rawPubKey); + actPubKey = &rawPubKey; + freeRawKey = CSSM_TRUE; + break; + default: + tpCredDebug("SubmitCsrRequest: bad key blob type (%u)", + (unsigned)subjectPubKey->KeyHeader.BlobType); + CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); + } + + /* cook up a CL-passthrough-specific request */ + csrReq.subjectNameX509 = buildX509Name(certReq->subjectNames, + certReq->numSubjectNames); + csrReq.signatureAlg = certReq->signatureAlg; + csrReq.signatureOid = certReq->signatureOid; + csrReq.cspHand = certReq->cspHand; + csrReq.subjectPublicKey = actPubKey; + csrReq.subjectPrivateKey = certReq->issuerPrivateKey; + csrReq.challengeString = certReq->challengeString; + + /* A crypto handle to pass to the CL */ + CSSM_RETURN crtn; + crtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand, + certReq->signatureAlg, + (CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL), + certReq->issuerPrivateKey, + &sigHand); + if(crtn) { + tpCredDebug("CSSM_CSP_CreateSignatureContext returned %ld", (long)crtn); + goto abort; + } + + /* down to the CL to do the actual work */ + crtn = CSSM_CL_PassThrough(certReq->clHand, + sigHand, + CSSM_APPLEX509CL_OBTAIN_CSR, + &csrReq, + (void **)&csrPtr); + if(crtn) { + tpCredDebug("CSSM_CL_PassThrough returned %ld", (long)crtn); + goto abort; + } + + /* save it for retrieval by RetrieveCredResult */ + addCertToMap(csrPtr, &ReferenceIdentifier); + EstimatedTime = 0; + +abort: + /* free local resources */ + if(csrReq.subjectNameX509) { + freeX509Name(csrReq.subjectNameX509); + } + if(sigHand) { + CSSM_DeleteContext(sigHand); + } + if(freeRawKey) { + tpFreeCssmData(*this, &rawPubKey.KeyData, CSSM_FALSE); + } + if(crtn) { + CssmError::throwMe(crtn); + } +} + +/* + * Submit cred (cert) request. Currently the only form of request we + * handle is the basis "sign this cert with key right now", with policy OI + * CSSMOID_APPLE_TP_LOCAL_CERT_GEN. + */ +void AppleTPSession::SubmitCredRequest( + const CSSM_TP_AUTHORITY_ID *PreferredAuthority, + CSSM_TP_AUTHORITY_REQUEST_TYPE RequestType, + const CSSM_TP_REQUEST_SET &RequestInput, + const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthContext, + sint32 &EstimatedTime, + CssmData &ReferenceIdentifier) +{ + /* free all of these on return if non-NULL */ + CSSM_DATA_PTR certTemplate = NULL; + CSSM_X509_TIME_PTR notBeforeX509 = NULL; + CSSM_X509_TIME_PTR notAfterX509 = NULL; + CSSM_X509_NAME_PTR subjectX509 = NULL; + CSSM_X509_NAME_PTR issuerX509 = NULL; + CSSM_X509_EXTENSION_PTR extens509 = NULL; + CSSM_CC_HANDLE sigContext = 0; + + /* this gets saved on success */ + CSSM_DATA_PTR signedCert = NULL; + + /* validate rather limited set of input args */ + if(PreferredAuthority != NULL) { + CssmError::throwMe(CSSMERR_TP_INVALID_AUTHORITY); + } + if(RequestType != CSSM_TP_AUTHORITY_REQUEST_CERTISSUE) { + CssmError::throwMe(CSSMERR_TP_UNSUPPORTED_SERVICE); + } + if(CallerAuthContext == NULL) { + CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER); + } + if((RequestInput.NumberOfRequests != 1) || + (RequestInput.Requests == NULL)) { + CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); + } + + /* Apple-specific args */ + const CSSM_TP_POLICYINFO *tpPolicy = &CallerAuthContext->Policy; + if((tpPolicy->NumberOfPolicyIds != 1) || + (tpPolicy->PolicyIds == NULL)) { + CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER); + } + if(tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid, + &CSSMOID_APPLE_TP_CSR_GEN)) { + /* break out to CSR-specific code */ + SubmitCsrRequest(RequestInput, CallerAuthContext, EstimatedTime, ReferenceIdentifier); + return; + } + else if(!tpCompareCssmData(&tpPolicy->PolicyIds->FieldOid, + &CSSMOID_APPLE_TP_LOCAL_CERT_GEN)) { + CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS); + } + + CSSM_APPLE_TP_CERT_REQUEST *certReq = + (CSSM_APPLE_TP_CERT_REQUEST *)RequestInput.Requests; + if((certReq->cspHand == 0) || + (certReq->clHand == 0) || + (certReq->certPublicKey == NULL) || + (certReq->issuerPrivateKey == NULL)) { + CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); + } + if((certReq->numExtensions != 0) & (certReq->extensions == NULL)) { + CssmError::throwMe(CSSMERR_TP_INVALID_POINTER); + } + + CSSM_RETURN ourRtn = CSSM_OK; + + try { + /* convert caller's friendly names and times to CDSA style */ + subjectX509 = buildX509Name(certReq->subjectNames, certReq->numSubjectNames); + if(certReq->issuerNames != NULL) { + issuerX509 = buildX509Name(certReq->issuerNames, certReq->numIssuerNames); + } + else if(certReq->issuerNameX509) { + /* caller obtained this from an existing signer's cert */ + issuerX509 = certReq->issuerNameX509; + } + else { + /* self-signed */ + issuerX509 = subjectX509; + } + notBeforeX509 = buildX509Time(certReq->notBefore); + notAfterX509 = buildX509Time(certReq->notAfter); + + if(certReq->numExtensions != 0) { + /* convert extensions array from CE_DataAndType to CSSM_X509_EXTENSION */ + extens509 = (CSSM_X509_EXTENSION *)malloc(sizeof(CSSM_X509_EXTENSION) * + certReq->numExtensions); + memset(extens509, 0, sizeof(CSSM_X509_EXTENSION) * + certReq->numExtensions); + for(unsigned dex=0; dexnumExtensions; dex++) { + CSSM_X509_EXTENSION *extn = &extens509[dex]; + CE_DataAndType *cdt = &certReq->extensions[dex]; + void *parsedValue; + CSSM_OID extnId; + + switch(cdt->type) { + case DT_AuthorityKeyID: + parsedValue = &cdt->extension.authorityKeyID; + extnId = CSSMOID_AuthorityKeyIdentifier; + break; + case DT_SubjectKeyID: + parsedValue = &cdt->extension.subjectKeyID; + extnId = CSSMOID_SubjectKeyIdentifier; + break; + case DT_KeyUsage: + parsedValue = &cdt->extension.keyUsage; + extnId = CSSMOID_KeyUsage; + break; + case DT_SubjectAltName: + parsedValue = &cdt->extension.subjectAltName; + extnId = CSSMOID_SubjectAltName; + break; + case DT_IssuerAltName: + parsedValue = &cdt->extension.issuerAltName; + extnId = CSSMOID_IssuerAltName; + break; + case DT_ExtendedKeyUsage: + parsedValue = &cdt->extension.extendedKeyUsage; + extnId = CSSMOID_ExtendedKeyUsage; + break; + case DT_BasicConstraints: + parsedValue = &cdt->extension.basicConstraints; + extnId = CSSMOID_BasicConstraints; + break; + case DT_CertPolicies: + parsedValue = &cdt->extension.certPolicies; + extnId = CSSMOID_CertificatePolicies; + break; + case DT_NetscapeCertType: + parsedValue = &cdt->extension.netscapeCertType; + extnId = CSSMOID_NetscapeCertType; + break; + case DT_CrlDistributionPoints: + parsedValue = &cdt->extension.crlDistPoints; + extnId = CSSMOID_CrlDistributionPoints; + break; + case DT_AuthorityInfoAccess: + parsedValue = &cdt->extension.authorityInfoAccess; + extnId = CSSMOID_AuthorityInfoAccess; + break; + case DT_Other: + default: + tpCredDebug("SubmitCredRequest: DT_Other not supported"); + CssmError::throwMe(CSSMERR_TP_UNKNOWN_TAG); + // NOT REACHED + } + extn->extnId = extnId; + extn->critical = cdt->critical; + extn->format = CSSM_X509_DATAFORMAT_PARSED; + extn->value.parsedValue = parsedValue; + extn->BERvalue.Data = NULL; + extn->BERvalue.Length = 0; + } /* for each extension */ + } /* converting extensions */ + + /* cook up the unsigned template */ + makeCertTemplate(certReq->clHand, + certReq->cspHand, + certReq->serialNumber, + issuerX509, + subjectX509, + notBeforeX509, + notAfterX509, + certReq->certPublicKey, + certReq->signatureOid, + NULL, // subjectUniqueID, not used here (yet) + NULL, // issuerUniqueId + extens509, + certReq->numExtensions, + certTemplate); + + /* create signature context */ + ourRtn = CSSM_CSP_CreateSignatureContext(certReq->cspHand, + certReq->signatureAlg, + (CallerAuthContext ? CallerAuthContext->CallerCredentials : NULL), + certReq->issuerPrivateKey, + &sigContext); + if(ourRtn) { + tpCredDebug("CSSM_CSP_CreateSignatureContext returned %ld", (long)ourRtn); + CssmError::throwMe(ourRtn); + } + + signedCert = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); + signedCert->Data = NULL; + signedCert->Length = 0; + ourRtn = CSSM_CL_CertSign(certReq->clHand, + sigContext, + certTemplate, // CertToBeSigned + NULL, // SignScope + 0, // ScopeSize, + signedCert); + if(ourRtn) { + tpCredDebug("CSSM_CL_CertSign returned %ld", (long)ourRtn); + CssmError::throwMe(ourRtn); + } + + /* save it for retrieval by RetrieveCredResult */ + addCertToMap(signedCert, &ReferenceIdentifier); + EstimatedTime = 0; + } + catch (const CssmError &cerr) { + tpCredDebug("SubmitCredRequest: CSSM error %ld", (long)cerr.error); + ourRtn = cerr.error; + } + catch(...) { + tpCredDebug("SubmitCredRequest: unknown exception"); + ourRtn = CSSMERR_TP_INTERNAL_ERROR; // ?? + } + + /* free reources */ + tpFreeCssmData(*this, certTemplate, CSSM_TRUE); + freeX509Name(subjectX509); + if(certReq->issuerNames) { + freeX509Name(issuerX509); + } + /* else same as subject */ + freeX509Time(notBeforeX509); + freeX509Time(notAfterX509); + if(extens509) { + free(extens509); + } + if(sigContext != 0) { + CSSM_DeleteContext(sigContext); + } + if(ourRtn) { + CssmError::throwMe(ourRtn); + } +} + +void AppleTPSession::RetrieveCredResult( + const CssmData &ReferenceIdentifier, + const CSSM_TP_CALLERAUTH_CONTEXT *CallerAuthCredentials, + sint32 &EstimatedTime, + CSSM_BOOL &ConfirmationRequired, + CSSM_TP_RESULT_SET_PTR &RetrieveOutput) +{ + CSSM_DATA *cert = getCertFromMap(&ReferenceIdentifier); + + if(cert == NULL) { + tpCredDebug("RetrieveCredResult: refId not found"); + CssmError::throwMe(CSSMERR_TP_INVALID_IDENTIFIER); + } + + /* CSSM_TP_RESULT_SET.Results points to a CSSM_ENCODED_CERT */ + CSSM_ENCODED_CERT *encCert = (CSSM_ENCODED_CERT *)malloc(sizeof(CSSM_ENCODED_CERT)); + encCert->CertType = CSSM_CERT_X_509v3; + encCert->CertEncoding = CSSM_CERT_ENCODING_DER; + + /* + * caller must free all three: + * CSSM_TP_RESULT_SET_PTR RetrieveOutput + * RetrieveOutput->Results (CSSM_ENCODED_CERT *encCert) + * encCert->CertBlob.Data (the actual cert) + * We free: + * cert -- mallocd in SubmitCredRequest + */ + encCert->CertBlob = *cert; + RetrieveOutput = (CSSM_TP_RESULT_SET_PTR)malloc( + sizeof(CSSM_TP_RESULT_SET)); + RetrieveOutput->Results = encCert; + RetrieveOutput->NumberOfResults = 1; + ConfirmationRequired = CSSM_FALSE; + free(cert); + EstimatedTime = 0; +}