transition.cpp
1 /* 2 * Copyright (c) 2000-2008,2011-2013 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 24 25 // 26 // transition - SecurityServer client library transition code. 27 // 28 // These are the functions that implement CssmClient methods in terms of 29 // MIG IPC client calls, plus their supporting machinery. 30 // 31 // WARNING! HERE BE DRAGONS! 32 // This code involves moderately arcane magic including (but not limited to) 33 // dancing macros paired off with self-maintaining stack objects. Don't take 34 // anything for granted! Be very afraid of ALL-CAPS names. Your best bet is 35 // probably to stick with the existing patterns. 36 // 37 // Dragons, the sequel. You just don't go killing of that kind of prose, so 38 // we'll continue the saga here with a bit of an update. In transitioning 39 // into securityd there are a couple of steps. The current setup is there 40 // to allow Security.framework to have 32 and 64 bit clients and either 41 // big or little endian. Data is packaged up as hand-generated XDR, which 42 // means it's also in network byte-order. 43 // 44 // CSSM_HANDLEs have remained longs in the 64 bit transition to keep the 45 // optimization option open to allow cssm modules to hand back pointers as 46 // handles. Since we don't identify the client, handles across ipc will 47 // remain 32 bit. Handles you see here are passed out by securityd, and 48 // are clipped and expanded in this layer (high bits always zero). 49 // 50 #include "sstransit.h" 51 #include <security_cdsa_client/cspclient.h> 52 53 #include <CommonCrypto/CommonRandom.h> 54 #include <securityd_client/xdr_auth.h> 55 #include <securityd_client/xdr_cssm.h> 56 #include <securityd_client/xdr_dldb.h> 57 58 namespace Security { 59 namespace SecurityServer { 60 61 using MachPlusPlus::check; 62 using MachPlusPlus::VMGuard; 63 64 // 65 // Common database interface 66 // 67 void ClientSession::authenticateDb(DbHandle db, CSSM_DB_ACCESS_TYPE type, 68 const AccessCredentials *cred) 69 { 70 // XXX/cs Leave it up to DatabaseAccessCredentials to rewrite it for now 71 DatabaseAccessCredentials creds(cred, internalAllocator); 72 CopyIn copy(creds.value(), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 73 IPC(ucsp_client_authenticateDb(UCSP_ARGS, db, type, copy.data(), copy.length())); 74 } 75 76 77 void ClientSession::releaseDb(DbHandle db) 78 { 79 IPC(ucsp_client_releaseDb(UCSP_ARGS, db)); 80 } 81 82 83 // 84 // External database interface 85 // 86 DbHandle ClientSession::openToken(uint32 ssid, const AccessCredentials *cred, 87 const char *name) 88 { 89 DbHandle db; 90 DatabaseAccessCredentials creds(cred, internalAllocator); 91 CopyIn copycreds(creds.value(), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 92 93 IPC(ucsp_client_openToken(UCSP_ARGS, ssid, name ? name : "", copycreds.data(), copycreds.length(), &db)); 94 95 return db; 96 } 97 98 99 RecordHandle ClientSession::insertRecord(DbHandle db, 100 CSSM_DB_RECORDTYPE recordType, 101 const CssmDbRecordAttributeData *attributes, 102 const CssmData *data) 103 { 104 RecordHandle record; 105 CopyIn db_record_attr_data(attributes, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA)); 106 107 IPC(ucsp_client_insertRecord(UCSP_ARGS, db, recordType, db_record_attr_data.data(), (mach_msg_type_number_t)db_record_attr_data.length(), OPTIONALDATA(data), &record)); 108 109 return record; 110 } 111 112 113 void ClientSession::deleteRecord(DbHandle db, RecordHandle record) 114 { 115 IPC(ucsp_client_deleteRecord(UCSP_ARGS, db, record)); 116 } 117 118 119 void ClientSession::modifyRecord(DbHandle db, RecordHandle &record, 120 CSSM_DB_RECORDTYPE recordType, 121 const CssmDbRecordAttributeData *attributes, 122 const CssmData *data, 123 CSSM_DB_MODIFY_MODE modifyMode) 124 { 125 CopyIn db_record_attr_data(attributes, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA)); 126 127 IPC(ucsp_client_modifyRecord(UCSP_ARGS, db, &record, recordType, db_record_attr_data.data(), (mach_msg_type_number_t)db_record_attr_data.length(), 128 data != NULL, OPTIONALDATA(data), modifyMode)); 129 } 130 131 static 132 void copy_back_attribute_return_data(CssmDbRecordAttributeData *dest_attrs, CssmDbRecordAttributeData *source_attrs, Allocator &returnAllocator) 133 { 134 assert(dest_attrs->size() == source_attrs->size()); 135 // global (per-record) fields 136 dest_attrs->recordType(source_attrs->recordType()); 137 dest_attrs->semanticInformation(source_attrs->semanticInformation()); 138 139 // transfer data values (but not infos, which we keep in the original vector) 140 for (uint32 n = 0; n < dest_attrs->size(); n++) 141 dest_attrs->at(n).copyValues(source_attrs->at(n), returnAllocator); 142 } 143 144 RecordHandle ClientSession::findFirst(DbHandle db, 145 const CssmQuery &inQuery, 146 SearchHandle &hSearch, 147 CssmDbRecordAttributeData *attributes, 148 CssmData *data, KeyHandle &hKey) 149 { 150 CopyIn query(&inQuery, reinterpret_cast<xdrproc_t>(xdr_CSSM_QUERY)); 151 CopyIn in_attr(attributes, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA)); 152 void *out_attr_data = NULL, *out_data = NULL; 153 mach_msg_size_t out_attr_length = 0, out_data_length = 0; 154 RecordHandle ipcHRecord = 0; 155 156 IPC(ucsp_client_findFirst(UCSP_ARGS, db, 157 query.data(), query.length(), in_attr.data(), in_attr.length(), 158 &out_attr_data, &out_attr_length, (data != NULL), &out_data, &out_data_length, 159 &hKey, &hSearch, &ipcHRecord)); 160 161 if (ipcHRecord != 0) 162 { 163 CopyOut out_attrs(out_attr_data, out_attr_length, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR), true); 164 copy_back_attribute_return_data(attributes, reinterpret_cast<CssmDbRecordAttributeData*>(out_attrs.data()), returnAllocator); 165 } 166 167 // decode data from server as cssm_data or cssm_key (get data on keys returns cssm_key in data) 168 CopyOut possible_key_in_data(out_data, out_data_length, reinterpret_cast<xdrproc_t>(xdr_CSSM_POSSIBLY_KEY_IN_DATA_PTR), true, data); 169 170 return ipcHRecord; 171 } 172 173 174 RecordHandle ClientSession::findNext(SearchHandle hSearch, 175 CssmDbRecordAttributeData *attributes, 176 CssmData *data, KeyHandle &hKey) 177 { 178 CopyIn in_attr(attributes, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA)); 179 void *out_attr_data = NULL, *out_data = NULL; 180 mach_msg_size_t out_attr_length = 0, out_data_length = 0; 181 //DataOutput out_data(data, returnAllocator); 182 RecordHandle ipcHRecord = 0; 183 184 IPC(ucsp_client_findNext(UCSP_ARGS, hSearch, 185 in_attr.data(), in_attr.length(), &out_attr_data, &out_attr_length, 186 (data != NULL), &out_data, &out_data_length, &hKey, &ipcHRecord)); 187 188 if (ipcHRecord != 0) 189 { 190 CopyOut out_attrs(out_attr_data, out_attr_length, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR), true); 191 copy_back_attribute_return_data(attributes, reinterpret_cast<CssmDbRecordAttributeData*>(out_attrs.data()), returnAllocator); 192 } 193 194 // decode data from server as cssm_data or cssm_key (get data on keys returns cssm_key in data) 195 CopyOut possible_key_in_data(out_data, out_data_length, reinterpret_cast<xdrproc_t>(xdr_CSSM_POSSIBLY_KEY_IN_DATA_PTR), true, data); 196 197 return ipcHRecord; 198 } 199 200 201 void ClientSession::findRecordHandle(RecordHandle hRecord, 202 CssmDbRecordAttributeData *attributes, 203 CssmData *data, KeyHandle &hKey) 204 { 205 CopyIn in_attr(attributes, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA)); 206 void *out_attr_data = NULL, *out_data = NULL; 207 mach_msg_size_t out_attr_length = 0, out_data_length = 0; 208 IPC(ucsp_client_findRecordHandle(UCSP_ARGS, hRecord, 209 in_attr.data(), in_attr.length(), &out_attr_data, &out_attr_length, 210 data != NULL, &out_data, &out_data_length, &hKey)); 211 212 if (hRecord != 0) 213 { 214 CopyOut out_attrs(out_attr_data, out_attr_length, reinterpret_cast<xdrproc_t>(xdr_CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR), true); 215 copy_back_attribute_return_data(attributes, reinterpret_cast<CssmDbRecordAttributeData*>(out_attrs.data()), returnAllocator); 216 } 217 218 // decode data from server as cssm_data or cssm_key (get data on keys returns cssm_key in data) 219 CopyOut possible_key_in_data(out_data, out_data_length, reinterpret_cast<xdrproc_t>(xdr_CSSM_POSSIBLY_KEY_IN_DATA_PTR), true, data); 220 } 221 222 223 void ClientSession::releaseSearch(SearchHandle searchHandle) 224 { 225 IPC(ucsp_client_releaseSearch(UCSP_ARGS, searchHandle)); 226 } 227 228 229 void ClientSession::releaseRecord(RecordHandle record) 230 { 231 IPC(ucsp_client_releaseRecord(UCSP_ARGS, record)); 232 } 233 234 void ClientSession::getDbName(DbHandle db, string &name) 235 { 236 char result[PATH_MAX]; 237 238 IPC(ucsp_client_getDbName(UCSP_ARGS, db, result)); 239 240 name = result; 241 } 242 243 void ClientSession::setDbName(DbHandle db, const string &name) 244 { 245 IPC(ucsp_client_setDbName(UCSP_ARGS, db, name.c_str())); 246 } 247 248 249 // 250 // Internal database management 251 // 252 DbHandle ClientSession::createDb(const DLDbIdentifier &dbId, 253 const AccessCredentials *cred, const AclEntryInput *owner, 254 const DBParameters ¶ms) 255 { 256 DatabaseAccessCredentials creds(cred, internalAllocator); 257 CopyIn copycreds(creds.value(), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 258 CopyIn proto(owner ? &owner->proto() : NULL, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE)); 259 // XXX/64 make xdr routines translate directly between dldbident and flat rep 260 DataWalkers::DLDbFlatIdentifier ident(dbId); 261 CopyIn id(&ident, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifier)); 262 DbHandle db; 263 264 IPC(ucsp_client_createDb(UCSP_ARGS, &db, id.data(), id.length(), copycreds.data(), copycreds.length(), proto.data(), proto.length(), params)); 265 266 return db; 267 } 268 269 DbHandle ClientSession::cloneDb(const DLDbIdentifier &newDbId, DbHandle srcDb) { 270 DataWalkers::DLDbFlatIdentifier ident(newDbId); 271 CopyIn id(&ident, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifier)); 272 273 DbHandle db; 274 IPC(ucsp_client_cloneDb(UCSP_ARGS, srcDb, id.data(), id.length(), &db)); 275 return db; 276 } 277 278 DbHandle ClientSession::recodeDbForSync(DbHandle dbToClone, 279 DbHandle srcDb) 280 { 281 DbHandle newDb; 282 283 IPC(ucsp_client_recodeDbForSync(UCSP_ARGS, dbToClone, srcDb, &newDb)); 284 285 return newDb; 286 } 287 288 DbHandle ClientSession::recodeDbToVersion(uint32 newVersion, DbHandle srcDb) 289 { 290 DbHandle newDb; 291 292 IPC(ucsp_client_recodeDbToVersion(UCSP_ARGS, newVersion, srcDb, &newDb)); 293 294 return newDb; 295 } 296 297 void ClientSession::recodeFinished(DbHandle db) 298 { 299 IPC(ucsp_client_recodeFinished(UCSP_ARGS, db)); 300 } 301 302 DbHandle ClientSession::authenticateDbsForSync(const CssmData &dbHandleArray, 303 const CssmData &agentData) 304 { 305 DbHandle newDb; 306 307 IPC(ucsp_client_authenticateDbsForSync(UCSP_ARGS, DATA(dbHandleArray), DATA(agentData), &newDb)); 308 309 return newDb; 310 } 311 312 void ClientSession::commitDbForSync(DbHandle srcDb, DbHandle cloneDb, 313 CssmData &blob, Allocator &alloc) 314 { 315 DataOutput outBlob(blob, alloc); 316 IPC(ucsp_client_commitDbForSync(UCSP_ARGS, srcDb, cloneDb, DATA_OUT(outBlob))); 317 } 318 319 DbHandle ClientSession::decodeDb(const DLDbIdentifier &dbId, 320 const AccessCredentials *cred, const CssmData &blob) 321 { 322 // XXX/64 fold into one translation 323 DatabaseAccessCredentials credentials(cred, internalAllocator); 324 CopyIn creds(credentials.value(), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 325 // XXX/64 fold into one translation 326 DataWalkers::DLDbFlatIdentifier ident(dbId); 327 CopyIn id(&ident, reinterpret_cast<xdrproc_t>(xdr_DLDbFlatIdentifier)); 328 DbHandle db; 329 330 IPC(ucsp_client_decodeDb(UCSP_ARGS, &db, id.data(), id.length(), creds.data(), creds.length(), DATA(blob))); 331 332 return db; 333 } 334 335 void ClientSession::encodeDb(DbHandle db, CssmData &blob, Allocator &alloc) 336 { 337 DataOutput outBlob(blob, alloc); 338 IPC(ucsp_client_encodeDb(UCSP_ARGS, db, DATA_OUT(outBlob))); 339 } 340 341 void ClientSession::setDbParameters(DbHandle db, const DBParameters ¶ms) 342 { 343 IPC(ucsp_client_setDbParameters(UCSP_ARGS, db, params)); 344 } 345 346 void ClientSession::getDbParameters(DbHandle db, DBParameters ¶ms) 347 { 348 IPC(ucsp_client_getDbParameters(UCSP_ARGS, db, ¶ms)); 349 } 350 351 void ClientSession::changePassphrase(DbHandle db, const AccessCredentials *cred) 352 { 353 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 354 IPC(ucsp_client_changePassphrase(UCSP_ARGS, db, creds.data(), creds.length())); 355 } 356 357 358 void ClientSession::lock(DbHandle db) 359 { 360 IPC(ucsp_client_authenticateDb(UCSP_ARGS, db, CSSM_DB_ACCESS_RESET, NULL, 0)); 361 //@@@VIRTUAL IPC(ucsp_client_lockDb(UCSP_ARGS, db)); 362 } 363 364 void ClientSession::lockAll (bool forSleep) 365 { 366 IPC(ucsp_client_lockAll (UCSP_ARGS, forSleep)); 367 } 368 369 void ClientSession::unlock(DbHandle db) 370 { 371 IPC(ucsp_client_unlockDb(UCSP_ARGS, db)); 372 } 373 374 void ClientSession::unlock(DbHandle db, const CssmData &passphrase) 375 { 376 IPC(ucsp_client_unlockDbWithPassphrase(UCSP_ARGS, db, DATA(passphrase))); 377 } 378 379 void ClientSession::stashDb(DbHandle db) 380 { 381 IPC(ucsp_client_stashDb(UCSP_ARGS, db)); 382 } 383 384 void ClientSession::stashDbCheck(DbHandle db) 385 { 386 IPC(ucsp_client_stashDbCheck(UCSP_ARGS, db)); 387 } 388 389 bool ClientSession::isLocked(DbHandle db) 390 { 391 boolean_t locked; 392 IPC(ucsp_client_isLocked(UCSP_ARGS, db, &locked)); 393 return locked; 394 } 395 396 void ClientSession::verifyKeyStorePassphrase(uint32_t retries) 397 { 398 IPC(ucsp_client_verifyKeyStorePassphrase(UCSP_ARGS, retries)); 399 } 400 401 void ClientSession::resetKeyStorePassphrase(const CssmData &passphrase) 402 { 403 IPC(ucsp_client_resetKeyStorePassphrase(UCSP_ARGS, DATA(passphrase))); 404 } 405 406 void ClientSession::changeKeyStorePassphrase() 407 { 408 IPC(ucsp_client_changeKeyStorePassphrase(UCSP_ARGS)); 409 } 410 411 // 412 // Key control 413 // 414 void ClientSession::encodeKey(KeyHandle key, CssmData &blob, 415 KeyUID *uid, Allocator &alloc) 416 { 417 // Not really used as output 418 DataOutput oBlob(blob, alloc); 419 void *uidp; 420 mach_msg_type_number_t uidLength; 421 422 IPC(ucsp_client_encodeKey(UCSP_ARGS, key, oBlob.data(), oBlob.length(), 423 (uid != NULL), &uidp, &uidLength)); 424 425 // return key uid if requested 426 if (uid) { 427 assert(uidLength == sizeof(KeyUID)); 428 memcpy(uid, uidp, sizeof(KeyUID)); 429 } 430 } 431 432 KeyHandle ClientSession::decodeKey(DbHandle db, const CssmData &blob, CssmKey::Header &header) 433 { 434 KeyHandle key; 435 void *keyHeaderData; 436 mach_msg_type_number_t keyHeaderDataLength; 437 438 IPC(ucsp_client_decodeKey(UCSP_ARGS, &key, &keyHeaderData, &keyHeaderDataLength, db, blob.data(), (mach_msg_type_number_t)blob.length())); 439 440 CopyOut wrappedKeyHeaderXDR(keyHeaderData, keyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 441 header = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedKeyHeaderXDR.data())); 442 443 return key; 444 } 445 446 // keychain synchronization 447 void ClientSession::recodeKey(DbHandle oldDb, KeyHandle key, DbHandle newDb, 448 CssmData &blob) 449 { 450 DataOutput outBlob(blob, returnAllocator); 451 IPC(ucsp_client_recodeKey(UCSP_ARGS, oldDb, key, newDb, DATA_OUT(outBlob))); 452 } 453 454 void ClientSession::releaseKey(KeyHandle key) 455 { 456 IPC(ucsp_client_releaseKey(UCSP_ARGS, key)); 457 } 458 459 460 CssmKeySize ClientSession::queryKeySizeInBits(KeyHandle key) 461 { 462 CssmKeySize length; 463 IPC(ucsp_client_queryKeySizeInBits(UCSP_ARGS, key, &length)); 464 return length; 465 } 466 467 468 uint32 ClientSession::getOutputSize(const Context &context, KeyHandle key, 469 uint32 inputSize, bool encrypt) 470 { 471 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 472 uint32 outputSize; 473 474 IPC(ucsp_client_getOutputSize(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, inputSize, encrypt, &outputSize)); 475 return outputSize; 476 } 477 478 479 // 480 // Random number generation. 481 // This interfaces to the secure RNG inside the SecurityServer; it does not access 482 // a PRNG in its CSP. If you need a reproducible PRNG, attach a local CSP and use it. 483 // Note that this function does not allocate a buffer; it always fills the buffer provided. 484 // 485 // As of macOS 10.15 this no longer fetches random data from the daemon but generates it in-process 486 // 487 void ClientSession::generateRandom(const Security::Context &context, CssmData &data, Allocator &alloc) 488 { 489 size_t count = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE); 490 if (data.length() < count) { 491 CssmError::throwMe(CSSM_ERRCODE_INVALID_DATA); 492 } 493 CCRNGStatus status = CCRandomGenerateBytes(data.data(), count); 494 if (status != kCCSuccess) { 495 CssmError::throwMe(status); 496 } 497 } 498 499 500 // 501 // Signatures and MACs 502 // 503 void ClientSession::generateSignature(const Context &context, KeyHandle key, 504 const CssmData &data, CssmData &signature, Allocator &alloc, CSSM_ALGORITHMS signOnlyAlgorithm) 505 { 506 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 507 DataOutput sig(signature, alloc); 508 509 IPCKEY(ucsp_client_generateSignature(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, signOnlyAlgorithm, 510 DATA(data), DATA_OUT(sig)), 511 key, CSSM_ACL_AUTHORIZATION_SIGN); 512 } 513 514 void ClientSession::verifySignature(const Context &context, KeyHandle key, 515 const CssmData &data, const CssmData &signature, CSSM_ALGORITHMS verifyOnlyAlgorithm) 516 { 517 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 518 519 IPC(ucsp_client_verifySignature(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, verifyOnlyAlgorithm, DATA(data), DATA(signature))); 520 } 521 522 523 void ClientSession::generateMac(const Context &context, KeyHandle key, 524 const CssmData &data, CssmData &signature, Allocator &alloc) 525 { 526 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 527 DataOutput sig(signature, alloc); 528 529 IPCKEY(ucsp_client_generateMac(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, DATA(data), DATA_OUT(sig)), 530 key, CSSM_ACL_AUTHORIZATION_MAC); 531 } 532 533 void ClientSession::verifyMac(const Context &context, KeyHandle key, 534 const CssmData &data, const CssmData &signature) 535 { 536 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 537 538 IPCKEY(ucsp_client_verifyMac(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, 539 DATA(data), DATA(signature)), 540 key, CSSM_ACL_AUTHORIZATION_MAC); 541 } 542 543 544 // 545 // Encryption/Decryption 546 // 547 548 void ClientSession::encrypt(const Context &context, KeyHandle key, 549 const CssmData &clear, CssmData &cipher, Allocator &alloc) 550 { 551 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 552 DataOutput cipherOut(cipher, alloc); 553 IPCKEY(ucsp_client_encrypt(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, DATA(clear), DATA_OUT(cipherOut)), 554 key, CSSM_ACL_AUTHORIZATION_ENCRYPT); 555 } 556 557 void ClientSession::decrypt(const Context &context, KeyHandle key, 558 const CssmData &cipher, CssmData &clear, Allocator &alloc) 559 { 560 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 561 DataOutput clearOut(clear, alloc); 562 563 IPCKEY(ucsp_client_decrypt(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, DATA(cipher), DATA_OUT(clearOut)), 564 key, CSSM_ACL_AUTHORIZATION_DECRYPT); 565 } 566 567 568 // 569 // Key generation 570 // 571 void ClientSession::generateKey(DbHandle db, const Context &context, uint32 keyUsage, uint32 keyAttr, 572 const AccessCredentials *cred, const AclEntryInput *owner, 573 KeyHandle &newKey, CssmKey::Header &newHeader) 574 { 575 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 576 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 577 CopyIn proto(owner ? &owner->proto() : NULL, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE)); 578 void *keyHeaderData; 579 mach_msg_type_number_t keyHeaderDataLength; 580 581 IPC(ucsp_client_generateKey(UCSP_ARGS, db, ctxcopy.data(), ctxcopy.length(), 582 creds.data(), creds.length(), proto.data(), proto.length(), 583 keyUsage, keyAttr, &newKey, &keyHeaderData, &keyHeaderDataLength)); 584 585 CopyOut wrappedKeyHeaderXDR(keyHeaderData, keyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 586 newHeader = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedKeyHeaderXDR.data())); 587 } 588 589 void ClientSession::generateKey(DbHandle db, const Context &context, 590 uint32 pubKeyUsage, uint32 pubKeyAttr, 591 uint32 privKeyUsage, uint32 privKeyAttr, 592 const AccessCredentials *cred, const AclEntryInput *owner, 593 KeyHandle &pubKey, CssmKey::Header &pubHeader, 594 KeyHandle &privKey, CssmKey::Header &privHeader) 595 { 596 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 597 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 598 CopyIn proto(owner ? &owner->proto() : NULL, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE)); 599 void *pubKeyHeaderData, *privKeyHeaderData; 600 mach_msg_type_number_t pubKeyHeaderDataLength, privKeyHeaderDataLength; 601 602 IPC(ucsp_client_generateKeyPair(UCSP_ARGS, db, ctxcopy.data(), ctxcopy.length(), 603 creds.data(), creds.length(), proto.data(), proto.length(), 604 pubKeyUsage, pubKeyAttr, privKeyUsage, privKeyAttr, 605 &pubKey, &pubKeyHeaderData, &pubKeyHeaderDataLength, 606 &privKey, &privKeyHeaderData, &privKeyHeaderDataLength)); 607 608 CopyOut wrappedPubKeyHeaderXDR(pubKeyHeaderData, pubKeyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 609 pubHeader = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedPubKeyHeaderXDR.data())); 610 CopyOut wrappedPrivKeyHeaderXDR(privKeyHeaderData, privKeyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 611 privHeader = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedPrivKeyHeaderXDR.data())); 612 613 } 614 615 616 // 617 // Key derivation 618 // This is a bit strained; the incoming 'param' value may have structure, 619 // and we use a synthetic CssmDeriveData structure (with ad-hoc walker) to 620 // handle that. Param also is input/output, which is always a pain (not to mention 621 // ill-defined by the CDSA standard). 622 // 623 // If you're here because an algorithm of yours requires structured parameter 624 // input, go to security_cdsa_utilities/cssmwalkers.h and add a case to the 625 // CssmDeriveData walker. 626 // 627 void ClientSession::deriveKey(DbHandle db, const Context &context, KeyHandle baseKey, 628 CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, CssmData ¶m, 629 const AccessCredentials *cred, const AclEntryInput *owner, 630 KeyHandle &newKey, CssmKey::Header &newHeader, Allocator &allocator) 631 { 632 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 633 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 634 CopyIn proto(owner ? &owner->proto() : NULL, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE)); 635 CSSM_DERIVE_DATA inParamForm = { context.algorithm(), param }; 636 CopyIn inParam(&inParamForm, reinterpret_cast<xdrproc_t>(xdr_CSSM_DERIVE_DATA)); 637 638 try 639 { 640 DataOutput paramOutput(param, allocator); 641 void *keyHeaderData; 642 mach_msg_type_number_t keyHeaderDataLength; 643 644 IPCKEY(ucsp_client_deriveKey(UCSP_ARGS, db, ctxcopy.data(), ctxcopy.length(), baseKey, 645 creds.data(), creds.length(), proto.data(), proto.length(), 646 inParam.data(), inParam.length(), DATA_OUT(paramOutput), 647 usage, attrs, &newKey, &keyHeaderData, &keyHeaderDataLength), 648 baseKey, CSSM_ACL_AUTHORIZATION_DERIVE); 649 650 CopyOut wrappedKeyHeaderXDR(keyHeaderData, keyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 651 newHeader = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedKeyHeaderXDR.data())); 652 } 653 catch (CssmError& e) 654 { 655 // filter out errors for CSSM_ALGID_PKCS5_PBKDF2 656 if (context.algorithm() != CSSM_ALGID_PKCS5_PBKDF2 && e.error != CSSMERR_CSP_OUTPUT_LENGTH_ERROR) 657 { 658 throw; 659 } 660 } 661 } 662 663 664 // 665 // Digest generation 666 // 667 void ClientSession::getKeyDigest(KeyHandle key, CssmData &digest, Allocator &allocator) 668 { 669 DataOutput dig(digest, allocator); 670 IPC(ucsp_client_getKeyDigest(UCSP_ARGS, key, DATA_OUT(dig))); 671 } 672 673 674 // 675 // Key wrapping and unwrapping 676 // 677 void ClientSession::wrapKey(const Context &context, KeyHandle wrappingKey, 678 KeyHandle keyToBeWrapped, const AccessCredentials *cred, 679 const CssmData *descriptiveData, CssmWrappedKey &wrappedKey, Allocator &alloc) 680 { 681 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 682 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 683 void *keyData; 684 mach_msg_type_number_t keyDataLength; 685 686 IPCKEY(ucsp_client_wrapKey(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), wrappingKey, 687 creds.data(), creds.length(), 688 keyToBeWrapped, OPTIONALDATA(descriptiveData), 689 &keyData, &keyDataLength), 690 keyToBeWrapped, 691 context.algorithm() == CSSM_ALGID_NONE 692 ? CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED); 693 694 CopyOut wrappedKeyXDR(keyData, keyDataLength + sizeof(CSSM_KEY), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY_PTR), true); 695 CssmWrappedKey *wrappedKeyIPC = reinterpret_cast<CssmWrappedKey*>(wrappedKeyXDR.data()); 696 wrappedKey.header() = wrappedKeyIPC->header(); 697 wrappedKey.keyData() = CssmData(alloc.malloc(wrappedKeyIPC->keyData().length()), wrappedKeyIPC->keyData().length()); 698 memcpy(wrappedKey.keyData().data(), wrappedKeyIPC->keyData(), wrappedKeyIPC->keyData().length()); 699 } 700 701 void ClientSession::unwrapKey(DbHandle db, const Context &context, KeyHandle key, 702 KeyHandle publicKey, const CssmWrappedKey &wrappedKey, 703 uint32 usage, uint32 attr, 704 const AccessCredentials *cred, const AclEntryInput *acl, 705 CssmData &descriptiveData, 706 KeyHandle &newKey, CssmKey::Header &newHeader, Allocator &alloc) 707 { 708 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 709 DataOutput descriptor(descriptiveData, alloc); 710 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 711 CopyIn proto(acl ? &acl->proto() : NULL, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE)); 712 CopyIn wrappedKeyXDR(&wrappedKey, reinterpret_cast<xdrproc_t>(xdr_CSSM_KEY)); 713 void *keyHeaderData; 714 mach_msg_type_number_t keyHeaderDataLength; 715 716 IPCKEY(ucsp_client_unwrapKey(UCSP_ARGS, db, ctxcopy.data(), ctxcopy.length(), key, 717 creds.data(), creds.length(), proto.data(), proto.length(), 718 publicKey, wrappedKeyXDR.data(), wrappedKeyXDR.length(), usage, attr, DATA_OUT(descriptor), 719 &newKey, &keyHeaderData, &keyHeaderDataLength), 720 key, CSSM_ACL_AUTHORIZATION_DECRYPT); 721 722 CopyOut wrappedKeyHeaderXDR(keyHeaderData, keyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 723 newHeader = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedKeyHeaderXDR.data())); 724 } 725 726 727 // 728 // ACL management 729 // 730 void ClientSession::getAcl(AclKind kind, GenericHandle key, const char *tag, 731 uint32 &infoCount, AclEntryInfo * &infoArray, Allocator &alloc) 732 { 733 uint32 count; 734 void* info; mach_msg_type_number_t infoLength; 735 IPC(ucsp_client_getAcl(UCSP_ARGS, kind, key, 736 (tag != NULL), tag ? tag : "", 737 &count, &info, &infoLength)); 738 739 CSSM_ACL_ENTRY_INFO_ARRAY_PTR aclsArray; 740 if (!::copyout_chunked(info, infoLength, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_INFO_ARRAY_PTR), reinterpret_cast<void**>(&aclsArray))) 741 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR); 742 743 infoCount = aclsArray->count; 744 infoArray = reinterpret_cast<AclEntryInfo*>(aclsArray->acls); 745 free(aclsArray); 746 } 747 748 void ClientSession::changeAcl(AclKind kind, GenericHandle key, const AccessCredentials &cred, 749 const AclEdit &edit) 750 { 751 CopyIn creds(&cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 752 //@@@ ignoring callback 753 CopyIn newEntry(edit.newEntry(), reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_INPUT)); 754 755 IPCKEY(ucsp_client_changeAcl(UCSP_ARGS, kind, key, creds.data(), creds.length(), 756 edit.mode(), toIPCHandle(edit.handle()), newEntry.data(), newEntry.length()), 757 key, CSSM_ACL_AUTHORIZATION_CHANGE_ACL); 758 } 759 760 void ClientSession::getOwner(AclKind kind, GenericHandle key, AclOwnerPrototype &owner, 761 Allocator &alloc) 762 { 763 void* proto; mach_msg_type_number_t protoLength; 764 IPC(ucsp_client_getOwner(UCSP_ARGS, kind, key, &proto, &protoLength)); 765 766 CSSM_ACL_OWNER_PROTOTYPE_PTR tmpOwner; 767 if (!::copyout_chunked(proto, protoLength, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_OWNER_PROTOTYPE_PTR), reinterpret_cast<void **>(&tmpOwner))) 768 CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR); 769 owner = *static_cast<AclOwnerPrototypePtr>(tmpOwner); 770 free(tmpOwner); 771 } 772 773 void ClientSession::changeOwner(AclKind kind, GenericHandle key, 774 const AccessCredentials &cred, const AclOwnerPrototype &proto) 775 { 776 CopyIn creds(&cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 777 CopyIn protos(&proto, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_OWNER_PROTOTYPE)); 778 IPCKEY(ucsp_client_setOwner(UCSP_ARGS, kind, key, creds.data(), creds.length(), protos.data(), protos.length()), 779 key, CSSM_ACL_AUTHORIZATION_CHANGE_OWNER); 780 } 781 782 783 void ClientSession::getKeyAcl(DbHandle db, const char *tag, 784 uint32 &count, AclEntryInfo * &info, Allocator &alloc) 785 { getAcl(keyAcl, db, tag, count, info, alloc); } 786 787 void ClientSession::changeKeyAcl(DbHandle db, const AccessCredentials &cred, 788 const AclEdit &edit) 789 { changeAcl(keyAcl, db, cred, edit); } 790 791 void ClientSession::getKeyOwner(DbHandle db, AclOwnerPrototype &owner, Allocator &alloc) 792 { getOwner(keyAcl, db, owner, alloc); } 793 794 void ClientSession::changeKeyOwner(DbHandle db, const AccessCredentials &cred, 795 const AclOwnerPrototype &edit) 796 { changeOwner(keyAcl, db, cred, edit); } 797 798 void ClientSession::getDbAcl(DbHandle db, const char *tag, 799 uint32 &count, AclEntryInfo * &info, Allocator &alloc) 800 { getAcl(dbAcl, db, tag, count, info, alloc); } 801 802 void ClientSession::changeDbAcl(DbHandle db, const AccessCredentials &cred, 803 const AclEdit &edit) 804 { changeAcl(dbAcl, db, cred, edit); } 805 806 void ClientSession::getDbOwner(DbHandle db, AclOwnerPrototype &owner, Allocator &alloc) 807 { getOwner(dbAcl, db, owner, alloc); } 808 809 void ClientSession::changeDbOwner(DbHandle db, const AccessCredentials &cred, 810 const AclOwnerPrototype &edit) 811 { changeOwner(dbAcl, db, cred, edit); } 812 813 814 // 815 // Database key management 816 // 817 void ClientSession::extractMasterKey(DbHandle db, const Context &context, DbHandle sourceDb, 818 uint32 keyUsage, uint32 keyAttr, 819 const AccessCredentials *cred, const AclEntryInput *owner, 820 KeyHandle &newKey, CssmKey::Header &newHeader, Allocator &alloc) 821 { 822 CopyIn ctxcopy(&context, reinterpret_cast<xdrproc_t>(xdr_CSSM_CONTEXT)); 823 CopyIn creds(cred, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACCESS_CREDENTIALS)); 824 CopyIn proto(owner ? &owner->proto() : NULL, reinterpret_cast<xdrproc_t>(xdr_CSSM_ACL_ENTRY_PROTOTYPE)); 825 void *keyHeaderData; 826 mach_msg_type_number_t keyHeaderDataLength; 827 828 IPC(ucsp_client_extractMasterKey(UCSP_ARGS, db, ctxcopy.data(), ctxcopy.length(), sourceDb, 829 creds.data(), creds.length(), proto.data(), proto.length(), 830 keyUsage, keyAttr, &newKey, &keyHeaderData, &keyHeaderDataLength)); 831 832 CopyOut wrappedKeyHeaderXDR(keyHeaderData, keyHeaderDataLength + sizeof(CSSM_KEYHEADER), reinterpret_cast<xdrproc_t>(xdr_CSSM_KEYHEADER_PTR), true); 833 newHeader = *static_cast<CssmKey::Header *>(reinterpret_cast<CSSM_KEYHEADER*>(wrappedKeyHeaderXDR.data())); 834 } 835 836 837 void ClientSession::postNotification(NotificationDomain domain, NotificationEvent event, const CssmData &data) 838 { 839 uint32 seq = ++mGlobal().thread().notifySeq; 840 #if !defined(NDEBUG) 841 if (getenv("NOTIFYJITTER")) { 842 // artificially reverse odd/even sequences to test securityd's jitter buffer 843 seq += 2 * (seq % 2) - 1; 844 secinfo("notify", "POSTING FAKE SEQUENCE %d NOTIFICATION", seq); 845 } 846 #endif //NDEBUG 847 secinfo("notify", "posting domain 0x%x event %d sequence %d", 848 domain, event, seq); 849 IPC(ucsp_client_postNotification(UCSP_ARGS, domain, event, DATA(data), seq)); 850 } 851 852 853 // 854 // Testing related 855 // 856 857 // Return the number of Keychain users prompts securityd has considered showing. 858 // On non-internal installs, this returns 0. 859 void ClientSession::getUserPromptAttempts(uint32_t& attempts) { 860 IPC(ucsp_client_getUserPromptAttempts(UCSP_ARGS, &attempts)); 861 } 862 863 864 } // end namespace SecurityServer 865 } // end namespace Security