--- /dev/null
+/*
+ * Copyright (c) 2003-2005 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.
+ */
+
+/*
+ * CertParser.h - cert parser with autorelease of fetched fields
+ *
+ * Created 24 October 2003 by Doug Mitchell
+ */
+
+#include "CertParser.h"
+#import <AvailabilityMacros.h>
+
+#define CP_DEBUG 1
+#if CP_DEBUG
+#define dprintf(args...) printf(args)
+#else
+#define dprintf(args...)
+#endif
+
+#pragma mark --- CP_FetchedField ---
+
+class CP_FetchedField
+{
+public:
+ /* construct one fetched field (which will be stored in CertParser's
+ * mFetchedFields) */
+ CP_FetchedField(
+ const CSSM_OID &fieldOid,
+ CSSM_DATA_PTR fieldData,
+ CSSM_CL_HANDLE clHand);
+
+ /* Free the field via CL */
+ ~CP_FetchedField();
+private:
+ CSSM_OID mFieldOid;
+ CSSM_DATA_PTR mFieldData;
+ CSSM_CL_HANDLE mClHand;
+};
+
+CP_FetchedField::CP_FetchedField(
+ const CSSM_OID &fieldOid,
+ CSSM_DATA_PTR fieldData,
+ CSSM_CL_HANDLE clHand)
+ : mFieldOid(fieldOid), mFieldData(fieldData), mClHand(clHand)
+{
+}
+
+/* Free the field via CL */
+CP_FetchedField::~CP_FetchedField()
+{
+ CSSM_CL_FreeFieldValue(mClHand, &mFieldOid, mFieldData);
+}
+
+#pragma mark --- CertParser implementation ---
+
+/* Construct with or without data - you can add the data later with
+ * initWithData() to parse without exceptions */
+CertParser::CertParser()
+{
+ initFields();
+}
+
+CertParser::CertParser(
+ CSSM_CL_HANDLE clHand)
+{
+ initFields();
+ mClHand = clHand;
+}
+
+CertParser::CertParser(
+ CSSM_CL_HANDLE clHand,
+ const CSSM_DATA &certData)
+{
+ initFields();
+ mClHand = clHand;
+ CSSM_RETURN crtn = initWithData(certData);
+ if(crtn) {
+ throw ((int)crtn);
+ }
+}
+
+CertParser::CertParser(
+ SecCertificateRef secCert)
+{
+ initFields();
+ OSStatus ortn = initWithSecCert(secCert);
+ if(ortn) {
+ throw ((int)ortn);
+ }
+}
+
+/* frees all the fields we fetched */
+CertParser::~CertParser()
+{
+ if(mClHand && mCacheHand) {
+ CSSM_RETURN crtn = CSSM_CL_CertAbortCache(mClHand, mCacheHand);
+ if(crtn) {
+ /* almost certainly a bug */
+ printf("Internal Error: CertParser error on free.");
+ cssmPerror("CSSM_CL_CertAbortCache", crtn);
+ }
+ }
+ vector<CP_FetchedField *>::iterator iter;
+ for(iter=mFetchedFields.begin(); iter!=mFetchedFields.end(); iter++) {
+ delete *iter;
+ }
+}
+
+/* common init for all constructors */
+void CertParser::initFields()
+{
+ mClHand = 0;
+ mCacheHand = 0;
+}
+
+/*** NO MORE EXCEPTIONS ***/
+
+/*
+ * No cert- or CDSA-related exceptions thrown by remainder.
+ * This is the core initializer: have the CL parse and cache the cert.
+ */
+CSSM_RETURN CertParser::initWithData(
+ const CSSM_DATA &certData)
+{
+ assert(mClHand != 0);
+ CSSM_RETURN crtn = CSSM_CL_CertCache(mClHand, &certData, &mCacheHand);
+ #if CP_DEBUG
+ if(crtn) {
+ cssmPerror("CSSM_CL_CertCache", crtn);
+ }
+ #endif
+ return crtn;
+}
+
+OSStatus CertParser::initWithSecCert(
+ SecCertificateRef secCert)
+{
+ OSStatus ortn;
+ CSSM_DATA certData;
+
+ assert(mClHand == 0);
+ ortn = SecCertificateGetCLHandle(secCert, &mClHand);
+ if(ortn) {
+ return ortn;
+ }
+ ortn = SecCertificateGetData(secCert, &certData);
+ if(ortn) {
+ return ortn;
+ }
+ return (OSStatus)initWithData(certData);
+}
+
+CSSM_RETURN CertParser::initWithCFData(
+ CFDataRef cfData)
+{
+ CSSM_DATA cdata;
+
+ cdata.Data = (uint8 *)CFDataGetBytePtr(cfData);
+ cdata.Length = CFDataGetLength(cfData);
+ return initWithData(cdata);
+}
+
+/*
+ * Obtain atrbitrary field from cached cert. This class takes care of freeing
+ * the field in its destructor.
+ *
+ * Returns NULL if field not found (not exception).
+ *
+ * Caller optionally specifies field length to check - specifying zero means
+ * "don't care, don't check". Actual field length always returned in fieldLength.
+ */
+const void *CertParser::fieldForOid(
+ const CSSM_OID &oid,
+ CSSM_SIZE &fieldLength) // IN/OUT
+{
+ CSSM_RETURN crtn;
+
+ uint32 NumberOfFields = 0;
+ CSSM_HANDLE resultHand = 0;
+ CSSM_DATA_PTR fieldData = NULL;
+
+ assert(mClHand != 0);
+ assert(mCacheHand != 0);
+ crtn = CSSM_CL_CertGetFirstCachedFieldValue(
+ mClHand,
+ mCacheHand,
+ &oid,
+ &resultHand,
+ &NumberOfFields,
+ &fieldData);
+ if(crtn) {
+ /* not an error; just means that the cert doesn't have this field */
+ return NULL;
+ }
+ assert(NumberOfFields == 1);
+ CSSM_CL_CertAbortQuery(mClHand, resultHand);
+
+ if(fieldLength) {
+ if(fieldLength != fieldData->Length) {
+ /* FIXME what's a good way to log in this situation? */
+ printf("***CertParser::fieldForOid: field length mismatch\n");
+ return NULL;
+ }
+ }
+ /* Store the OID and the field for autorelease */
+ CP_FetchedField *cpField = new CP_FetchedField(oid, fieldData, mClHand);
+ mFetchedFields.push_back(cpField);
+ fieldLength = fieldData->Length;
+ return fieldData->Data;
+}
+
+/*
+ * Conveneince routine to fetch an extension we "know" the CL can parse.
+ * The return value gets cast to one of the CE_Data types.
+ */
+const void *CertParser::extensionForOid(
+ const CSSM_OID &oid)
+{
+ CSSM_SIZE len = sizeof(CSSM_X509_EXTENSION);
+ CSSM_X509_EXTENSION *cssmExt =
+ (CSSM_X509_EXTENSION *)fieldForOid(oid, len);
+ if(cssmExt) {
+ if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
+ printf("***Badly formatted extension");
+ return NULL;
+ }
+ return cssmExt->value.parsedValue;
+ }
+ else {
+ return NULL;
+ }
+}
+