1/* 2 * Copyright (c) 2003-2005 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please 7 * obtain a copy of the License at http://www.apple.com/publicsource and 8 * read it before using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 15 * Please see the License for the specific language governing rights and 16 * limitations under the License. 17 */ 18 19/* 20 * CertParser.h - cert parser with autorelease of fetched fields 21 * 22 * Created 24 October 2003 by Doug Mitchell 23 */ 24 25#include "CertParser.h" 26#import <AvailabilityMacros.h> 27 28#define CP_DEBUG 1 29#if CP_DEBUG 30#define dprintf(args...) printf(args) 31#else 32#define dprintf(args...) 33#endif 34 35#pragma mark --- CP_FetchedField --- 36 37class CP_FetchedField 38{ 39public: 40 /* construct one fetched field (which will be stored in CertParser's 41 * mFetchedFields) */ 42 CP_FetchedField( 43 const CSSM_OID &fieldOid, 44 CSSM_DATA_PTR fieldData, 45 CSSM_CL_HANDLE clHand); 46 47 /* Free the field via CL */ 48 ~CP_FetchedField(); 49private: 50 CSSM_OID mFieldOid; 51 CSSM_DATA_PTR mFieldData; 52 CSSM_CL_HANDLE mClHand; 53}; 54 55CP_FetchedField::CP_FetchedField( 56 const CSSM_OID &fieldOid, 57 CSSM_DATA_PTR fieldData, 58 CSSM_CL_HANDLE clHand) 59 : mFieldOid(fieldOid), mFieldData(fieldData), mClHand(clHand) 60{ 61} 62 63/* Free the field via CL */ 64CP_FetchedField::~CP_FetchedField() 65{ 66 CSSM_CL_FreeFieldValue(mClHand, &mFieldOid, mFieldData); 67} 68 69#pragma mark --- CertParser implementation --- 70 71/* Construct with or without data - you can add the data later with 72 * initWithData() to parse without exceptions */ 73CertParser::CertParser() 74{ 75 initFields(); 76} 77 78CertParser::CertParser( 79 CSSM_CL_HANDLE clHand) 80{ 81 initFields(); 82 mClHand = clHand; 83} 84 85CertParser::CertParser( 86 CSSM_CL_HANDLE clHand, 87 const CSSM_DATA &certData) 88{ 89 initFields(); 90 mClHand = clHand; 91 CSSM_RETURN crtn = initWithData(certData); 92 if(crtn) { 93 throw ((int)crtn); 94 } 95} 96 97CertParser::CertParser( 98 SecCertificateRef secCert) 99{ 100 initFields(); 101 OSStatus ortn = initWithSecCert(secCert); 102 if(ortn) { 103 throw ((int)ortn); 104 } 105} 106 107/* frees all the fields we fetched */ 108CertParser::~CertParser() 109{ 110 if(mClHand && mCacheHand) { 111 CSSM_RETURN crtn = CSSM_CL_CertAbortCache(mClHand, mCacheHand); 112 if(crtn) { 113 /* almost certainly a bug */ 114 printf("Internal Error: CertParser error on free."); 115 cssmPerror("CSSM_CL_CertAbortCache", crtn); 116 } 117 } 118 vector<CP_FetchedField *>::iterator iter; 119 for(iter=mFetchedFields.begin(); iter!=mFetchedFields.end(); iter++) { 120 delete *iter; 121 } 122} 123 124/* common init for all constructors */ 125void CertParser::initFields() 126{ 127 mClHand = 0; 128 mCacheHand = 0; 129} 130 131/*** NO MORE EXCEPTIONS ***/ 132 133/* 134 * No cert- or CDSA-related exceptions thrown by remainder. 135 * This is the core initializer: have the CL parse and cache the cert. 136 */ 137CSSM_RETURN CertParser::initWithData( 138 const CSSM_DATA &certData) 139{ 140 assert(mClHand != 0); 141 CSSM_RETURN crtn = CSSM_CL_CertCache(mClHand, &certData, &mCacheHand); 142 #if CP_DEBUG 143 if(crtn) { 144 cssmPerror("CSSM_CL_CertCache", crtn); 145 } 146 #endif 147 return crtn; 148} 149 150OSStatus CertParser::initWithSecCert( 151 SecCertificateRef secCert) 152{ 153 OSStatus ortn; 154 CSSM_DATA certData; 155 156 assert(mClHand == 0); 157 ortn = SecCertificateGetCLHandle(secCert, &mClHand); 158 if(ortn) { 159 return ortn; 160 } 161 ortn = SecCertificateGetData(secCert, &certData); 162 if(ortn) { 163 return ortn; 164 } 165 return (OSStatus)initWithData(certData); 166} 167 168CSSM_RETURN CertParser::initWithCFData( 169 CFDataRef cfData) 170{ 171 CSSM_DATA cdata; 172 173 cdata.Data = (uint8 *)CFDataGetBytePtr(cfData); 174 cdata.Length = CFDataGetLength(cfData); 175 return initWithData(cdata); 176} 177 178/* 179 * Obtain atrbitrary field from cached cert. This class takes care of freeing 180 * the field in its destructor. 181 * 182 * Returns NULL if field not found (not exception). 183 * 184 * Caller optionally specifies field length to check - specifying zero means 185 * "don't care, don't check". Actual field length always returned in fieldLength. 186 */ 187const void *CertParser::fieldForOid( 188 const CSSM_OID &oid, 189 CSSM_SIZE &fieldLength) // IN/OUT 190{ 191 CSSM_RETURN crtn; 192 193 uint32 NumberOfFields = 0; 194 CSSM_HANDLE resultHand = 0; 195 CSSM_DATA_PTR fieldData = NULL; 196 197 assert(mClHand != 0); 198 assert(mCacheHand != 0); 199 crtn = CSSM_CL_CertGetFirstCachedFieldValue( 200 mClHand, 201 mCacheHand, 202 &oid, 203 &resultHand, 204 &NumberOfFields, 205 &fieldData); 206 if(crtn) { 207 /* not an error; just means that the cert doesn't have this field */ 208 return NULL; 209 } 210 assert(NumberOfFields == 1); 211 CSSM_CL_CertAbortQuery(mClHand, resultHand); 212 213 if(fieldLength) { 214 if(fieldLength != fieldData->Length) { 215 /* FIXME what's a good way to log in this situation? */ 216 printf("***CertParser::fieldForOid: field length mismatch\n"); 217 return NULL; 218 } 219 } 220 /* Store the OID and the field for autorelease */ 221 CP_FetchedField *cpField = new CP_FetchedField(oid, fieldData, mClHand); 222 mFetchedFields.push_back(cpField); 223 fieldLength = fieldData->Length; 224 return fieldData->Data; 225} 226 227/* 228 * Conveneince routine to fetch an extension we "know" the CL can parse. 229 * The return value gets cast to one of the CE_Data types. 230 */ 231const void *CertParser::extensionForOid( 232 const CSSM_OID &oid) 233{ 234 CSSM_SIZE len = sizeof(CSSM_X509_EXTENSION); 235 CSSM_X509_EXTENSION *cssmExt = 236 (CSSM_X509_EXTENSION *)fieldForOid(oid, len); 237 if(cssmExt) { 238 if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) { 239 printf("***Badly formatted extension"); 240 return NULL; 241 } 242 return cssmExt->value.parsedValue; 243 } 244 else { 245 return NULL; 246 } 247} 248 249