]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/clAppUtils/CertParser.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / CertParser.cpp
diff --git a/SecurityTests/clxutils/clAppUtils/CertParser.cpp b/SecurityTests/clxutils/clAppUtils/CertParser.cpp
new file mode 100644 (file)
index 0000000..ca46f8a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * 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;
+       }
+}
+