]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurityd/lib/transition.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurityd / lib / transition.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2000-2008,2011-2013 Apple Inc. All Rights Reserved.
b1ab9ed8
A
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>
b1ab9ed8 52
b54c578e 53#include <CommonCrypto/CommonRandom.h>
b1ab9ed8
A
54#include <securityd_client/xdr_auth.h>
55#include <securityd_client/xdr_cssm.h>
56#include <securityd_client/xdr_dldb.h>
57
58namespace Security {
59namespace SecurityServer {
60
61using MachPlusPlus::check;
62using MachPlusPlus::VMGuard;
63
64//
65// Common database interface
66//
67void 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
77void ClientSession::releaseDb(DbHandle db)
78{
79 IPC(ucsp_client_releaseDb(UCSP_ARGS, db));
80}
81
82
83//
84// External database interface
85//
86DbHandle 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
99RecordHandle 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
427c49bc 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));
b1ab9ed8
A
108
109 return record;
110}
111
112
113void ClientSession::deleteRecord(DbHandle db, RecordHandle record)
114{
115 IPC(ucsp_client_deleteRecord(UCSP_ARGS, db, record));
116}
117
118
119void 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
427c49bc 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(),
b1ab9ed8
A
128 data != NULL, OPTIONALDATA(data), modifyMode));
129}
130
427c49bc 131static
b1ab9ed8
A
132void 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
144RecordHandle 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
174RecordHandle 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
201void 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
223void ClientSession::releaseSearch(SearchHandle searchHandle)
224{
225 IPC(ucsp_client_releaseSearch(UCSP_ARGS, searchHandle));
226}
227
228
229void ClientSession::releaseRecord(RecordHandle record)
230{
231 IPC(ucsp_client_releaseRecord(UCSP_ARGS, record));
232}
233
234void 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
243void 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//
252DbHandle 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
fa7225c8
A
269DbHandle 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
b1ab9ed8
A
278DbHandle ClientSession::recodeDbForSync(DbHandle dbToClone,
279 DbHandle srcDb)
280{
281 DbHandle newDb;
282
283 IPC(ucsp_client_recodeDbForSync(UCSP_ARGS, dbToClone, srcDb, &newDb));
fa7225c8
A
284
285 return newDb;
b1ab9ed8
A
286}
287
e3d460c9
A
288DbHandle 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
fa7225c8
A
297void ClientSession::recodeFinished(DbHandle db)
298{
299 IPC(ucsp_client_recodeFinished(UCSP_ARGS, db));
300}
301
b1ab9ed8
A
302DbHandle 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
312void ClientSession::commitDbForSync(DbHandle srcDb, DbHandle cloneDb,
313 CssmData &blob, Allocator &alloc)
314{
315 DataOutput outBlob(blob, alloc);
427c49bc 316 IPC(ucsp_client_commitDbForSync(UCSP_ARGS, srcDb, cloneDb, DATA_OUT(outBlob)));
b1ab9ed8
A
317}
318
319DbHandle 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
335void ClientSession::encodeDb(DbHandle db, CssmData &blob, Allocator &alloc)
336{
337 DataOutput outBlob(blob, alloc);
427c49bc 338 IPC(ucsp_client_encodeDb(UCSP_ARGS, db, DATA_OUT(outBlob)));
b1ab9ed8
A
339}
340
341void ClientSession::setDbParameters(DbHandle db, const DBParameters &params)
342{
343 IPC(ucsp_client_setDbParameters(UCSP_ARGS, db, params));
344}
345
346void ClientSession::getDbParameters(DbHandle db, DBParameters &params)
347{
348 IPC(ucsp_client_getDbParameters(UCSP_ARGS, db, &params));
349}
350
351void 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
358void 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
364void ClientSession::lockAll (bool forSleep)
365{
366 IPC(ucsp_client_lockAll (UCSP_ARGS, forSleep));
367}
368
369void ClientSession::unlock(DbHandle db)
370{
371 IPC(ucsp_client_unlockDb(UCSP_ARGS, db));
372}
373
374void ClientSession::unlock(DbHandle db, const CssmData &passphrase)
375{
376 IPC(ucsp_client_unlockDbWithPassphrase(UCSP_ARGS, db, DATA(passphrase)));
377}
378
427c49bc
A
379void ClientSession::stashDb(DbHandle db)
380{
381 IPC(ucsp_client_stashDb(UCSP_ARGS, db));
382}
383
384void ClientSession::stashDbCheck(DbHandle db)
385{
386 IPC(ucsp_client_stashDbCheck(UCSP_ARGS, db));
387}
388
b1ab9ed8
A
389bool ClientSession::isLocked(DbHandle db)
390{
391 boolean_t locked;
392 IPC(ucsp_client_isLocked(UCSP_ARGS, db, &locked));
393 return locked;
394}
395
427c49bc
A
396void ClientSession::verifyKeyStorePassphrase(uint32_t retries)
397{
398 IPC(ucsp_client_verifyKeyStorePassphrase(UCSP_ARGS, retries));
399}
400
401void ClientSession::resetKeyStorePassphrase(const CssmData &passphrase)
402{
403 IPC(ucsp_client_resetKeyStorePassphrase(UCSP_ARGS, DATA(passphrase)));
404}
405
406void ClientSession::changeKeyStorePassphrase()
407{
408 IPC(ucsp_client_changeKeyStorePassphrase(UCSP_ARGS));
409}
b1ab9ed8
A
410
411//
412// Key control
413//
414void 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
432KeyHandle 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
427c49bc 438 IPC(ucsp_client_decodeKey(UCSP_ARGS, &key, &keyHeaderData, &keyHeaderDataLength, db, blob.data(), (mach_msg_type_number_t)blob.length()));
b1ab9ed8
A
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
447void ClientSession::recodeKey(DbHandle oldDb, KeyHandle key, DbHandle newDb,
448 CssmData &blob)
449{
450 DataOutput outBlob(blob, returnAllocator);
427c49bc 451 IPC(ucsp_client_recodeKey(UCSP_ARGS, oldDb, key, newDb, DATA_OUT(outBlob)));
b1ab9ed8
A
452}
453
454void ClientSession::releaseKey(KeyHandle key)
455{
456 IPC(ucsp_client_releaseKey(UCSP_ARGS, key));
457}
458
459
460CssmKeySize ClientSession::queryKeySizeInBits(KeyHandle key)
461{
462 CssmKeySize length;
463 IPC(ucsp_client_queryKeySizeInBits(UCSP_ARGS, key, &length));
464 return length;
465}
466
467
468uint32 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//
b54c578e
A
485// As of macOS 10.15 this no longer fetches random data from the daemon but generates it in-process
486//
b1ab9ed8
A
487void ClientSession::generateRandom(const Security::Context &context, CssmData &data, Allocator &alloc)
488{
b54c578e
A
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 }
b1ab9ed8
A
497}
498
499
500//
501// Signatures and MACs
502//
503void 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,
427c49bc 510 DATA(data), DATA_OUT(sig)),
b1ab9ed8
A
511 key, CSSM_ACL_AUTHORIZATION_SIGN);
512}
513
514void 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
523void 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
427c49bc 529 IPCKEY(ucsp_client_generateMac(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, DATA(data), DATA_OUT(sig)),
b1ab9ed8
A
530 key, CSSM_ACL_AUTHORIZATION_MAC);
531}
532
533void 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
548void 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);
427c49bc 553 IPCKEY(ucsp_client_encrypt(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, DATA(clear), DATA_OUT(cipherOut)),
b1ab9ed8
A
554 key, CSSM_ACL_AUTHORIZATION_ENCRYPT);
555}
556
557void 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
427c49bc 563 IPCKEY(ucsp_client_decrypt(UCSP_ARGS, ctxcopy.data(), ctxcopy.length(), key, DATA(cipher), DATA_OUT(clearOut)),
b1ab9ed8
A
564 key, CSSM_ACL_AUTHORIZATION_DECRYPT);
565}
566
567
568//
569// Key generation
570//
571void 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
589void 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//
627void 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(),
427c49bc 646 inParam.data(), inParam.length(), DATA_OUT(paramOutput),
b1ab9ed8
A
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//
667void ClientSession::getKeyDigest(KeyHandle key, CssmData &digest, Allocator &allocator)
668{
669 DataOutput dig(digest, allocator);
427c49bc 670 IPC(ucsp_client_getKeyDigest(UCSP_ARGS, key, DATA_OUT(dig)));
b1ab9ed8
A
671}
672
673
674//
675// Key wrapping and unwrapping
676//
677void 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
701void 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(),
427c49bc 718 publicKey, wrappedKeyXDR.data(), wrappedKeyXDR.length(), usage, attr, DATA_OUT(descriptor),
b1ab9ed8
A
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//
730void 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
748void 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
760void 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
773void 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
783void ClientSession::getKeyAcl(DbHandle db, const char *tag,
784 uint32 &count, AclEntryInfo * &info, Allocator &alloc)
785{ getAcl(keyAcl, db, tag, count, info, alloc); }
786
787void ClientSession::changeKeyAcl(DbHandle db, const AccessCredentials &cred,
788 const AclEdit &edit)
789{ changeAcl(keyAcl, db, cred, edit); }
790
791void ClientSession::getKeyOwner(DbHandle db, AclOwnerPrototype &owner, Allocator &alloc)
792{ getOwner(keyAcl, db, owner, alloc); }
793
794void ClientSession::changeKeyOwner(DbHandle db, const AccessCredentials &cred,
795 const AclOwnerPrototype &edit)
796{ changeOwner(keyAcl, db, cred, edit); }
797
798void ClientSession::getDbAcl(DbHandle db, const char *tag,
799 uint32 &count, AclEntryInfo * &info, Allocator &alloc)
800{ getAcl(dbAcl, db, tag, count, info, alloc); }
801
802void ClientSession::changeDbAcl(DbHandle db, const AccessCredentials &cred,
803 const AclEdit &edit)
804{ changeAcl(dbAcl, db, cred, edit); }
805
806void ClientSession::getDbOwner(DbHandle db, AclOwnerPrototype &owner, Allocator &alloc)
807{ getOwner(dbAcl, db, owner, alloc); }
808
809void 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//
817void 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
b1ab9ed8
A
837void 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;
fa7225c8 844 secinfo("notify", "POSTING FAKE SEQUENCE %d NOTIFICATION", seq);
b1ab9ed8
A
845 }
846#endif //NDEBUG
fa7225c8 847 secinfo("notify", "posting domain 0x%x event %d sequence %d",
b1ab9ed8
A
848 domain, event, seq);
849 IPC(ucsp_client_postNotification(UCSP_ARGS, domain, event, DATA(data), seq));
850}
851
b1ab9ed8 852
fa7225c8
A
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.
859void ClientSession::getUserPromptAttempts(uint32_t& attempts) {
860 IPC(ucsp_client_getUserPromptAttempts(UCSP_ARGS, &attempts));
861}
862
b1ab9ed8
A
863
864} // end namespace SecurityServer
865} // end namespace Security