2 * Copyright (c) 2000-2004,2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // transition - securityd IPC-to-class-methods transition layer
28 #include <securityd_client/ucsp.h>
32 #include "kcdatabase.h"
33 #include "tokendatabase.h"
35 #include "transwalkers.h"
37 #include <mach/mach_error.h>
38 #include "securityd_data_saver.h" // for SecuritydDataSave
40 #include <CoreFoundation/CFDictionary.h>
41 #include <CoreFoundation/CFPropertyList.h>
47 #define UCSP_ARGS mach_port_t servicePort, mach_port_t replyPort, audit_token_t auditToken, \
49 #define CONTEXT_ARGS Context context, Pointer contextBase, Context::Attr *attributes, mach_msg_type_number_t attrSize
51 #define BEGIN_IPCN *rcode = CSSM_OK; try {
52 #define BEGIN_IPC BEGIN_IPCN RefPointer<Connection> connRef(&Server::connection(replyPort)); \
53 Connection &connection __attribute__((unused)) = *connRef;
54 #define END_IPC(base) END_IPCN(base) Server::requestComplete(); return KERN_SUCCESS;
55 #define END_IPCN(base) } \
56 catch (const CommonError &err) { *rcode = CssmError::cssmError(err, CSSM_ ## base ## _BASE_ERROR); } \
57 catch (const std::bad_alloc &) { *rcode = CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
58 catch (Connection *conn) { *rcode = 0; } \
59 catch (...) { *rcode = CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_ ## base ## _BASE_ERROR); }
61 #define BEGIN_IPCS try {
62 #define END_IPCS(more) } catch (...) { } \
63 mach_port_deallocate(mach_task_self(), serverPort); more; return KERN_SUCCESS;
65 #define DATA_IN(base) void *base, mach_msg_type_number_t base##Length
66 #define DATA_OUT(base) void **base, mach_msg_type_number_t *base##Length
67 #define DATA(base) CssmData(base, base##Length)
68 #define OPTDATA(base) (base ? &CssmData(base, base##Length) : NULL)
70 #define SSBLOB(Type, name) makeBlob<Type>(DATA(name))
72 #define COPY_IN(type,name) type *name, mach_msg_type_number_t name##Length, type *name##Base
73 #define COPY_OUT(type,name) \
74 type **name, mach_msg_type_number_t *name##Length, type **name##Base
77 using LowLevelMemoryUtilities::increment
;
78 using LowLevelMemoryUtilities::difference
;
82 // Setup/Teardown functions.
84 kern_return_t
ucsp_server_setup(UCSP_ARGS
, mach_port_t taskPort
, ClientSetupInfo info
, const char *identity
)
87 Server::active().setupConnection(Server::connectNewProcess
, servicePort
, replyPort
,
88 taskPort
, auditToken
, &info
, identity
);
93 kern_return_t
ucsp_server_setupNew(UCSP_ARGS
, mach_port_t taskPort
,
94 ClientSetupInfo info
, const char *identity
,
95 mach_port_t
*newServicePort
)
99 RefPointer
<Session
> session
= new DynamicSession(taskPort
);
100 Server::active().setupConnection(Server::connectNewSession
, session
->servicePort(), replyPort
,
101 taskPort
, auditToken
, &info
, identity
);
102 *newServicePort
= session
->servicePort();
103 } catch (const MachPlusPlus::Error
&err
) {
105 case BOOTSTRAP_SERVICE_ACTIVE
:
106 MacOSError::throwMe(errSessionAuthorizationDenied
); // translate
115 kern_return_t
ucsp_server_setupThread(UCSP_ARGS
, mach_port_t taskPort
)
118 Server::active().setupConnection(Server::connectNewThread
, servicePort
, replyPort
,
119 taskPort
, auditToken
);
125 kern_return_t
ucsp_server_teardown(UCSP_ARGS
)
128 Server::active().endConnection(replyPort
);
135 // Common database operations
137 kern_return_t
ucsp_server_authenticateDb(UCSP_ARGS
, DbHandle db
,
138 CSSM_DB_ACCESS_TYPE accessType
, COPY_IN(AccessCredentials
, cred
))
141 secdebug("dl", "authenticateDb");
142 relocate(cred
, credBase
, credLength
);
143 // ignoring accessType
144 Server::database(db
)->authenticate(accessType
, cred
);
148 kern_return_t
ucsp_server_releaseDb(UCSP_ARGS
, DbHandle db
)
151 connection
.process().kill(*Server::database(db
));
156 kern_return_t
ucsp_server_getDbName(UCSP_ARGS
, DbHandle db
, char name
[PATH_MAX
])
159 string result
= Server::database(db
)->dbName();
160 assert(result
.length() < PATH_MAX
);
161 memcpy(name
, result
.c_str(), result
.length() + 1);
165 kern_return_t
ucsp_server_setDbName(UCSP_ARGS
, DbHandle db
, const char *name
)
168 Server::database(db
)->dbName(name
);
174 // External database interface
176 kern_return_t
ucsp_server_openToken(UCSP_ARGS
, uint32 ssid
, FilePath name
,
177 COPY_IN(AccessCredentials
, accessCredentials
), DbHandle
*db
)
180 relocate(accessCredentials
, accessCredentialsBase
, accessCredentialsLength
);
181 *db
= (new TokenDatabase(ssid
, connection
.process(), name
, accessCredentials
))->handle();
185 kern_return_t
ucsp_server_findFirst(UCSP_ARGS
, DbHandle db
,
186 COPY_IN(CssmQuery
, query
),
187 COPY_IN(CssmDbRecordAttributeData
, inAttributes
),
188 COPY_OUT(CssmDbRecordAttributeData
, outAttributes
),
190 DATA_OUT(data
), KeyHandle
*hKey
, SearchHandle
*hSearch
, RecordHandle
*hRecord
)
193 relocate(query
, queryBase
, queryLength
);
194 SecuritydDataSave
sds("/var/tmp/Query_findFirst");
195 sds
.writeQuery(query
, queryLength
);
196 relocate(inAttributes
, inAttributesBase
, inAttributesLength
);
198 RefPointer
<Database::Search
> search
;
199 RefPointer
<Database::Record
> record
;
201 CssmData outData
; //OutputData outData(data, dataLength);
202 CssmDbRecordAttributeData
*outAttrs
; mach_msg_type_number_t outAttrsLength
;
203 Server::database(db
)->findFirst(*query
, inAttributes
, inAttributesLength
,
204 getData
? &outData
: NULL
, key
, search
, record
, outAttrs
, outAttrsLength
);
206 // handle nothing-found case without exceptions
213 *hRecord
= record
->handle();
214 *hSearch
= search
->handle();
215 *hKey
= key
? key
->handle() : noKey
;
217 // return attributes (assumes relocated flat blob)
218 flips(outAttrs
, outAttributes
, outAttributesBase
);
219 *outAttributesLength
= outAttrsLength
;
221 // return data (temporary fix)
223 *data
= outData
.data();
224 *dataLength
= outData
.length();
230 kern_return_t
ucsp_server_findNext(UCSP_ARGS
, SearchHandle hSearch
,
231 COPY_IN(CssmDbRecordAttributeData
, inAttributes
),
232 COPY_OUT(CssmDbRecordAttributeData
, outAttributes
),
233 boolean_t getData
, DATA_OUT(data
), KeyHandle
*hKey
,
234 RecordHandle
*hRecord
)
237 relocate(inAttributes
, inAttributesBase
, inAttributesLength
);
238 RefPointer
<Database::Search
> search
=
239 Server::find
<Database::Search
>(hSearch
, CSSMERR_DL_INVALID_RESULTS_HANDLE
);
240 RefPointer
<Database::Record
> record
;
242 CssmData outData
; //OutputData outData(data, dataLength);
243 CssmDbRecordAttributeData
*outAttrs
; mach_msg_type_number_t outAttrsLength
;
244 search
->database().findNext(search
, inAttributes
, inAttributesLength
,
245 getData
? &outData
: NULL
, key
, record
, outAttrs
, outAttrsLength
);
247 // handle nothing-found case without exceptions
253 *hRecord
= record
->handle();
254 *hKey
= key
? key
->handle() : noKey
;
256 // return attributes (assumes relocated flat blob)
257 flips(outAttrs
, outAttributes
, outAttributesBase
);
258 *outAttributesLength
= outAttrsLength
;
260 // return data (temporary fix)
262 *data
= outData
.data();
263 *dataLength
= outData
.length();
269 kern_return_t
ucsp_server_findRecordHandle(UCSP_ARGS
, RecordHandle hRecord
,
270 COPY_IN(CssmDbRecordAttributeData
, inAttributes
),
271 COPY_OUT(CssmDbRecordAttributeData
, outAttributes
),
272 boolean_t getData
, DATA_OUT(data
), KeyHandle
*hKey
)
275 relocate(inAttributes
, inAttributesBase
, inAttributesLength
);
276 RefPointer
<Database::Record
> record
=
277 Server::find
<Database::Record
>(hRecord
, CSSMERR_DL_INVALID_RECORD_UID
);
279 CssmData outData
; //OutputData outData(data, dataLength);
280 CssmDbRecordAttributeData
*outAttrs
; mach_msg_type_number_t outAttrsLength
;
281 record
->database().findRecordHandle(record
, inAttributes
, inAttributesLength
,
282 getData
? &outData
: NULL
, key
, outAttrs
, outAttrsLength
);
285 *hKey
= key
? key
->handle() : noKey
;
287 // return attributes (assumes relocated flat blob)
288 flips(outAttrs
, outAttributes
, outAttributesBase
);
289 *outAttributesLength
= outAttrsLength
;
291 // return data (temporary fix)
293 *data
= outData
.data();
294 *dataLength
= outData
.length();
299 kern_return_t
ucsp_server_insertRecord(UCSP_ARGS
, DbHandle db
, CSSM_DB_RECORDTYPE recordType
,
300 COPY_IN(CssmDbRecordAttributeData
, attributes
), DATA_IN(data
), RecordHandle
*record
)
303 relocate(attributes
, attributesBase
, attributesLength
);
304 Server::database(db
)->insertRecord(recordType
, attributes
, attributesLength
,
305 DATA(data
), *record
);
309 kern_return_t
ucsp_server_modifyRecord(UCSP_ARGS
, DbHandle db
, RecordHandle
*hRecord
,
310 CSSM_DB_RECORDTYPE recordType
, COPY_IN(CssmDbRecordAttributeData
, attributes
),
311 boolean_t setData
, DATA_IN(data
), CSSM_DB_MODIFY_MODE modifyMode
)
314 relocate(attributes
, attributesBase
, attributesLength
);
315 CssmData
newData(DATA(data
));
316 RefPointer
<Database::Record
> record
=
317 Server::find
<Database::Record
>(*hRecord
, CSSMERR_DL_INVALID_RECORD_UID
);
318 Server::database(db
)->modifyRecord(recordType
, record
, attributes
, attributesLength
,
319 setData
? &newData
: NULL
, modifyMode
);
320 // note that the record handle presented to the client never changes here
321 // (we could, but have no reason to - our record handles are just always up to date)
325 kern_return_t
ucsp_server_deleteRecord(UCSP_ARGS
, DbHandle db
, RecordHandle hRecord
)
328 Server::database(db
)->deleteRecord(
329 Server::find
<Database::Record
>(hRecord
, CSSMERR_DL_INVALID_RECORD_UID
));
333 kern_return_t
ucsp_server_releaseSearch(UCSP_ARGS
, SearchHandle hSearch
)
336 RefPointer
<Database::Search
> search
= Server::find
<Database::Search
>(hSearch
, 0);
337 search
->database().releaseSearch(*search
);
341 kern_return_t
ucsp_server_releaseRecord(UCSP_ARGS
, RecordHandle hRecord
)
344 RefPointer
<Database::Record
> record
= Server::find
<Database::Record
>(hRecord
, 0);
345 record
->database().releaseRecord(*record
);
349 kern_return_t
ucsp_server_getRecordFromHandle(UCSP_ARGS
, RecordHandle record
,
350 COPY_IN(CssmDbRecordAttributeData
, inAttributes
),
351 COPY_OUT(CssmDbRecordAttributeData
, outAttributes
),
356 secdebug("dl", "getRecordFromHandle");
357 relocate(inAttributes
, inAttributesBase
, inAttributesLength
);
364 // Internal database management
366 kern_return_t
ucsp_server_createDb(UCSP_ARGS
, DbHandle
*db
,
367 COPY_IN(DLDbFlatIdentifier
, ident
),
368 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
372 relocate(cred
, credBase
, credLength
);
373 relocate(owner
, ownerBase
, ownerLength
);
374 relocate(ident
, identBase
, identLength
);
375 *db
= (new KeychainDatabase(*ident
, params
, connection
.process(), cred
, owner
))->handle();
379 // keychain synchronization
380 // @@@ caller should be required to call decodeDb() to get a DbHandle
381 // instead of passing the blob itself
382 kern_return_t
ucsp_server_cloneDbForSync(UCSP_ARGS
, DATA_IN(blob
),
383 DbHandle srcDb
, DATA_IN(agentData
), DbHandle
*newDb
)
386 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
387 *newDb
= (new KeychainDatabase(*srcKC
, connection
.process(),
388 SSBLOB(DbBlob
, blob
), DATA(agentData
)))->handle();
392 kern_return_t
ucsp_server_commitDbForSync(UCSP_ARGS
, DbHandle srcDb
,
393 DbHandle cloneDb
, DATA_OUT(blob
))
396 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(srcDb
);
397 RefPointer
<KeychainDatabase
> cloneKC
= Server::keychain(cloneDb
);
398 srcKC
->commitSecretsForSync(*cloneKC
);
400 // re-encode blob for convenience
401 if (blob
&& blobLength
) {
402 DbBlob
*dbBlob
= srcKC
->blob();
404 *blobLength
= dbBlob
->length();
406 secdebug("kcrecode", "No blob can be returned to client");
411 kern_return_t
ucsp_server_decodeDb(UCSP_ARGS
, DbHandle
*db
,
412 COPY_IN(DLDbFlatIdentifier
, ident
), COPY_IN(AccessCredentials
, cred
), DATA_IN(blob
))
415 relocate(cred
, credBase
, credLength
);
416 relocate(ident
, identBase
, identLength
);
417 *db
= (new KeychainDatabase(*ident
, SSBLOB(DbBlob
, blob
),
418 connection
.process(), cred
))->handle();
422 kern_return_t
ucsp_server_encodeDb(UCSP_ARGS
, DbHandle db
, DATA_OUT(blob
))
425 DbBlob
*dbBlob
= Server::keychain(db
)->blob(); // memory owned by database
427 *blobLength
= dbBlob
->length();
431 kern_return_t
ucsp_server_setDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters params
)
434 Server::keychain(db
)->setParameters(params
);
438 kern_return_t
ucsp_server_getDbParameters(UCSP_ARGS
, DbHandle db
, DBParameters
*params
)
441 Server::keychain(db
)->getParameters(*params
);
445 kern_return_t
ucsp_server_changePassphrase(UCSP_ARGS
, DbHandle db
,
446 COPY_IN(AccessCredentials
, cred
))
449 relocate(cred
, credBase
, credLength
);
450 Server::keychain(db
)->changePassphrase(cred
);
454 kern_return_t
ucsp_server_lockAll (UCSP_ARGS
, boolean_t
)
457 connection
.session().processLockAll();
461 kern_return_t
ucsp_server_unlockDb(UCSP_ARGS
, DbHandle db
)
464 Server::keychain(db
)->unlockDb();
468 kern_return_t
ucsp_server_unlockDbWithPassphrase(UCSP_ARGS
, DbHandle db
, DATA_IN(passphrase
))
471 Server::keychain(db
)->unlockDb(DATA(passphrase
));
475 kern_return_t
ucsp_server_isLocked(UCSP_ARGS
, DbHandle db
, boolean_t
*locked
)
478 *locked
= Server::database(db
)->isLocked();
486 kern_return_t
ucsp_server_encodeKey(UCSP_ARGS
, KeyHandle keyh
, DATA_OUT(blob
),
487 boolean_t wantUid
, DATA_OUT(uid
))
490 RefPointer
<Key
> gKey
= Server::key(keyh
);
491 if (KeychainKey
*key
= dynamic_cast<KeychainKey
*>(gKey
.get())) {
492 KeyBlob
*keyBlob
= key
->blob(); // still owned by key
494 *blobLength
= keyBlob
->length();
495 if (wantUid
) { // uid generation is not implemented
496 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
498 *uidLength
= 0; // do not return this
500 } else { // not a KeychainKey
501 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
506 kern_return_t
ucsp_server_decodeKey(UCSP_ARGS
, KeyHandle
*keyh
, CssmKey::Header
*header
,
507 DbHandle db
, DATA_IN(blob
))
510 RefPointer
<Key
> key
= new KeychainKey(*Server::keychain(db
), SSBLOB(KeyBlob
, blob
));
511 key
->returnKey(*keyh
, *header
);
516 // keychain synchronization
517 kern_return_t
ucsp_server_recodeKey(UCSP_ARGS
, DbHandle oldDb
, KeyHandle keyh
,
518 DbHandle newDb
, DATA_OUT(newBlob
))
521 // If the old key is passed in as DATA_IN(oldBlob):
522 // RefPointer<KeychainKey> key = new KeychainKey(*Server::keychain(oldDb), SSBLOB(KeyBlob, oldBlob));
523 RefPointer
<Key
> key
= Server::key(keyh
);
524 if (KeychainKey
*kckey
= dynamic_cast<KeychainKey
*>(key
.get())) {
525 KeyBlob
*blob
= Server::keychain(newDb
)->recodeKey(*kckey
);
527 *newBlobLength
= blob
->length();
528 Server::releaseWhenDone(*newBlob
);
529 // @@@ stop leaking blob
530 } else { // not a KeychainKey
531 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
536 kern_return_t
ucsp_server_releaseKey(UCSP_ARGS
, KeyHandle keyh
)
539 RefPointer
<Key
> key
= Server::key(keyh
);
540 key
->database().releaseKey(*key
);
544 kern_return_t
ucsp_server_queryKeySizeInBits(UCSP_ARGS
, KeyHandle keyh
, CSSM_KEY_SIZE
*length
)
547 RefPointer
<Key
> key
= Server::key(keyh
);
548 key
->database().queryKeySizeInBits(*key
, CssmKeySize::overlay(*length
));
552 kern_return_t
ucsp_server_getOutputSize(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
553 uint32 inputSize
, boolean_t encrypt
, uint32
*outputSize
)
556 relocate(context
, contextBase
, attributes
, attrSize
);
557 RefPointer
<Key
> key
= Server::key(keyh
);
558 key
->database().getOutputSize(context
, *key
, inputSize
, encrypt
, *outputSize
);
562 kern_return_t
ucsp_server_getKeyDigest(UCSP_ARGS
, KeyHandle key
, DATA_OUT(digest
))
565 CssmData digestData
= Server::key(key
)->canonicalDigest();
566 *digest
= digestData
.data();
567 *digestLength
= digestData
.length();
573 // Signatures and MACs
575 kern_return_t
ucsp_server_generateSignature(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
576 CSSM_ALGORITHMS signOnlyAlgorithm
, DATA_IN(data
), DATA_OUT(signature
))
579 relocate(context
, contextBase
, attributes
, attrSize
);
580 RefPointer
<Key
> key
= Server::key(keyh
);
581 OutputData
sigData(signature
, signatureLength
);
582 key
->database().generateSignature(context
, *key
, signOnlyAlgorithm
,
583 DATA(data
), sigData
);
587 kern_return_t
ucsp_server_verifySignature(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
588 CSSM_ALGORITHMS verifyOnlyAlgorithm
, DATA_IN(data
), DATA_IN(signature
))
591 relocate(context
, contextBase
, attributes
, attrSize
);
592 RefPointer
<Key
> key
= Server::key(keyh
);
593 key
->database().verifySignature(context
, *key
, verifyOnlyAlgorithm
,
594 DATA(data
), DATA(signature
));
598 kern_return_t
ucsp_server_generateMac(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
599 DATA_IN(data
), DATA_OUT(mac
))
602 relocate(context
, contextBase
, attributes
, attrSize
);
603 RefPointer
<Key
> key
= Server::key(keyh
);
604 OutputData
macData(mac
, macLength
);
605 key
->database().generateMac(context
, *key
, DATA(data
), macData
);
609 kern_return_t
ucsp_server_verifyMac(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
610 DATA_IN(data
), DATA_IN(mac
))
613 relocate(context
, contextBase
, attributes
, attrSize
);
614 RefPointer
<Key
> key
= Server::key(keyh
);
615 key
->database().verifyMac(context
, *key
, DATA(data
), DATA(mac
));
621 // Encryption/Decryption
623 kern_return_t
ucsp_server_encrypt(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
624 DATA_IN(clear
), DATA_OUT(cipher
))
627 relocate(context
, contextBase
, attributes
, attrSize
);
628 RefPointer
<Key
> key
= Server::key(keyh
);
629 OutputData
cipherOut(cipher
, cipherLength
);
630 key
->database().encrypt(context
, *key
, DATA(clear
), cipherOut
);
634 kern_return_t
ucsp_server_decrypt(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle keyh
,
635 DATA_IN(cipher
), DATA_OUT(clear
))
638 SecuritydDataSave
sds("/var/tmp/securityd_Context_decrypt"); // XXX/gh get sample Context for XDR testing
639 relocate(context
, contextBase
, attributes
, attrSize
);
640 // save attributes base addr for backwards compatibility
641 intptr_t attraddr
= reinterpret_cast<intptr_t>(&context
->ContextAttributes
);
642 sds
.writeContext(&context
, attraddr
, attrSize
);
643 RefPointer
<Key
> key
= Server::key(keyh
);
644 OutputData
clearOut(clear
, clearLength
);
645 key
->database().decrypt(context
, *key
, DATA(cipher
), clearOut
);
653 kern_return_t
ucsp_server_generateKey(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
,
654 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
655 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, CssmKey::Header
*newHeader
)
658 relocate(context
, contextBase
, attributes
, attrSize
);
659 relocate(cred
, credBase
, credLength
);
660 relocate(owner
, ownerBase
, ownerLength
);
661 //@@@ preliminary interpretation - will get "type handle"
662 RefPointer
<Database
> database
=
663 Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
);
665 database
->generateKey(context
, cred
, owner
, usage
, attrs
, key
);
666 key
->returnKey(*newKey
, *newHeader
);
671 kern_return_t
ucsp_server_generateKeyPair(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
,
672 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
673 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
674 KeyHandle
*pubKey
, CssmKey::Header
*pubHeader
, KeyHandle
*privKey
, CssmKey::Header
*privHeader
)
677 relocate(context
, contextBase
, attributes
, attrSize
);
678 relocate(cred
, credBase
, credLength
);
679 relocate(owner
, ownerBase
, ownerLength
);
680 RefPointer
<Database
> database
=
681 Server::optionalDatabase(db
, (privAttrs
| pubAttrs
) & CSSM_KEYATTR_PERMANENT
);
682 RefPointer
<Key
> pub
, priv
;
683 database
->generateKey(context
, cred
, owner
,
684 pubUsage
, pubAttrs
, privUsage
, privAttrs
, pub
, priv
);
685 pub
->returnKey(*pubKey
, *pubHeader
);
687 priv
->returnKey(*privKey
, *privHeader
);
694 // Key wrapping and unwrapping
696 kern_return_t
ucsp_server_wrapKey(UCSP_ARGS
, CONTEXT_ARGS
, KeyHandle hWrappingKey
,
697 COPY_IN(AccessCredentials
, cred
), KeyHandle hKeyToBeWrapped
,
698 DATA_IN(descriptiveData
), CssmKey
*wrappedKey
, DATA_OUT(keyData
))
701 relocate(context
, contextBase
, attributes
, attrSize
);
702 relocate(cred
, credBase
, credLength
);
703 RefPointer
<Key
> subjectKey
= Server::key(hKeyToBeWrapped
);
704 RefPointer
<Key
> wrappingKey
= Server::optionalKey(hWrappingKey
);
705 if ((context
.algorithm() == CSSM_ALGID_NONE
&& subjectKey
->attribute(CSSM_KEYATTR_SENSITIVE
))
706 || !subjectKey
->attribute(CSSM_KEYATTR_EXTRACTABLE
))
707 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
708 pickDb(subjectKey
, wrappingKey
)->wrapKey(context
, cred
, wrappingKey
, *subjectKey
, DATA(descriptiveData
), *wrappedKey
);
710 // transmit key data back as a separate blob
711 OutputData
keyDatas(keyData
, keyDataLength
);
712 keyDatas
= wrappedKey
->keyData();
717 kern_return_t
ucsp_server_unwrapKey(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
,
718 KeyHandle hWrappingKey
, COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
719 KeyHandle hPublicKey
, CssmKey wrappedKey
, DATA_IN(wrappedKeyData
),
720 CSSM_KEYUSE usage
, CSSM_KEYATTR_FLAGS attrs
, DATA_OUT(descriptiveData
),
721 KeyHandle
*newKey
, CssmKey::Header
*newHeader
)
724 relocate(context
, contextBase
, attributes
, attrSize
);
726 wrappedKey
.keyData() = DATA(wrappedKeyData
);
727 relocate(cred
, credBase
, credLength
);
728 relocate(owner
, ownerBase
, ownerLength
);
729 OutputData
descriptiveDatas(descriptiveData
, descriptiveDataLength
);
730 RefPointer
<Key
> wrappingKey
= Server::optionalKey(hWrappingKey
);
731 RefPointer
<Key
> unwrappedKey
;
732 pickDb(Server::optionalDatabase(db
), wrappingKey
)->unwrapKey(context
, cred
, owner
,
733 wrappingKey
, Server::optionalKey(hPublicKey
),
734 usage
, attrs
, wrappedKey
, unwrappedKey
, descriptiveDatas
);
735 unwrappedKey
->returnKey(*newKey
, *newHeader
);
744 // Note that the "param" argument can have structure. The walker for the
745 // (artificial) POD CssmDeriveData handles those that are known; if you add
746 // an algorithm with structured param, you need to add a case there.
748 kern_return_t
ucsp_server_deriveKey(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
, KeyHandle hKey
,
749 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
750 COPY_IN(CssmDeriveData
, paramInput
), DATA_OUT(paramOutput
),
751 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, CssmKey::Header
*newHeader
)
754 relocate(context
, contextBase
, attributes
, attrSize
);
755 relocate(cred
, credBase
, credLength
);
756 relocate(owner
, ownerBase
, ownerLength
);
757 relocate(paramInput
, paramInputBase
, paramInputLength
);
758 if (!paramInput
|| paramInput
->algorithm
!= context
.algorithm())
759 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
); // client layer fault
761 RefPointer
<Database
> database
=
762 Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
);
763 RefPointer
<Key
> key
= Server::optionalKey(hKey
);
764 CssmData
*param
= paramInput
? ¶mInput
->baseData
: NULL
;
765 RefPointer
<Key
> derivedKey
;
766 pickDb(Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
),
767 key
)->deriveKey(context
, key
, cred
, owner
, param
, usage
, attrs
, derivedKey
);
768 derivedKey
->returnKey(*newKey
, *newHeader
);
770 if (param
&& param
->length()) {
771 if (!param
->data()) // CSP screwed up
772 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
773 if (paramInputLength
) // using incoming buffer; make a copy
774 *param
= CssmAutoData(Server::csp().allocator(), *param
).release();
775 OutputData(paramOutput
, paramOutputLength
) = *param
; // return the data
784 kern_return_t
ucsp_server_generateRandom(UCSP_ARGS
, uint32 ssid
, CONTEXT_ARGS
, DATA_OUT(data
))
787 relocate(context
, contextBase
, attributes
, attrSize
);
789 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
791 // default version (use /dev/random)
792 Allocator
&allocator
= Allocator::standard(Allocator::sensitive
);
793 if (size_t bytes
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
)) {
794 void *buffer
= allocator
.malloc(bytes
);
795 Server::active().random(buffer
, bytes
);
798 Server::releaseWhenDone(allocator
, buffer
);
806 // Watch out for the memory-management tap-dance.
808 kern_return_t
ucsp_server_getOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
809 COPY_OUT(AclOwnerPrototype
, ownerOut
))
812 AclOwnerPrototype owner
;
813 Server::aclBearer(kind
, key
).getOwner(owner
); // allocates memory in owner
814 Copier
<AclOwnerPrototype
> owners(&owner
, Allocator::standard()); // make flat copy
815 { ChunkFreeWalker free
; walk(free
, owner
); } // release chunked original
816 *ownerOutLength
= owners
.length();
817 flips(owners
.value(), ownerOut
, ownerOutBase
);
818 Server::releaseWhenDone(owners
.keep()); // throw flat copy out when done
822 kern_return_t
ucsp_server_setOwner(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
823 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclOwnerPrototype
, owner
))
826 relocate(cred
, credBase
, credLength
);
827 relocate(owner
, ownerBase
, ownerLength
);
828 Server::aclBearer(kind
, key
).changeOwner(*owner
, cred
);
832 kern_return_t
ucsp_server_getAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
833 boolean_t haveTag
, const char *tag
,
834 uint32
*countp
, COPY_OUT(AclEntryInfo
, acls
))
838 AclEntryInfo
*aclList
;
839 Server::aclBearer(kind
, key
).getAcl(haveTag
? tag
: NULL
, count
, aclList
);
841 Copier
<AclEntryInfo
> aclsOut(aclList
, count
); // make flat copy
843 { // release the chunked memory originals
844 ChunkFreeWalker free
;
845 for (uint32 n
= 0; n
< count
; n
++)
846 walk(free
, aclList
[n
]);
848 // release the memory allocated for the list itself when we are done
849 Allocator::standard().free (aclList
);
852 // set result (note: this is *almost* flips(), but on an array)
853 *aclsLength
= aclsOut
.length();
854 *acls
= *aclsBase
= aclsOut
;
857 for (uint32 n
= 0; n
< count
; n
++)
860 Flippers::flip(*aclsBase
);
862 SecuritydDataSave
sds("/var/tmp/AclEntryInfo_getAcl");
863 sds
.writeAclEntryInfo(*acls
, *aclsLength
);
864 Server::releaseWhenDone(aclsOut
.keep());
868 kern_return_t
ucsp_server_changeAcl(UCSP_ARGS
, AclKind kind
, KeyHandle key
,
869 COPY_IN(AccessCredentials
, cred
), CSSM_ACL_EDIT_MODE mode
, CSSM_ACL_HANDLE handle
,
870 COPY_IN(AclEntryInput
, acl
))
873 relocate(cred
, credBase
, credLength
);
874 relocate(acl
, aclBase
, aclLength
);
875 SecuritydDataSave
sds("/var/tmp/AclEntryInput_changeAcl");
876 sds
.writeAclEntryInput(acl
, aclLength
);
877 Server::aclBearer(kind
, key
).changeAcl(AclEdit(mode
, handle
, acl
), cred
);
885 kern_return_t
ucsp_server_login(UCSP_ARGS
, COPY_IN(AccessCredentials
, cred
), DATA_IN(name
))
888 relocate(cred
, credBase
, credLength
);
889 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
893 kern_return_t
ucsp_server_logout(UCSP_ARGS
)
896 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
902 // Miscellaneous CSP-related calls
904 kern_return_t
ucsp_server_getStatistics(UCSP_ARGS
, uint32 ssid
, CSPOperationalStatistics
*statistics
)
907 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
911 kern_return_t
ucsp_server_getTime(UCSP_ARGS
, uint32 ssid
, CSSM_ALGORITHMS algorithm
, DATA_OUT(data
))
914 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
918 kern_return_t
ucsp_server_getCounter(UCSP_ARGS
, uint32 ssid
, DATA_OUT(data
))
921 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
925 kern_return_t
ucsp_server_selfVerify(UCSP_ARGS
, uint32 ssid
)
928 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
934 // Passthrough calls (separate for CSP and DL passthroughs)
936 kern_return_t
ucsp_server_cspPassThrough(UCSP_ARGS
, uint32 ssid
, uint32 id
, CONTEXT_ARGS
,
937 KeyHandle hKey
, DATA_IN(inData
), DATA_OUT(outData
))
940 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
944 kern_return_t
ucsp_server_dlPassThrough(UCSP_ARGS
, uint32 ssid
, uint32 id
,
945 DATA_IN(inData
), DATA_OUT(outData
))
948 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
954 // Database key management.
955 // ExtractMasterKey looks vaguely like a key derivation operation, and is in fact
956 // presented by the CSPDL's CSSM layer as such.
958 kern_return_t
ucsp_server_extractMasterKey(UCSP_ARGS
, DbHandle db
, CONTEXT_ARGS
, DbHandle sourceDb
,
959 COPY_IN(AccessCredentials
, cred
), COPY_IN(AclEntryPrototype
, owner
),
960 uint32 usage
, uint32 attrs
, KeyHandle
*newKey
, CssmKey::Header
*newHeader
)
963 context
.postIPC(contextBase
, attributes
);
964 relocate(cred
, credBase
, credLength
);
965 relocate(owner
, ownerBase
, ownerLength
);
966 RefPointer
<KeychainDatabase
> keychain
= Server::keychain(sourceDb
);
967 RefPointer
<Key
> masterKey
= keychain
->extractMasterKey(
968 *Server::optionalDatabase(db
, attrs
& CSSM_KEYATTR_PERMANENT
),
969 cred
, owner
, usage
, attrs
);
970 masterKey
->returnKey(*newKey
, *newHeader
);
977 // Authorization subsystem support
979 kern_return_t
ucsp_server_authorizationCreate(UCSP_ARGS
,
980 COPY_IN(AuthorizationItemSet
, inRights
),
982 COPY_IN(AuthorizationItemSet
, inEnvironment
),
983 AuthorizationBlob
*authorization
)
986 relocate(inRights
, inRightsBase
, inRightsLength
);
987 relocate(inEnvironment
, inEnvironmentBase
, inEnvironmentLength
);
988 Authorization::AuthItemSet
rights(inRights
), environment(inEnvironment
);
990 *rcode
= connection
.process().session().authCreate(rights
, environment
,
991 flags
, *authorization
, auditToken
);
995 kern_return_t
ucsp_server_authorizationRelease(UCSP_ARGS
,
996 AuthorizationBlob authorization
, uint32 flags
)
999 connection
.process().session().authFree(authorization
, flags
);
1003 kern_return_t
ucsp_server_authorizationCopyRights(UCSP_ARGS
,
1004 AuthorizationBlob authorization
,
1005 COPY_IN(AuthorizationItemSet
, inRights
),
1007 COPY_IN(AuthorizationItemSet
, inEnvironment
),
1008 COPY_OUT(AuthorizationItemSet
, result
))
1011 relocate(inRights
, inRightsBase
, inRightsLength
);
1012 relocate(inEnvironment
, inEnvironmentBase
, inEnvironmentLength
);
1013 Authorization::AuthItemSet
rights(inRights
), environment(inEnvironment
), grantedRights
;
1014 *rcode
= connection
.process().session().authGetRights(authorization
,
1015 rights
, environment
, flags
, grantedRights
);
1016 if (result
&& resultLength
)
1019 grantedRights
.copy(*result
, resultSize
);
1020 *resultLength
= resultSize
;
1021 *resultBase
= *result
;
1022 flips(*result
, result
, resultBase
);
1023 Server::releaseWhenDone(*result
);
1028 kern_return_t
ucsp_server_authorizationCopyInfo(UCSP_ARGS
,
1029 AuthorizationBlob authorization
,
1030 AuthorizationString tag
,
1031 COPY_OUT(AuthorizationItemSet
, info
))
1034 Authorization::AuthItemSet infoSet
;
1035 *info
= *infoBase
= NULL
;
1037 *rcode
= connection
.process().session().authGetInfo(authorization
,
1038 tag
[0] ? tag
: NULL
, infoSet
);
1039 if (*rcode
== noErr
) {
1041 infoSet
.copy(*info
, infoSize
);
1042 *infoLength
= infoSize
;
1044 flips(*info
, info
, infoBase
);
1045 Server::releaseWhenDone(*info
);
1050 kern_return_t
ucsp_server_authorizationExternalize(UCSP_ARGS
,
1051 AuthorizationBlob authorization
, AuthorizationExternalForm
*extForm
)
1054 *rcode
= connection
.process().session().authExternalize(authorization
, *extForm
);
1058 kern_return_t
ucsp_server_authorizationInternalize(UCSP_ARGS
,
1059 AuthorizationExternalForm extForm
, AuthorizationBlob
*authorization
)
1062 *rcode
= connection
.process().session().authInternalize(extForm
, *authorization
);
1068 // Session management subsystem
1070 kern_return_t
ucsp_server_getSessionInfo(UCSP_ARGS
,
1071 SecuritySessionId
*sessionId
, SessionAttributeBits
*attrs
)
1074 Session
&session
= Session::find(*sessionId
);
1075 *sessionId
= session
.handle();
1076 *attrs
= session
.attributes();
1080 kern_return_t
ucsp_server_setupSession(UCSP_ARGS
,
1081 SessionCreationFlags flags
, SessionAttributeBits attrs
)
1084 Server::process().session().setupAttributes(flags
, attrs
);
1088 kern_return_t
ucsp_server_setSessionDistinguishedUid(UCSP_ARGS
,
1089 SecuritySessionId sessionId
, uid_t user
)
1092 Session::find
<DynamicSession
>(sessionId
).originatorUid(user
);
1096 kern_return_t
ucsp_server_getSessionDistinguishedUid(UCSP_ARGS
,
1097 SecuritySessionId sessionId
, uid_t
*user
)
1100 *user
= Session::find(sessionId
).originatorUid();
1104 kern_return_t
ucsp_server_setSessionUserPrefs(UCSP_ARGS
, SecuritySessionId sessionId
, DATA_IN(userPrefs
))
1107 CFRef
<CFDataRef
> data(CFDataCreate(NULL
, (UInt8
*)userPrefs
, userPrefsLength
));
1111 *rcode
= errSessionValueNotSet
;
1115 Session::find
<DynamicSession
>(sessionId
).setUserPrefs(data
);
1124 // Notification core subsystem
1126 kern_return_t
ucsp_server_requestNotification(UCSP_ARGS
, mach_port_t receiver
, uint32 domain
, uint32 events
)
1129 connection
.process().requestNotifications(receiver
, domain
, events
);
1133 kern_return_t
ucsp_server_stopNotification(UCSP_ARGS
, mach_port_t receiver
)
1136 connection
.process().stopNotifications(receiver
);
1140 kern_return_t
ucsp_server_postNotification(mach_port_t serverPort
, uint32 domain
, uint32 event
, DATA_IN(data
))
1143 Listener::notify(domain
, event
, DATA(data
));
1149 // AuthorizationDB modification
1151 kern_return_t
ucsp_server_authorizationdbGet(UCSP_ARGS
, const char *rightname
, DATA_OUT(rightDefinition
))
1154 CFDictionaryRef rightDict
;
1156 *rcode
= connection
.process().session().authorizationdbGet(rightname
, &rightDict
);
1158 if (!*rcode
&& rightDict
)
1160 CFRef
<CFDataRef
> data(CFPropertyListCreateXMLData (NULL
, rightDict
));
1161 CFRelease(rightDict
);
1163 return errAuthorizationInternal
;
1165 // @@@ copy data to avoid having to do a delayed cfrelease
1166 mach_msg_type_number_t length
= CFDataGetLength(data
);
1167 void *xmlData
= Allocator::standard().malloc(length
);
1168 memcpy(xmlData
, CFDataGetBytePtr(data
), length
);
1169 Server::releaseWhenDone(xmlData
);
1171 *rightDefinition
= xmlData
;
1172 *rightDefinitionLength
= length
;
1177 kern_return_t
ucsp_server_authorizationdbSet(UCSP_ARGS
, AuthorizationBlob authorization
, const char *rightname
, DATA_IN(rightDefinition
))
1180 CFRef
<CFDataRef
> data(CFDataCreate(NULL
, (UInt8
*)rightDefinition
, rightDefinitionLength
));
1183 return errAuthorizationInternal
;
1185 CFRef
<CFDictionaryRef
> rightDefinition(static_cast<CFDictionaryRef
>(CFPropertyListCreateFromXMLData(NULL
, data
, kCFPropertyListImmutable
, NULL
)));
1187 if (!rightDefinition
|| (CFGetTypeID(rightDefinition
) != CFDictionaryGetTypeID()))
1188 return errAuthorizationInternal
;
1190 *rcode
= connection
.process().session().authorizationdbSet(authorization
, rightname
, rightDefinition
);
1195 kern_return_t
ucsp_server_authorizationdbRemove(UCSP_ARGS
, AuthorizationBlob authorization
, const char *rightname
)
1198 *rcode
= connection
.process().session().authorizationdbRemove(authorization
, rightname
);
1204 // Miscellaneous administrative functions
1206 kern_return_t
ucsp_server_addCodeEquivalence(UCSP_ARGS
, DATA_IN(oldHash
), DATA_IN(newHash
),
1207 const char *name
, boolean_t forSystem
)
1210 Server::codeSignatures().addLink(DATA(oldHash
), DATA(newHash
), name
, forSystem
);
1214 kern_return_t
ucsp_server_removeCodeEquivalence(UCSP_ARGS
, DATA_IN(hash
),
1215 const char *name
, boolean_t forSystem
)
1218 Server::codeSignatures().removeLink(DATA(hash
), name
, forSystem
);
1222 kern_return_t
ucsp_server_setAlternateSystemRoot(UCSP_ARGS
, const char *root
)
1226 if (connection
.process().uid() != 0)
1227 CssmError::throwMe(CSSM_ERRCODE_OS_ACCESS_DENIED
);
1229 Server::codeSignatures().open((string(root
) + EQUIVALENCEDBPATH
).c_str());
1235 // Child check-in service.
1236 // Note that this isn't using the standard argument pattern.
1238 kern_return_t
ucsp_server_childCheckIn(mach_port_t serverPort
,
1239 mach_port_t servicePort
, mach_port_t taskPort
)
1242 ServerChild::checkIn(servicePort
, TaskPort(taskPort
).pid());
1243 END_IPCS(mach_port_deallocate(mach_task_self(), taskPort
))