/* * 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); } }
/* * Find private key by label, modify its Label attr to be the * hash of the associated public key. */ static CSSM_RETURN setPubKeyHash( CSSM_CSP_HANDLE cspHand, CSSM_DL_DB_HANDLE dlDbHand, const CSSM_KEY *pubOrPrivKey, // to get hash; raw or ref/CSPDL const char *keyLabel) // look up by this { CSSM_QUERY query; CSSM_SELECTION_PREDICATE predicate; CSSM_DB_UNIQUE_RECORD_PTR record = NULL; CSSM_RETURN crtn; CSSM_DATA labelData; CSSM_HANDLE resultHand; labelData.Data = (uint8 *)keyLabel; labelData.Length = strlen(keyLabel) + 1; // incl. NULL query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; query.Conjunctive = CSSM_DB_NONE; query.NumSelectionPredicates = 1; predicate.DbOperator = CSSM_DB_EQUAL; predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; predicate.Attribute.Info.Label.AttributeName = "Label"; predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; predicate.Attribute.Value = &labelData; query.SelectionPredicate = &predicate; query.QueryLimits.TimeLimit = 0; query.QueryLimits.SizeLimit = 1; query.QueryFlags = 0; /* build Record attribute with one attr */ CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; CSSM_DB_ATTRIBUTE_DATA attr; attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; attr.Info.Label.AttributeName = "Label"; attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; recordAttrs.NumberOfAttributes = 1; recordAttrs.AttributeData = &attr; crtn = CSSM_DL_DataGetFirst(dlDbHand, &query, &resultHand, &recordAttrs, NULL, // hopefully optional ...theData, &record); /* abort only on success */ if(crtn != CSSM_OK) { sec_error("CSSM_DL_DataGetFirst: setPubKeyHash: can't find private key: %s", sec_errstr(crtn)); return crtn; } /* * If specified key is a ref key, do NULL unwrap for use with raw CSP. * If the CSPDL and SecurityServer support the key digest passthrough * this is unnecessary. */ CSSM_KEY rawKeyToDigest; if(pubOrPrivKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE) { crtn = refKeyToRaw(cspHand, pubOrPrivKey, &rawKeyToDigest); if(crtn) { sec_error("setPubKeyHash: Error converting public key to raw format: %s", sec_errstr(crtn)); return crtn; } } else { /* use as is */ rawKeyToDigest = *pubOrPrivKey; } /* connect to raw CSP */ CSSM_CSP_HANDLE rawCspHand = srCspStartup(CSSM_TRUE); if(rawCspHand == 0) { printf("***Error connecting to raw CSP; aborting.\n"); return -1; } /* calculate hash of pub key from private or public part */ CSSM_DATA_PTR keyDigest = NULL; CSSM_CC_HANDLE ccHand; crtn = CSSM_CSP_CreatePassThroughContext(rawCspHand, &rawKeyToDigest, &ccHand); if(ccHand == 0) { sec_error("CSSM_CSP_CreatePassThroughContext: Error calculating public key hash. Aborting: %s", sec_errstr(crtn)); return -1; } crtn = CSSM_CSP_PassThrough(ccHand, CSSM_APPLECSP_KEYDIGEST, NULL, (void **)&keyDigest); if(crtn) { sec_error("CSSM_CSP_PassThrough(PUBKEYHASH): Error calculating public key hash. Aborting: %s", sec_errstr(crtn)); return crtn; } if(pubOrPrivKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE) { /* created in refKeyToRaw().... */ CSSM_FreeKey(cspHand, NULL, &rawKeyToDigest, CSSM_FALSE); } CSSM_DeleteContext(ccHand); CSSM_ModuleDetach(rawCspHand); /* * Replace Label attr data with hash. * NOTE: the module which allocated this attribute data - a DL - * was loaded and attached by the Sec layer, not by us. Thus * we can't use the memory allocator functions *we* used when * attaching to the CSPDL - we have to use the ones * which the Sec layer registered with the DL. */ CSSM_API_MEMORY_FUNCS memFuncs; crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs); if(crtn) { sec_error("CSSM_GetAPIMemoryFunctions(DLHandle): Error: %s", sec_errstr(crtn)); /* oh well, leak and continue */ } else { memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef); memFuncs.free_func(attr.Value, memFuncs.AllocRef); } attr.Value = keyDigest; /* modify key attributes */ crtn = CSSM_DL_DataModify(dlDbHand, CSSM_DL_DB_RECORD_PRIVATE_KEY, record, &recordAttrs, NULL, // DataToBeModified CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); if(crtn) { sec_error("CSSM_DL_DataModify(PUBKEYHASH): Error setting public key hash. Aborting: %s", sec_errstr(crtn)); return crtn; } crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand); if(crtn) { sec_error("CSSM_DL_DataAbortQuery: Error while stopping query: %s", sec_errstr(crtn)); /* let's keep going in this case */ } crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record); if(crtn) { sec_error("CSSM_DL_FreeUniqueRecord: Error while freeing record: %s", sec_errstr(crtn)); /* let's keep going in this case */ crtn = CSSM_OK; } /* free resources */ if (keyDigest) { srAppFree(keyDigest->Data, NULL); srAppFree(keyDigest, NULL); } return CSSM_OK; }
/* * Cook up an unsigned cert. * This is just a wrapper for CSSM_CL_CertCreateTemplate(). */ void AppleTPSession::makeCertTemplate( /* required */ CSSM_CL_HANDLE clHand, CSSM_CSP_HANDLE cspHand, // for converting ref to raw key uint32 serialNumber, const CSSM_X509_NAME *issuerName, const CSSM_X509_NAME *subjectName, const CSSM_X509_TIME *notBefore, const CSSM_X509_TIME *notAfter, const CSSM_KEY *subjectPubKey, const CSSM_OID &sigOid, // e.g., CSSMOID_SHA1WithRSA /* optional */ const CSSM_DATA *subjectUniqueId, const CSSM_DATA *issuerUniqueId, CSSM_X509_EXTENSION *extensions, unsigned numExtensions, CSSM_DATA_PTR &rawCert) { CSSM_FIELD *certTemp; unsigned fieldDex = 0; // index into certTemp CSSM_DATA serialDER = {0, NULL}; // serial number, DER format CSSM_DATA versionDER = {0, NULL}; unsigned extNum; CSSM_X509_ALGORITHM_IDENTIFIER algId; const CSSM_KEY *actPubKey; CSSM_KEY rawPubKey; CSSM_BOOL freeRawKey = CSSM_FALSE; rawCert = NULL; algId.algorithm = sigOid; algId.parameters.Data = NULL; algId.parameters.Length = 0; /* * Convert possible ref public key to raw format as required by CL. */ switch(subjectPubKey->KeyHeader.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; extNum<numExtensions; extNum++) { CSSM_X509_EXTENSION_PTR ext = &extensions[extNum]; if(ext->format == 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); } }