1/* 2 * Copyright (c) 2001,2003-2011 Apple, 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 * srCdsaUtils.cpp -- common CDSA access utilities 24 */ 25 26#include "srCdsaUtils.h" 27#include <stdlib.h> 28#include <stdio.h> 29#include <Security/SecCertificate.h> 30#include <Security/cssmapple.h> /* for cssmPerror() */ 31#include <Security/oidsalg.h> /* for cssmPerror() */ 32#include <strings.h> 33 34static CSSM_VERSION vers = {2, 0}; 35static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }}; 36 37/* 38 * Standard app-level memory functions required by CDSA. 39 */ 40void * srAppMalloc (CSSM_SIZE size, void *allocRef) { 41 return( malloc(size) ); 42} 43 44void srAppFree (void *mem_ptr, void *allocRef) { 45 free(mem_ptr); 46 return; 47} 48 49void * srAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) { 50 return( realloc( ptr, size ) ); 51} 52 53void * srAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) { 54 return( calloc( num, size ) ); 55} 56 57static CSSM_API_MEMORY_FUNCS memFuncs = { 58 srAppMalloc, 59 srAppFree, 60 srAppRealloc, 61 srAppCalloc, 62 NULL 63 }; 64 65CSSM_BOOL srCompareCssmData(const CSSM_DATA *d1, 66 const CSSM_DATA *d2) 67{ 68 if(d1->Length != d2->Length) { 69 return CSSM_FALSE; 70 } 71 if(memcmp(d1->Data, d2->Data, d1->Length)) { 72 return CSSM_FALSE; 73 } 74 return CSSM_TRUE; 75} 76 77/* 78 * Init CSSM; returns CSSM_FALSE on error. Reusable. 79 */ 80static CSSM_BOOL cssmInitd = CSSM_FALSE; 81 82CSSM_BOOL srCssmStartup() 83{ 84 CSSM_RETURN crtn; 85 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE; 86 87 if(cssmInitd) { 88 return CSSM_TRUE; 89 } 90 crtn = CSSM_Init (&vers, 91 CSSM_PRIVILEGE_SCOPE_NONE, 92 &testGuid, 93 CSSM_KEY_HIERARCHY_NONE, 94 &pvcPolicy, 95 NULL /* reserved */); 96 if(crtn != CSSM_OK) 97 { 98 srPrintError("CSSM_Init", crtn); 99 return CSSM_FALSE; 100 } 101 else { 102 cssmInitd = CSSM_TRUE; 103 return CSSM_TRUE; 104 } 105} 106 107/* 108 * Attach to CSP. Returns zero on error. 109 */ 110CSSM_CSP_HANDLE srCspStartup( 111 CSSM_BOOL bareCsp) // true ==> CSP, false ==> CSP/DL 112{ 113 CSSM_CSP_HANDLE cspHand; 114 CSSM_RETURN crtn; 115 const CSSM_GUID *guid; 116 117 /* common CSSM init */ 118 if(srCssmStartup() == CSSM_FALSE) { 119 return 0; 120 } 121 if(bareCsp) { 122 guid = &gGuidAppleCSP; 123 } 124 else { 125 guid = &gGuidAppleCSPDL; 126 } 127 crtn = CSSM_ModuleLoad(guid, 128 CSSM_KEY_HIERARCHY_NONE, 129 NULL, // eventHandler 130 NULL); // AppNotifyCallbackCtx 131 if(crtn) { 132 srPrintError("CSSM_ModuleLoad()", crtn); 133 return 0; 134 } 135 crtn = CSSM_ModuleAttach (guid, 136 &vers, 137 &memFuncs, // memFuncs 138 0, // SubserviceID 139 CSSM_SERVICE_CSP, 140 0, // AttachFlags 141 CSSM_KEY_HIERARCHY_NONE, 142 NULL, // FunctionTable 143 0, // NumFuncTable 144 NULL, // reserved 145 &cspHand); 146 if(crtn) { 147 srPrintError("CSSM_ModuleAttach()", crtn); 148 return 0; 149 } 150 return cspHand; 151} 152 153/* Attach to DL side of CSPDL */ 154CSSM_DL_HANDLE srDlStartup() 155{ 156 CSSM_DL_HANDLE dlHand = 0; 157 CSSM_RETURN crtn; 158 159 if(srCssmStartup() == CSSM_FALSE) { 160 return 0; 161 } 162 crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL, 163 CSSM_KEY_HIERARCHY_NONE, 164 NULL, // eventHandler 165 NULL); // AppNotifyCallbackCtx 166 if(crtn) { 167 srPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn); 168 return 0; 169 } 170 crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL, 171 &vers, 172 &memFuncs, // memFuncs 173 0, // SubserviceID 174 CSSM_SERVICE_DL, 175 0, // AttachFlags 176 CSSM_KEY_HIERARCHY_NONE, 177 NULL, // FunctionTable 178 0, // NumFuncTable 179 NULL, // reserved 180 &dlHand); 181 if(crtn) { 182 srPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn); 183 return 0; 184 } 185 return dlHand; 186} 187 188CSSM_CL_HANDLE srClStartup() 189{ 190 CSSM_CL_HANDLE clHand; 191 CSSM_RETURN crtn; 192 193 if(srCssmStartup() == CSSM_FALSE) { 194 return 0; 195 } 196 crtn = CSSM_ModuleLoad(&gGuidAppleX509CL, 197 CSSM_KEY_HIERARCHY_NONE, 198 NULL, // eventHandler 199 NULL); // AppNotifyCallbackCtx 200 if(crtn) { 201 srPrintError("CSSM_ModuleLoad(AppleCL)", crtn); 202 return 0; 203 } 204 crtn = CSSM_ModuleAttach (&gGuidAppleX509CL, 205 &vers, 206 &memFuncs, // memFuncs 207 0, // SubserviceID 208 CSSM_SERVICE_CL, // SubserviceFlags - Where is this used? 209 0, // AttachFlags 210 CSSM_KEY_HIERARCHY_NONE, 211 NULL, // FunctionTable 212 0, // NumFuncTable 213 NULL, // reserved 214 &clHand); 215 if(crtn) { 216 srPrintError("CSSM_ModuleAttach(AppleCL)", crtn); 217 return 0; 218 } 219 else { 220 return clHand; 221 } 222} 223 224CSSM_TP_HANDLE srTpStartup() 225{ 226 CSSM_TP_HANDLE tpHand; 227 CSSM_RETURN crtn; 228 229 if(srCssmStartup() == CSSM_FALSE) { 230 return 0; 231 } 232 crtn = CSSM_ModuleLoad(&gGuidAppleX509TP, 233 CSSM_KEY_HIERARCHY_NONE, 234 NULL, // eventHandler 235 NULL); // AppNotifyCallbackCtx 236 if(crtn) { 237 srPrintError("CSSM_ModuleLoad(AppleTP)", crtn); 238 return 0; 239 } 240 crtn = CSSM_ModuleAttach (&gGuidAppleX509TP, 241 &vers, 242 &memFuncs, // memFuncs 243 0, // SubserviceID 244 CSSM_SERVICE_TP, // SubserviceFlags 245 0, // AttachFlags 246 CSSM_KEY_HIERARCHY_NONE, 247 NULL, // FunctionTable 248 0, // NumFuncTable 249 NULL, // reserved 250 &tpHand); 251 if(crtn) { 252 srPrintError("CSSM_ModuleAttach(AppleTP)", crtn); 253 return 0; 254 } 255 else { 256 return tpHand; 257 } 258} 259 260/* 261 * Given a context specified via a CSSM_CC_HANDLE, add a new 262 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, 263 * AttributeLength, and an untyped pointer. 264 */ 265CSSM_RETURN srAddContextAttribute(CSSM_CC_HANDLE CCHandle, 266 uint32 AttributeType, 267 uint32 AttributeLength, 268 const void *AttributePtr) 269{ 270 CSSM_CONTEXT_ATTRIBUTE newAttr; 271 CSSM_RETURN crtn; 272 273 newAttr.AttributeType = AttributeType; 274 newAttr.AttributeLength = AttributeLength; 275 newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; 276 crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); 277 if(crtn) { 278 srPrintError("CSSM_UpdateContextAttributes", crtn); 279 } 280 return crtn; 281} 282 283 284/* 285 * Derive symmetric key. 286 * Note in the X CSP, we never return an IV. 287 */ 288CSSM_RETURN srCspDeriveKey(CSSM_CSP_HANDLE cspHand, 289 uint32 keyAlg, // CSSM_ALGID_RC5, etc. 290 const char *keyLabel, 291 unsigned keyLabelLen, 292 uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc. 293 uint32 keySizeInBits, 294 CSSM_DATA_PTR password, // in PKCS-5 lingo 295 CSSM_DATA_PTR salt, // ditto 296 uint32 iterationCnt, // ditto 297 CSSM_KEY_PTR key) 298{ 299 CSSM_RETURN crtn; 300 CSSM_CC_HANDLE ccHand; 301 uint32 keyAttr; 302 CSSM_DATA dummyLabel; 303 CSSM_PKCS5_PBKDF2_PARAMS pbeParams; 304 CSSM_DATA pbeData; 305 CSSM_ACCESS_CREDENTIALS creds; 306 307 memset(key, 0, sizeof(CSSM_KEY)); 308 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 309 crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand, 310 CSSM_ALGID_PKCS5_PBKDF2, 311 keyAlg, 312 keySizeInBits, 313 &creds, 314 NULL, // BaseKey 315 iterationCnt, 316 salt, 317 NULL, // seed 318 &ccHand); 319 if(crtn) { 320 srPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn); 321 return crtn; 322 } 323 keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF | 324 CSSM_KEYATTR_SENSITIVE; 325 dummyLabel.Length = keyLabelLen; 326 dummyLabel.Data = (uint8 *)keyLabel; 327 328 /* passing in password is pretty strange....*/ 329 pbeParams.Passphrase = *password; 330 pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1; 331 pbeData.Data = (uint8 *)&pbeParams; 332 pbeData.Length = sizeof(pbeParams); 333 crtn = CSSM_DeriveKey(ccHand, 334 &pbeData, 335 keyUsage, 336 keyAttr, 337 &dummyLabel, 338 NULL, // cred and acl 339 key); 340 if(crtn) { 341 srPrintError("CSSM_DeriveKey", crtn); 342 return crtn; 343 } 344 crtn = CSSM_DeleteContext(ccHand); 345 if(crtn) { 346 srPrintError("CSSM_DeleteContext", crtn); 347 } 348 return crtn; 349} 350 351/* 352 * Generate key pair of arbitrary algorithm. 353 */ 354 355/* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */ 356#define DO_DSA_GEN_PARAMS 0 357 358CSSM_RETURN srCspGenKeyPair(CSSM_CSP_HANDLE cspHand, 359 CSSM_DL_DB_HANDLE *dlDbHand, // optional 360 uint32 algorithm, 361 const char *keyLabel, 362 unsigned keyLabelLen, 363 uint32 keySize, // in bits 364 CSSM_KEY_PTR pubKey, // mallocd by caller 365 CSSM_KEYUSE pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc. 366 CSSM_KEYATTR_FLAGS pubAttrs, // CSSM_KEYATTR_EXTRACTABLE, etc. 367 CSSM_KEY_PTR privKey, // mallocd by caller 368 CSSM_KEYUSE privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc. 369 CSSM_KEYATTR_FLAGS privAttrs) // CSSM_KEYATTR_EXTRACTABLE, etc. 370{ 371 CSSM_RETURN crtn; 372 CSSM_RETURN ocrtn; 373 CSSM_CC_HANDLE ccHand; 374 CSSM_DATA keyLabelData; 375 376 keyLabelData.Data = (uint8 *)keyLabel, 377 keyLabelData.Length = keyLabelLen; 378 memset(pubKey, 0, sizeof(CSSM_KEY)); 379 memset(privKey, 0, sizeof(CSSM_KEY)); 380 381 crtn = CSSM_CSP_CreateKeyGenContext(cspHand, 382 algorithm, 383 keySize, 384 NULL, // Seed 385 NULL, // Salt 386 NULL, // StartDate 387 NULL, // EndDate 388 NULL, // Params 389 &ccHand); 390 if(crtn) { 391 srPrintError("CSSM_CSP_CreateKeyGenContext", crtn); 392 return crtn; 393 } 394 395 /* post-context-create algorithm-specific stuff */ 396 switch(algorithm) { 397 #if DO_DSA_GEN_PARAMS 398 case CSSM_ALGID_DSA: 399 /* 400 * extra step - generate params - this just adds some 401 * info to the context 402 */ 403 { 404 CSSM_DATA dummy = {0, NULL}; 405 crtn = CSSM_GenerateAlgorithmParams(ccHand, 406 keySize, &dummy); 407 if(crtn) { 408 srPrintError("CSSM_GenerateAlgorithmParams", crtn); 409 CSSM_DeleteContext(ccHand); 410 return crtn; 411 } 412 srAppFree(dummy.Data, NULL); 413 } 414 break; 415 #endif /* DO_DSA_GEN_PARAMS */ 416 default: 417 break; 418 } 419 420 /* optionally specify DL/DB storage location */ 421 if(dlDbHand) { 422 crtn = srAddContextAttribute(ccHand, 423 CSSM_ATTRIBUTE_DL_DB_HANDLE, 424 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE), 425 dlDbHand); 426 if(crtn) { 427 CSSM_DeleteContext(ccHand); 428 return crtn; 429 } 430 } 431 ocrtn = CSSM_GenerateKeyPair(ccHand, 432 pubKeyUsage, 433 pubAttrs, 434 &keyLabelData, 435 pubKey, 436 privKeyUsage, 437 privAttrs, 438 &keyLabelData, // same labels 439 NULL, // CredAndAclEntry 440 privKey); 441 if(ocrtn) { 442 srPrintError("CSSM_GenerateKeyPair", ocrtn); 443 } 444 crtn = CSSM_DeleteContext(ccHand); 445 if(crtn) { 446 srPrintError("CSSM_DeleteContext", crtn); 447 if(ocrtn == CSSM_OK) { 448 /* error on CSSM_GenerateKeyPair takes precedence */ 449 ocrtn = crtn; 450 } 451 } 452 return ocrtn; 453} 454 455 456/* 457 * Add a certificate to an open Keychain. 458 */ 459CSSM_RETURN srAddCertToKC( 460 SecKeychainRef keychain, 461 const CSSM_DATA *cert, 462 CSSM_CERT_TYPE certType, 463 CSSM_CERT_ENCODING certEncoding, 464 const char *printName, // C string 465 const CSSM_DATA *keyLabel) // ?? 466{ 467 SecCertificateRef certificate; 468 469 OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate); 470 if (!rslt) 471 { 472 rslt = SecCertificateAddToKeychain(certificate, keychain); 473 CFRelease(certificate); 474 } 475 476 return rslt; 477} 478 479/* 480 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an 481 * unsigned. 482 */ 483unsigned srDER_ToInt(const CSSM_DATA *DER_Data) 484{ 485 uint32 rtn = 0; 486 unsigned i = 0; 487 488 while(i < DER_Data->Length) { 489 rtn |= DER_Data->Data[i]; 490 if(++i == DER_Data->Length) { 491 break; 492 } 493 rtn <<= 8; 494 } 495 return rtn; 496} 497 498/* 499 * Log CSSM error. 500 */ 501void srPrintError(const char *op, CSSM_RETURN err) 502{ 503 cssmPerror(op, err); 504} 505 506/* 507 * Convert a CFString into a C string as safely as we can. Caller must 508 * free the result. 509 */ 510char *srCfStrToCString( 511 CFStringRef cfStr) 512{ 513 CFIndex len = CFStringGetLength(cfStr) + 1; 514 char *cstr = (char *)malloc(len); 515 if(cstr == NULL) { 516 return NULL; 517 } 518 if(!CFStringGetCString(cfStr, cstr, len, kCFStringEncodingASCII)) { 519 printf("***CFStringGetCString error\n"); 520 free(cstr); 521 return NULL; 522 } 523 return cstr; 524} 525 526