/ OSX / libsecurityd / lib / transition.cpp
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 &params)
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 &params)
342  {
343  	IPC(ucsp_client_setDbParameters(UCSP_ARGS, db, params));
344  }
345  
346  void ClientSession::getDbParameters(DbHandle db, DBParameters &params)
347  {
348  	IPC(ucsp_client_getDbParameters(UCSP_ARGS, db, &params));
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 &param,
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