--- /dev/null
+/*
+ * Copyright (c) 2000-2001 Apple Computer, 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.
+ */
+
+
+//
+// Session_Cert.cpp - cert-related session functions.
+//
+
+#include "AppleX509CLSession.h"
+#include "DecodedCert.h"
+#include "DecodedCrl.h"
+#include "CLCachedEntry.h"
+#include "cldebugging.h"
+#include <Security/oidscert.h>
+
+void
+AppleX509CLSession::CertDescribeFormat(
+ uint32 &NumberOfFields,
+ CSSM_OID_PTR &OidList)
+{
+ DecodedCert::describeFormat(*this, NumberOfFields, OidList);
+}
+
+void
+AppleX509CLSession::CertGetAllFields(
+ const CssmData &Cert,
+ uint32 &NumberOfFields,
+ CSSM_FIELD_PTR &CertFields)
+{
+ DecodedCert decodedCert(*this, Cert);
+ decodedCert.getAllParsedCertFields(NumberOfFields, CertFields);
+}
+
+
+CSSM_HANDLE
+AppleX509CLSession::CertGetFirstFieldValue(
+ const CssmData &EncodedCert,
+ const CssmData &CertField,
+ uint32 &NumberOfMatchedFields,
+ CSSM_DATA_PTR &Value)
+{
+ NumberOfMatchedFields = 0;
+ Value = NULL;
+ CssmAutoData aData(*this);
+
+ DecodedCert *decodedCert = new DecodedCert(*this, EncodedCert);
+ uint32 numMatches;
+
+ /* this returns false if field not there, throws on bad OID */
+ bool brtn;
+ try {
+ brtn = decodedCert->getCertFieldData(CertField,
+ 0, // index
+ numMatches,
+ aData);
+ }
+ catch (...) {
+ delete decodedCert;
+ throw;
+ }
+ if(!brtn) {
+ delete decodedCert;
+ return CSSM_INVALID_HANDLE;
+ }
+
+ /* cook up a CLCachedCert, stash it in cache */
+ CLCachedCert *cachedCert = new CLCachedCert(*decodedCert);
+ cacheMap.addEntry(*cachedCert, cachedCert->handle());
+
+ /* cook up a CLQuery, stash it */
+ CLQuery *query = new CLQuery(
+ CLQ_Cert,
+ CertField,
+ numMatches,
+ false, // isFromCache
+ cachedCert->handle());
+ queryMap.addEntry(*query, query->handle());
+
+ /* success - copy field data to outgoing Value */
+ Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
+ *Value = aData.release();
+ NumberOfMatchedFields = numMatches;
+ return query->handle();
+}
+
+
+bool
+AppleX509CLSession::CertGetNextFieldValue(
+ CSSM_HANDLE ResultsHandle,
+ CSSM_DATA_PTR &Value)
+{
+ /* fetch & validate the query */
+ CLQuery *query = queryMap.lookupEntry(ResultsHandle);
+ if(query == NULL) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
+ }
+ if(query->queryType() != CLQ_Cert) {
+ clErrorLog("CertGetNextFieldValue: bad queryType (%d)", (int)query->queryType());
+ CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
+ }
+ if(query->nextIndex() >= query->numFields()) {
+ return false;
+ }
+
+ /* fetch the associated cached cert */
+ CLCachedCert *cachedCert = lookupCachedCert(query->cachedObject());
+ uint32 dummy;
+ CssmAutoData aData(*this);
+ if(!cachedCert->cert().getCertFieldData(query->fieldId(),
+ query->nextIndex(),
+ dummy,
+ aData)) {
+ return false;
+ }
+
+ /* success - copy field data to outgoing Value */
+ Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
+ *Value = aData.release();
+ query->incrementIndex();
+ return true;
+}
+
+void
+AppleX509CLSession::CertCache(
+ const CssmData &EncodedCert,
+ CSSM_HANDLE &CertHandle)
+{
+ DecodedCert *decodedCert = new DecodedCert(*this, EncodedCert);
+
+ /* cook up a CLCachedCert, stash it in cache */
+ CLCachedCert *cachedCert = new CLCachedCert(*decodedCert);
+ cacheMap.addEntry(*cachedCert, cachedCert->handle());
+ CertHandle = cachedCert->handle();
+}
+
+CSSM_HANDLE
+AppleX509CLSession::CertGetFirstCachedFieldValue(
+ CSSM_HANDLE CertHandle,
+ const CssmData &CertField,
+ uint32 &NumberOfMatchedFields,
+ CSSM_DATA_PTR &Value)
+{
+ /* fetch the associated cached cert */
+ CLCachedCert *cachedCert = lookupCachedCert(CertHandle);
+ if(cachedCert == NULL) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_CACHE_HANDLE);
+ }
+
+ CssmAutoData aData(*this);
+ uint32 numMatches;
+
+ /* this returns false if field not there, throws on bad OID */
+ if(!cachedCert->cert().getCertFieldData(CertField,
+ 0, // index
+ numMatches,
+ aData)) {
+ return CSSM_INVALID_HANDLE;
+ }
+
+ /* cook up a CLQuery, stash it */
+ CLQuery *query = new CLQuery(
+ CLQ_Cert,
+ CertField,
+ numMatches,
+ true, // isFromCache
+ cachedCert->handle());
+ queryMap.addEntry(*query, query->handle());
+
+ /* success - copy field data to outgoing Value */
+ Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
+ *Value = aData.release();
+ NumberOfMatchedFields = numMatches;
+ return query->handle();
+}
+
+
+bool
+AppleX509CLSession::CertGetNextCachedFieldValue(
+ CSSM_HANDLE ResultsHandle,
+ CSSM_DATA_PTR &Value)
+{
+ /* Identical to, so just call... */
+ return CertGetNextFieldValue(ResultsHandle, Value);
+}
+
+void
+AppleX509CLSession::CertAbortCache(
+ CSSM_HANDLE CertHandle)
+{
+ /* fetch the associated cached cert, remove from map, delete it */
+ CLCachedCert *cachedCert = lookupCachedCert(CertHandle);
+ if(cachedCert == NULL) {
+ clErrorLog("CertAbortCache: cachedCert not found");
+ CssmError::throwMe(CSSMERR_CL_INVALID_CACHE_HANDLE);
+ }
+ cacheMap.removeEntry(cachedCert->handle());
+ delete cachedCert;
+}
+
+/*
+ * Abort either type of cert field query (cache based or non-cache based)
+ */
+void
+AppleX509CLSession::CertAbortQuery(
+ CSSM_HANDLE ResultsHandle)
+{
+ /* fetch & validate the query */
+ CLQuery *query = queryMap.lookupEntry(ResultsHandle);
+ if(query == NULL) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
+ }
+ if(query->queryType() != CLQ_Cert) {
+ clErrorLog("CertAbortQuery: bad queryType (%d)", (int)query->queryType());
+ CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
+ }
+
+ if(!query->fromCache()) {
+ /* the associated cached cert was created just for this query; dispose */
+ CLCachedCert *cachedCert = lookupCachedCert(query->cachedObject());
+ if(cachedCert == NULL) {
+ /* should never happen */
+ clErrorLog("CertAbortQuery: cachedCert not found");
+ CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
+ }
+ cacheMap.removeEntry(cachedCert->handle());
+ delete cachedCert;
+ }
+ queryMap.removeEntry(query->handle());
+ delete query;
+}
+
+void
+AppleX509CLSession::CertCreateTemplate(
+ uint32 NumberOfFields,
+ const CSSM_FIELD CertFields[],
+ CssmData &CertTemplate)
+{
+ /* cook up an empty Cert */
+ DecodedCert cert(*this);
+
+ /* grind thru specified fields; exceptions are fatal */
+ for(uint32 dex=0; dex<NumberOfFields; dex++) {
+ cert.setCertField(
+ CssmOid::overlay(CertFields[dex].FieldOid),
+ CssmData::overlay(CertFields[dex].FieldValue));
+ }
+
+ /* TBD - ensure all required fields are set? We do this
+ * when we sign the cert; maybe we should do it here. */
+
+ /*
+ * We have the CertificateToSign in NSS format. Encode.
+ */
+ CertTemplate.Data = NULL;
+ CertTemplate.Length = 0;
+ CssmRemoteData rData(*this, CertTemplate);
+ cert.encodeTbs(rData);
+ rData.release();
+}
+
+
+void
+AppleX509CLSession::CertGetAllTemplateFields(
+ const CssmData &CertTemplate,
+ uint32 &NumberOfFields,
+ CSSM_FIELD_PTR &CertFields)
+{
+ DecodedCert cert(*this); // empty
+ cert.decodeTbs(CertTemplate);
+ cert.getAllParsedCertFields(NumberOfFields, CertFields);
+}
+
+void
+AppleX509CLSession::FreeFields(
+ uint32 NumberOfFields,
+ CSSM_FIELD_PTR &FieldArray)
+{
+ unsigned i;
+ CSSM_FIELD_PTR thisField;
+ CSSM_OID_PTR thisOid;
+
+ for(i=0; i<NumberOfFields; i++) {
+ thisField = &FieldArray[i];
+ thisOid = &thisField->FieldOid;
+
+ /* oid-specific handling of value */
+ /* BUG - the CssmRemoteData constructor clears the referent,
+ * iff the referent is a CSSSM_DATA (as opposed to a CssmData).
+ */
+ CssmData &cData = CssmData::overlay(thisField->FieldValue);
+ CssmRemoteData rData(*this, cData);
+ try {
+ DecodedCert::freeCertFieldData(CssmOid::overlay(*thisOid), rData);
+ }
+ catch(...) {
+ /* CRL field? */
+ DecodedCrl::freeCrlFieldData(CssmOid::overlay(*thisOid), rData);
+ }
+ /* and the oid itself */
+ free(thisOid->Data);
+ thisOid->Data = NULL;
+ thisOid->Length = 0;
+ }
+ free(FieldArray);
+}
+
+void
+AppleX509CLSession::FreeFieldValue(
+ const CssmData &CertOrCrlOid,
+ CssmData &Value)
+{
+ CssmRemoteData cd(*this, Value);
+ try {
+ DecodedCert::freeCertFieldData(CertOrCrlOid, cd);
+ }
+ catch(...) {
+ /* CRL field? */
+ DecodedCrl::freeCrlFieldData(CertOrCrlOid, cd);
+ }
+ free(&Value);
+}
+
+void
+AppleX509CLSession::CertGroupFromVerifiedBundle(
+ CSSM_CC_HANDLE CCHandle,
+ const CSSM_CERT_BUNDLE &CertBundle,
+ const CssmData *SignerCert,
+ CSSM_CERTGROUP_PTR &CertGroup)
+{
+ unimplemented();
+}
+
+void
+AppleX509CLSession::CertGroupToSignedBundle(
+ CSSM_CC_HANDLE CCHandle,
+ const CSSM_CERTGROUP &CertGroupToBundle,
+ const CSSM_CERT_BUNDLE_HEADER *BundleInfo,
+ CssmData &SignedBundle)
+{
+ unimplemented();
+}
+
+void
+AppleX509CLSession::PassThrough(
+ CSSM_CC_HANDLE CCHandle,
+ uint32 PassThroughId,
+ const void *InputParams,
+ void **OutputParams)
+{
+ switch(PassThroughId) {
+ case CSSM_APPLEX509CL_OBTAIN_CSR:
+ {
+ /*
+ * Create a Cert Signing Request (CSR).
+ * Input is a CSSM_APPLE_CL_CSR_REQUEST.
+ * Output is a PEM-encoded CertSigningRequest (NSS type
+ * NSS_SignedCertRequest from pkcs10).
+ */
+ if(InputParams == NULL) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_INPUT_POINTER);
+ }
+ if(OutputParams == NULL) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_OUTPUT_POINTER);
+ }
+ CSSM_APPLE_CL_CSR_REQUEST *csrReq =
+ (CSSM_APPLE_CL_CSR_REQUEST *)InputParams;
+ if((csrReq->subjectNameX509 == NULL) ||
+ (csrReq->signatureOid.Data == NULL) ||
+ (csrReq->subjectPublicKey == NULL) ||
+ (csrReq->subjectPrivateKey == NULL)) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_INPUT_POINTER);
+ }
+ CSSM_DATA_PTR csrPtr = NULL;
+ generateCsr(CCHandle, csrReq, csrPtr);
+ *OutputParams = csrPtr;
+ break;
+ }
+ case CSSM_APPLEX509CL_VERIFY_CSR:
+ {
+ /*
+ * Perform signature verify of a CSR.
+ * Input: CSSM_DATA referring to a DER-encoded CSR.
+ * Output: Nothing, throws CSSMERR_CL_VERIFICATION_FAILURE
+ * on failure.
+ */
+ if(InputParams == NULL) {
+ CssmError::throwMe(CSSMERR_CL_INVALID_INPUT_POINTER);
+ }
+ const CSSM_DATA *csrPtr = (const CSSM_DATA *)InputParams;
+ verifyCsr(csrPtr);
+ break;
+ }
+ default:
+ CssmError::throwMe(CSSMERR_CL_INVALID_PASSTHROUGH_ID);
+ }
+}
+