1/* 2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <string.h> 25#include "CommonCode.h" 26#include "DSX509Relation.h" 27#include <security_utilities/debugging.h> 28#include "CommonCrypto/CommonDigest.h" 29 30/* 31 int mNumberOfValues; 32 Value* mValues; 33 BlobValue *mData; 34*/ 35 36DSX509Tuple::DSX509Tuple (int numberOfValues) : mNumberOfValues (numberOfValues), mValues (NULL), mData (NULL) 37{ 38 mValues = new Value*[numberOfValues]; 39 for (int i = 0; i < numberOfValues; ++i) 40 mValues[i] = NULL; 41} 42 43 44 45DSX509Tuple::~DSX509Tuple () 46{ 47 // walk the value array and delete each value 48 for (int i = 0; i < mNumberOfValues; ++i) 49 if (mValues[i] != NULL) delete mValues[i]; 50 delete [] mValues; 51 52 if (mData != NULL) delete mData; 53} 54 55 56 57void DSX509Tuple::SetValue (int i, Value* v) 58{ 59 mValues[i] = v; 60} 61 62 63 64Value* DSX509Tuple::GetValue (int i) 65{ 66 return mValues[i]; 67} 68 69 70 71int DSX509Tuple::GetNumberOfValues () 72{ 73 return mNumberOfValues; 74} 75 76 77 78void DSX509Tuple::GetData (CSSM_DATA &data) 79{ 80 size_t t; 81 const uint8* d = mData->GetRawValue (t); 82 data.Data = (uint8*) d; 83 data.Length = t; 84} 85 86 87 88void DSX509Tuple::SetData (BlobValue *value) 89{ 90 mData = value; 91} 92 93 94 95DSX509UniqueIdentifier::DSX509UniqueIdentifier (DSX509Tuple *t) : 96 UniqueIdentifier (CSSM_DL_DB_RECORD_X509_CERTIFICATE), mTuple (t) 97{ 98} 99 100 101 102DSX509UniqueIdentifier::~DSX509UniqueIdentifier () 103{ 104 delete mTuple; 105} 106 107 108 109void DSX509UniqueIdentifier::Export (CSSM_DB_UNIQUE_RECORD &record) 110{ 111 // memset the whole thing to 0, we don't care 112 memset (&record, 0, sizeof (CSSM_DB_UNIQUE_RECORD)); 113} 114 115 116 117DSX509Tuple* DSX509UniqueIdentifier::GetTuple () 118{ 119 return mTuple; 120} 121 122 123 124static void * appMalloc (CSSM_SIZE size, void *allocRef) { 125 return (malloc (size)); 126} 127 128 129 130static void appFree (void *mem_ptr, void *allocRef) { 131 free (mem_ptr); 132 return; 133} 134 135 136 137static void * appRealloc (void *ptr, CSSM_SIZE size, void *allocRef) { 138 return (realloc (ptr, size)); 139} 140 141 142 143static void * appCalloc (uint32 num, CSSM_SIZE size, void *allocRef) { 144 return (calloc (num, size)); 145} 146 147 148 149static CSSM_API_MEMORY_FUNCS memFuncs = { 150 appMalloc, 151 appFree, 152 appRealloc, 153 appCalloc, 154 NULL 155 }; 156 157 158 159static void CheckResult (CSSM_RETURN result) 160{ 161 if (result != 0) throw CSSMError (result); 162} 163 164 165 166void DSX509Relation::InitializeCertLibrary () 167{ 168 if (mCertificateLibrary != 0) return; 169 170 // figure out which GUID to attach to 171 const CSSM_GUID* attachGuid = &gGuidAppleX509CL; 172 173 // Initialize CDSA 174 CSSM_VERSION version = {2, 0}; 175 176 // load the CL 177 CSSM_RETURN result = CSSM_ModuleLoad (attachGuid, CSSM_KEY_HIERARCHY_NONE, NULL, NULL); 178 CheckResult (result); 179 180 result = CSSM_ModuleAttach (attachGuid, &version, &memFuncs, 0, CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &mCertificateLibrary); 181 CheckResult (result); 182} 183 184 185 186DSX509Relation::DSX509Relation (CSSM_DB_RECORDTYPE recordType, int numberOfColumns, columnInfoLoader *theColumnInfo) : PartialRelation (CSSM_DL_DB_RECORD_X509_CERTIFICATE, kNumberOfX509Attributes,theColumnInfo), mCertificateLibrary (0) 187{ 188 mDirectoryService = new DirectoryService(); 189} 190 191 192 193DSX509Relation::~DSX509Relation () 194{ 195 if (mCertificateLibrary != 0) 196 CSSM_ModuleDetach (mCertificateLibrary); 197} 198 199 200 201Query* DSX509Relation::MakeQuery (const CSSM_QUERY* query) 202{ 203 return new DSX509Query (this, query); 204} 205 206 207 208Tuple* DSX509Relation::GetTupleFromUniqueIdentifier (UniqueIdentifier* uniqueID) 209{ 210 DSX509UniqueIdentifier *id = (DSX509UniqueIdentifier*) uniqueID; 211 return id->GetTuple (); 212} 213 214 215 216UniqueIdentifier* DSX509Relation::ImportUniqueIdentifier (CSSM_DB_UNIQUE_RECORD *uniqueRecord) 217{ 218 throw CSSMERR_DL_UNSUPPORTED_QUERY; 219} 220 221 222 223CSSM_CL_HANDLE DSX509Relation::GetCLHandle () 224{ 225 InitializeCertLibrary (); 226 return mCertificateLibrary; 227} 228 229 230 231 232DSX509Query::DSX509Query (DSX509Relation* relation, const CSSM_QUERY *queryBase) : 233 Query (relation, queryBase), mRecordCount (0), mCurrentItem (1), 234 mRecordList (NULL), mNumberOfTuples (0), mNextTuple (0) 235{ 236 CSSM_RETURN error; 237 // attach to open directory 238 mRecordList = relation->mDirectoryService->translate_cssm_query_to_OD_query(queryBase, &error); 239 if(!mRecordList) throw CSSMERR_DL_ENDOFDATA; 240} 241 242 243 244DSX509Query::~DSX509Query () 245{ 246 // delete mRecordList; need to release the results handle 247} 248 249 250 251 252 253 254 255static bool CompareOIDs (const CSSM_OID &a, const CSSM_OID &b) 256{ 257 if (a.Length != b.Length) return false; 258 return memcmp (a.Data, b.Data, a.Length) == 0; 259} 260 261 262 263static CSSM_DATA GetValueFromFields (CSSM_FIELD *fields, uint32 numFields, const CSSM_OID& oid) 264{ 265 uint32 i; 266 for (i = 0; i < numFields; ++i) 267 if (CompareOIDs (fields[i].FieldOid, oid)) return fields[i].FieldValue; 268 269 throw CSSMERR_CSSM_INVALID_ATTRIBUTE; 270} 271 272 273 274static CSSM_DATA* GetAttributeFromX509Name (CSSM_X509_NAME *name, const CSSM_OID& oid) 275{ 276 uint32 i; 277 for (i = 0; i < name->numberOfRDNs; ++i) { 278 CSSM_X509_RDN &rdn = name->RelativeDistinguishedName[i]; 279 uint32 j; 280 for (j = 0; j < rdn.numberOfPairs; ++j) { 281 CSSM_X509_TYPE_VALUE_PAIR &pair = rdn.AttributeTypeAndValue[j]; 282 if (CompareOIDs (pair.type, oid)) 283 return &pair.value; 284 } 285 } 286 return NULL; 287} 288 289 290 291Tuple* DSX509Query::GetNextTuple (UniqueIdentifier *&id) 292{ 293 DSX509Tuple* t; 294 CFStringRef original_search; 295 296 original_search = this->mRecordList->searchString; 297 298 // get the current item from the list 299 CFDataRef certData = this->mDirectoryService->getNextCertFromResults(this->mRecordList); 300 if(!certData) return NULL; 301 DSX509Record record ((DSX509Relation*) mRelation); 302 303 t = record.GetTuple (certData, original_search, mTupleList, kMaxTuples); 304 mNextTuple++; 305 306 if (EvaluateTuple (t)) { 307 id = new DSX509UniqueIdentifier (t); 308 return t; 309 } 310 return NULL; 311} 312 313 314 315 316DSX509Tuple* DSX509Record::GetTuple (CFDataRef certData, CFStringRef original_search, DSX509Tuple *tupleList[], int maxTuples) 317{ 318 DSX509Tuple** tupleFinger = tupleList; 319 CSSM_CL_HANDLE clHandle = mRelation->GetCLHandle (); 320 // we now need to parse the cert 321 CSSM_DATA cert; 322 cert.Data = (uint8 *) CFDataGetBytePtr(certData); 323 cert.Length = CFDataGetLength(certData); 324 325 CSSM_FIELD *fields; 326 uint32 numberOfFields; 327 328 CSSM_RETURN result = CSSM_CL_CertGetAllFields (clHandle, &cert, &numberOfFields, &fields); 329 CheckResult (result); 330 331 CSSM_DATA data; 332 333 // get the version 334 data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1Version); 335 // make a tuple 336 DSX509Tuple* t = new DSX509Tuple (kNumberOfX509Attributes); 337 338 // set the data types 339 t->SetValue (kCertTypeID, new UInt32Value (*(uint32*) data.Data)); 340 t->SetValue (kCertEncodingID, new UInt32Value (CSSM_CERT_ENCODING_DER)); 341 342 // we need the print name, so start with the subject name 343 data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SubjectNameCStruct); 344 345 // from there, get the attribute 346 CSSM_X509_NAME* namePtr = (CSSM_X509_NAME*) data.Data; 347 CSSM_DATA *dp; 348 dp = GetAttributeFromX509Name (namePtr, CSSMOID_CommonName); 349 t->SetValue (kCertPrintName, dp == NULL ? new BlobValue (original_search) : new BlobValue (*dp)); 350 351 // set the email address to the original search string 352 t->SetValue (kCertAlias, new BlobValue (original_search)); 353 354 // get the subject 355 data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SubjectName); 356 t->SetValue (kCertSubject, new BlobValue (data)); 357 358 // get the issuer 359 data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1IssuerName); 360 t->SetValue (kCertIssuer, new BlobValue (data)); 361 362 // get the serial number 363 data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SerialNumber); 364 t->SetValue (kCertSerialNumber, new BlobValue (data)); 365 366 // handle the subject key identifier 367 t->SetValue (kCertSubjectKeyIdentifier, NULL); 368 369 // make hash of the public key. 370 data = GetValueFromFields (fields, numberOfFields, CSSMOID_X509V1SubjectPublicKeyCStruct); 371 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *publicKeyInfo = (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *) data.Data; 372 373 CC_SHA1_CTX context; 374 CC_SHA1_Init (&context); 375 CC_SHA1_Update (&context, publicKeyInfo->subjectPublicKey.Data, publicKeyInfo->subjectPublicKey.Length); 376 377 uint8 sha1Digest [20]; 378 CC_SHA1_Final (sha1Digest, &context); 379 380 t->SetValue (kCertPublicKeyHash, new BlobValue (sha1Digest, 20)); 381 382 // release the cert data 383 CSSM_CL_FreeFields (clHandle, numberOfFields, &fields); 384 385 // get the data that we will ultimately return 386 t->SetData (new BlobValue (cert)); 387 388 // save off the tuple 389 *tupleFinger++ = t; 390 --maxTuples; 391 return t; 392} 393