2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // connection - manage connections to clients.
22 // Note that Connection objects are single-threaded; only one request can be outstanding
23 // per connection. The various operational calls (e.g. generateMac) can be called by
24 // multiple threads, but each call will be for a different connection (the one the request
25 // came in on). Thus, locking happens elsewhere as needed.
27 #include "connection.h"
31 #include <Security/keyclient.h>
32 #include <Security/genkey.h>
33 #include <Security/wrapkey.h>
34 #include <Security/signclient.h>
35 #include <Security/macclient.h>
36 #include <Security/cryptoclient.h>
40 // Construct a Connection object.
42 Connection::Connection(Process
&proc
, Port rPort
)
43 : process(proc
), mClientPort(rPort
), state(idle
), agentWait(NULL
),
44 aclUpdateTrigger(NULL
)
46 // bump the send-rights count on the reply port so we keep the right after replying
47 mClientPort
.modRefs(MACH_PORT_RIGHT_SEND
, +1);
49 debug("SS", "New connection %p for process %d clientport=%d",
50 this, process
.pid(), int(rPort
));
55 // When a Connection's destructor executes, the connection must already have been
56 // terminated. All we have to do here is clean up a bit.
58 Connection::~Connection()
60 debug("SS", "Connection %p destroyed", this);
66 // Terminate a Connection normally.
67 // This is assumed to be properly sequenced, so no thread races are possible.
69 void Connection::terminate()
71 // cleanly discard port rights
72 assert(state
== idle
);
73 mClientPort
.modRefs(MACH_PORT_RIGHT_SEND
, -1); // discard surplus send right
74 assert(mClientPort
.getRefs(MACH_PORT_RIGHT_SEND
) == 1); // one left for final reply
75 debug("SS", "Connection %p terminated", this);
80 // Abort a Connection.
81 // This may be called from thread A while thread B is working a request for the Connection,
82 // so we must be careful.
84 bool Connection::abort(bool keepReplyPort
)
86 StLock
<Mutex
> _(lock
);
88 mClientPort
.destroy(); // dead as a doornail already
91 debug("SS", "Connection %p aborted", this);
92 return true; // just shoot me
94 state
= dying
; // shoot me soon, please
97 debug("SS", "Connection %p abort deferred (busy)", this);
98 return false; // but not quite yet
100 assert(false); // impossible (we hope)
106 // Service request framing.
107 // These are here so "hanging" connection service threads don't fall
108 // into the Big Bad Void as Connections and processes drop out from
111 void Connection::beginWork()
116 process
.beginConnection(*this);
119 debug("SS", "Attempt to re-enter connection %p(port %d)", this, mClientPort
.port());
120 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ some state-error code instead?
126 void Connection::checkWork()
128 StLock
<Mutex
> _(lock
);
133 agentWait
= NULL
; // obviously we're not waiting on this
140 bool Connection::endWork()
144 // process the n-step aclUpdateTrigger
145 if (aclUpdateTrigger
) {
146 if (--aclUpdateTriggerCount
== 0) {
147 aclUpdateTrigger
= NULL
;
148 debug("kcacl", "acl update trigger expires");
150 debug("kcacl", "acl update trigger armed for %d calls",
151 aclUpdateTriggerCount
);
155 process
.endConnection(*this);
158 debug("SS", "Connection %p abort resuming", this);
159 if (process
.endConnection(*this))
169 // Key creation and release
171 void Connection::releaseKey(Key::Handle key
)
173 delete &Server::key(key
);
178 // Signatures and MACs
180 void Connection::generateSignature(const Context
&context
, Key
&key
,
181 const CssmData
&data
, CssmData
&signature
)
183 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
184 key
.validate(CSSM_ACL_AUTHORIZATION_SIGN
, context
);
185 CssmClient::Sign
signer(Server::csp(), context
.algorithm());
186 signer
.override(context
);
187 signer
.sign(data
, signature
);
190 void Connection::verifySignature(const Context
&context
, Key
&key
,
191 const CssmData
&data
, const CssmData
&signature
)
193 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
194 CssmClient::Verify
verifier(Server::csp(), context
.algorithm());
195 verifier
.override(context
);
196 verifier
.verify(data
, signature
);
199 void Connection::generateMac(const Context
&context
, Key
&key
,
200 const CssmData
&data
, CssmData
&mac
)
202 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
203 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
204 CssmClient::GenerateMac
signer(Server::csp(), context
.algorithm());
205 signer
.override(context
);
206 signer
.sign(data
, mac
);
209 void Connection::verifyMac(const Context
&context
, Key
&key
,
210 const CssmData
&data
, const CssmData
&mac
)
212 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
213 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
214 CssmClient::VerifyMac
verifier(Server::csp(), context
.algorithm());
215 verifier
.override(context
);
216 verifier
.verify(data
, mac
);
221 // Encryption/decryption
223 void Connection::encrypt(const Context
&context
, Key
&key
,
224 const CssmData
&clear
, CssmData
&cipher
)
226 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
227 key
.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
);
228 CssmClient::Encrypt
cryptor(Server::csp(), context
.algorithm());
229 cryptor
.override(context
);
231 size_t totalLength
= cryptor
.encrypt(clear
, cipher
, remData
);
232 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
234 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
235 cipher
.length(totalLength
);
238 void Connection::decrypt(const Context
&context
, Key
&key
,
239 const CssmData
&cipher
, CssmData
&clear
)
241 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
242 key
.validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
);
243 CssmClient::Decrypt
cryptor(Server::csp(), context
.algorithm());
244 cryptor
.override(context
);
246 size_t totalLength
= cryptor
.decrypt(cipher
, clear
, remData
);
247 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
249 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
250 clear
.length(totalLength
);
256 // Currently, we consider symmetric key generation to be fast, but
257 // asymmetric key generation to be (potentially) slow.
259 void Connection::generateKey(Database
*db
, const Context
&context
,
260 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
261 uint32 usage
, uint32 attrs
, Key
* &newKey
)
264 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
265 generate
.override(context
);
268 // @@@ turn "none" return into reference if permanent (only)
270 generate(key
, CssmClient::KeySpec(usage
, attrs
& ~Key::managedAttributes
));
272 // register and return the generated key
273 newKey
= new Key(db
, key
, attrs
& Key::managedAttributes
, owner
);
276 void Connection::generateKey(Database
*db
, const Context
&context
,
277 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
278 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
279 Key
* &publicKey
, Key
* &privateKey
)
282 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
283 generate
.override(context
);
285 // this may take a while; let our server object know
286 Server::active().longTermActivity();
289 // @@@ turn "none" return into reference if permanent (only)
290 CssmKey pubKey
, privKey
;
291 generate(pubKey
, CssmClient::KeySpec(pubUsage
, pubAttrs
& ~Key::managedAttributes
),
292 privKey
, CssmClient::KeySpec(privUsage
, privAttrs
& ~Key::managedAttributes
));
294 // register and return the generated keys
295 publicKey
= new Key(db
, pubKey
, pubAttrs
& Key::managedAttributes
, owner
);
296 privateKey
= new Key(db
, privKey
, privAttrs
& Key::managedAttributes
, owner
);
301 // Key wrapping and unwrapping.
302 // Note that the key argument (the key in the context) is optional because of the special
303 // case of "cleartext" (null algorithm) wrapping for import/export.
305 void Connection::wrapKey(const Context
&context
, Key
*key
,
306 Key
&keyToBeWrapped
, const AccessCredentials
*cred
,
307 const CssmData
&descriptiveData
, CssmKey
&wrappedKey
)
309 keyToBeWrapped
.validate(context
.algorithm() == CSSM_ALGID_NONE
?
310 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR
: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
,
313 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)*key
);
314 CssmClient::WrapKey
wrap(Server::csp(), context
.algorithm());
315 wrap
.override(context
);
316 wrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
317 wrap(keyToBeWrapped
, wrappedKey
, &descriptiveData
);
320 Key
&Connection::unwrapKey(Database
*db
, const Context
&context
, Key
*key
,
321 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
322 uint32 usage
, uint32 attrs
, const CssmKey wrappedKey
,
323 Key
*publicKey
, CssmData
*descriptiveData
)
326 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)*key
);
327 CssmClient::UnwrapKey
unwrap(Server::csp(), context
.algorithm());
328 unwrap
.override(context
);
329 CssmKey unwrappedKey
;
330 unwrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
332 AclEntryInput
ownerInput(*owner
); //@@@ const trouble - fix in client/pod
333 unwrap
.aclEntry(ownerInput
);
336 // @@@ Invoking conversion operator to CssmKey & on *publicKey and take the address of the result.
337 unwrap(wrappedKey
, CssmClient::KeySpec(usage
, attrs
), unwrappedKey
,
338 descriptiveData
, publicKey
? &static_cast<CssmKey
&>(*publicKey
) : NULL
);
340 return *new Key(db
, unwrappedKey
, attrs
& Key::managedAttributes
, owner
);