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
);
180 CSSM_KEY_SIZE
Connection::queryKeySize(Key
&key
)
182 CssmClient::Key
theKey(Server::csp(), key
);
183 return theKey
.sizeInBits();
188 // Signatures and MACs
190 void Connection::generateSignature(const Context
&context
, Key
&key
,
191 CSSM_ALGORITHMS signOnlyAlgorithm
, const CssmData
&data
, CssmData
&signature
)
193 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
194 key
.validate(CSSM_ACL_AUTHORIZATION_SIGN
, context
);
195 CssmClient::Sign
signer(Server::csp(), context
.algorithm(), signOnlyAlgorithm
);
196 signer
.override(context
);
197 signer
.sign(data
, signature
);
200 void Connection::verifySignature(const Context
&context
, Key
&key
,
201 CSSM_ALGORITHMS verifyOnlyAlgorithm
, const CssmData
&data
, const CssmData
&signature
)
203 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
204 CssmClient::Verify
verifier(Server::csp(), context
.algorithm(), verifyOnlyAlgorithm
);
205 verifier
.override(context
);
206 verifier
.verify(data
, signature
);
209 void Connection::generateMac(const Context
&context
, Key
&key
,
210 const CssmData
&data
, CssmData
&mac
)
212 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
213 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
214 CssmClient::GenerateMac
signer(Server::csp(), context
.algorithm());
215 signer
.override(context
);
216 signer
.sign(data
, mac
);
219 void Connection::verifyMac(const Context
&context
, Key
&key
,
220 const CssmData
&data
, const CssmData
&mac
)
222 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
223 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
224 CssmClient::VerifyMac
verifier(Server::csp(), context
.algorithm());
225 verifier
.override(context
);
226 verifier
.verify(data
, mac
);
231 // Encryption/decryption
233 void Connection::encrypt(const Context
&context
, Key
&key
,
234 const CssmData
&clear
, CssmData
&cipher
)
236 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
237 key
.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
);
238 CssmClient::Encrypt
cryptor(Server::csp(), context
.algorithm());
239 cryptor
.override(context
);
241 size_t totalLength
= cryptor
.encrypt(clear
, cipher
, remData
);
242 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
244 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
245 cipher
.length(totalLength
);
248 void Connection::decrypt(const Context
&context
, Key
&key
,
249 const CssmData
&cipher
, CssmData
&clear
)
251 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
252 key
.validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
);
253 CssmClient::Decrypt
cryptor(Server::csp(), context
.algorithm());
254 cryptor
.override(context
);
256 size_t totalLength
= cryptor
.decrypt(cipher
, clear
, remData
);
257 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
259 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
260 clear
.length(totalLength
);
265 // Key generation and derivation.
266 // Currently, we consider symmetric key generation to be fast, but
267 // asymmetric key generation to be (potentially) slow.
269 void Connection::generateKey(Database
*db
, const Context
&context
,
270 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
271 uint32 usage
, uint32 attrs
, Key
* &newKey
)
274 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
275 generate
.override(context
);
278 // @@@ turn "none" return into reference if permanent (only)
280 generate(key
, Key::KeySpec(usage
, attrs
));
282 // register and return the generated key
283 newKey
= new Key(db
, key
, attrs
& Key::managedAttributes
, owner
);
286 void Connection::generateKey(Database
*db
, const Context
&context
,
287 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
288 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
289 Key
* &publicKey
, Key
* &privateKey
)
292 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
293 generate
.override(context
);
295 // this may take a while; let our server object know
296 Server::active().longTermActivity();
299 // @@@ turn "none" return into reference if permanent (only)
300 CssmKey pubKey
, privKey
;
301 generate(pubKey
, Key::KeySpec(pubUsage
, pubAttrs
),
302 privKey
, Key::KeySpec(privUsage
, privAttrs
));
304 // register and return the generated keys
305 publicKey
= new Key(db
, pubKey
, pubAttrs
& Key::managedAttributes
, owner
);
306 privateKey
= new Key(db
, privKey
, privAttrs
& Key::managedAttributes
, owner
);
309 Key
&Connection::deriveKey(Database
*db
, const Context
&context
, Key
*baseKey
,
310 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
311 CssmData
*param
, uint32 usage
, uint32 attrs
)
313 // prepare a key-derivation context
315 baseKey
->validate(CSSM_ACL_AUTHORIZATION_DERIVE
, cred
);
316 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)*baseKey
);
318 CssmClient::DeriveKey
derive(Server::csp(), context
.algorithm(), CSSM_ALGID_NONE
);
319 derive
.override(context
);
322 // @@@ turn "none" return into reference if permanent (only)
324 derive(param
, Key::KeySpec(usage
, attrs
), key
);
326 // register and return the generated key
327 return *new Key(db
, key
, attrs
& Key::managedAttributes
, owner
);
332 // Key wrapping and unwrapping.
333 // Note that the key argument (the key in the context) is optional because of the special
334 // case of "cleartext" (null algorithm) wrapping for import/export.
336 void Connection::wrapKey(const Context
&context
, Key
*key
,
337 Key
&keyToBeWrapped
, const AccessCredentials
*cred
,
338 const CssmData
&descriptiveData
, CssmKey
&wrappedKey
)
340 keyToBeWrapped
.validate(context
.algorithm() == CSSM_ALGID_NONE
?
341 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR
: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
,
344 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)*key
);
345 CssmClient::WrapKey
wrap(Server::csp(), context
.algorithm());
346 wrap
.override(context
);
347 wrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
348 wrap(keyToBeWrapped
, wrappedKey
, &descriptiveData
);
351 Key
&Connection::unwrapKey(Database
*db
, const Context
&context
, Key
*key
,
352 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
353 uint32 usage
, uint32 attrs
, const CssmKey wrappedKey
,
354 Key
*publicKey
, CssmData
*descriptiveData
)
357 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)*key
);
358 CssmClient::UnwrapKey
unwrap(Server::csp(), context
.algorithm());
359 unwrap
.override(context
);
360 CssmKey unwrappedKey
;
361 unwrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
363 AclEntryInput
ownerInput(*owner
); //@@@ const trouble - fix in client/pod
364 unwrap
.aclEntry(ownerInput
);
367 // @@@ Invoking conversion operator to CssmKey & on *publicKey and take the address of the result.
368 unwrap(wrappedKey
, Key::KeySpec(usage
, attrs
), unwrappedKey
,
369 descriptiveData
, publicKey
? &static_cast<CssmKey
&>(*publicKey
) : NULL
);
371 return *new Key(db
, unwrappedKey
, attrs
& Key::managedAttributes
, owner
);
376 // Miscellaneous CSSM functions
378 uint32
Connection::getOutputSize(const Context
&context
, Key
&key
, uint32 inputSize
, bool encrypt
)
380 // We're fudging here somewhat, since the context can be any type.
381 // ctx.override will fix the type, and no-one's the wiser.
382 context
.replace(CSSM_ATTRIBUTE_KEY
, (CSSM_KEY
&)key
);
383 CssmClient::Digest
ctx(Server::csp(), context
.algorithm());
384 ctx
.override(context
);
385 return ctx
.getOutputSize(inputSize
, encrypt
);