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 secdebug("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 secdebug("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 secdebug("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 secdebug("SS", "Connection %p aborted", this);
92 return true; // just shoot me
94 state
= dying
; // shoot me soon, please
97 secdebug("SS", "Connection %p abort deferred (busy)", this);
98 return false; // but not quite yet
100 assert(false); // impossible (we hope)
101 return true; // placebo
107 // Service request framing.
108 // These are here so "hanging" connection service threads don't fall
109 // into the Big Bad Void as Connections and processes drop out from
112 void Connection::beginWork()
117 process
.beginConnection(*this);
120 secdebug("SS", "Attempt to re-enter connection %p(port %d)", this, mClientPort
.port());
121 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); //@@@ some state-error code instead?
127 void Connection::checkWork()
129 StLock
<Mutex
> _(lock
);
134 agentWait
= NULL
; // obviously we're not waiting on this
141 bool Connection::endWork()
145 // process the n-step aclUpdateTrigger
146 if (aclUpdateTrigger
) {
147 if (--aclUpdateTriggerCount
== 0) {
148 aclUpdateTrigger
= NULL
;
149 secdebug("kcacl", "acl update trigger expires");
151 secdebug("kcacl", "acl update trigger armed for %d calls",
152 aclUpdateTriggerCount
);
156 process
.endConnection(*this);
159 secdebug("SS", "Connection %p abort resuming", this);
160 if (process
.endConnection(*this))
165 return true; // placebo
171 // Key creation and release
173 void Connection::releaseKey(Key::Handle key
)
175 delete &Server::key(key
);
182 CSSM_KEY_SIZE
Connection::queryKeySize(Key
&key
)
184 CssmClient::Key
theKey(Server::csp(), key
);
185 return theKey
.sizeInBits();
190 // Signatures and MACs
192 void Connection::generateSignature(const Context
&context
, Key
&key
,
193 CSSM_ALGORITHMS signOnlyAlgorithm
, const CssmData
&data
, CssmData
&signature
)
195 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
196 key
.validate(CSSM_ACL_AUTHORIZATION_SIGN
, context
);
197 CssmClient::Sign
signer(Server::csp(), context
.algorithm(), signOnlyAlgorithm
);
198 signer
.override(context
);
199 signer
.sign(data
, signature
);
202 void Connection::verifySignature(const Context
&context
, Key
&key
,
203 CSSM_ALGORITHMS verifyOnlyAlgorithm
, const CssmData
&data
, const CssmData
&signature
)
205 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
206 CssmClient::Verify
verifier(Server::csp(), context
.algorithm(), verifyOnlyAlgorithm
);
207 verifier
.override(context
);
208 verifier
.verify(data
, signature
);
211 void Connection::generateMac(const Context
&context
, Key
&key
,
212 const CssmData
&data
, CssmData
&mac
)
214 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
215 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
216 CssmClient::GenerateMac
signer(Server::csp(), context
.algorithm());
217 signer
.override(context
);
218 signer
.sign(data
, mac
);
221 void Connection::verifyMac(const Context
&context
, Key
&key
,
222 const CssmData
&data
, const CssmData
&mac
)
224 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
225 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
226 CssmClient::VerifyMac
verifier(Server::csp(), context
.algorithm());
227 verifier
.override(context
);
228 verifier
.verify(data
, mac
);
233 // Encryption/decryption
235 void Connection::encrypt(const Context
&context
, Key
&key
,
236 const CssmData
&clear
, CssmData
&cipher
)
238 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
239 key
.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
);
240 CssmClient::Encrypt
cryptor(Server::csp(), context
.algorithm());
241 cryptor
.override(context
);
243 size_t totalLength
= cryptor
.encrypt(clear
, cipher
, remData
);
244 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
246 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
247 cipher
.length(totalLength
);
250 void Connection::decrypt(const Context
&context
, Key
&key
,
251 const CssmData
&cipher
, CssmData
&clear
)
253 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
254 key
.validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
);
255 CssmClient::Decrypt
cryptor(Server::csp(), context
.algorithm());
256 cryptor
.override(context
);
258 size_t totalLength
= cryptor
.decrypt(cipher
, clear
, remData
);
259 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
261 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
262 clear
.length(totalLength
);
267 // Key generation and derivation.
268 // Currently, we consider symmetric key generation to be fast, but
269 // asymmetric key generation to be (potentially) slow.
271 void Connection::generateKey(Database
*db
, const Context
&context
,
272 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
273 uint32 usage
, uint32 attrs
, Key
* &newKey
)
276 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
277 generate
.override(context
);
280 // @@@ turn "none" return into reference if permanent (only)
282 generate(key
, Key::KeySpec(usage
, attrs
));
284 // register and return the generated key
285 newKey
= new Key(db
, key
, attrs
& Key::managedAttributes
, owner
);
288 void Connection::generateKey(Database
*db
, const Context
&context
,
289 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
290 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
291 Key
* &publicKey
, Key
* &privateKey
)
294 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
295 generate
.override(context
);
297 // this may take a while; let our server object know
298 Server::active().longTermActivity();
301 // @@@ turn "none" return into reference if permanent (only)
302 CssmKey pubKey
, privKey
;
303 generate(pubKey
, Key::KeySpec(pubUsage
, pubAttrs
),
304 privKey
, Key::KeySpec(privUsage
, privAttrs
));
306 // register and return the generated keys
307 publicKey
= new Key(db
, pubKey
, pubAttrs
& Key::managedAttributes
, owner
);
308 privateKey
= new Key(db
, privKey
, privAttrs
& Key::managedAttributes
, owner
);
311 Key
&Connection::deriveKey(Database
*db
, const Context
&context
, Key
*baseKey
,
312 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
313 CssmData
*param
, uint32 usage
, uint32 attrs
)
315 // prepare a key-derivation context
317 baseKey
->validate(CSSM_ACL_AUTHORIZATION_DERIVE
, cred
);
318 context
.replace(CSSM_ATTRIBUTE_KEY
, baseKey
->cssmKey());
320 CssmClient::DeriveKey
derive(Server::csp(), context
.algorithm(), CSSM_ALGID_NONE
);
321 derive
.override(context
);
324 // @@@ turn "none" return into reference if permanent (only)
326 derive(param
, Key::KeySpec(usage
, attrs
), key
);
328 // register and return the generated key
329 return *new Key(db
, key
, attrs
& Key::managedAttributes
, owner
);
334 // Key wrapping and unwrapping.
335 // Note that the key argument (the key in the context) is optional because of the special
336 // case of "cleartext" (null algorithm) wrapping for import/export.
339 void Connection::wrapKey(const Context
&context
, Key
*key
,
340 Key
&keyToBeWrapped
, const AccessCredentials
*cred
,
341 const CssmData
&descriptiveData
, CssmKey
&wrappedKey
)
343 keyToBeWrapped
.validate(context
.algorithm() == CSSM_ALGID_NONE
?
344 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR
: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
,
346 if(!(keyToBeWrapped
.attributes() & CSSM_KEYATTR_EXTRACTABLE
)) {
347 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
350 context
.replace(CSSM_ATTRIBUTE_KEY
, key
->cssmKey());
351 CssmClient::WrapKey
wrap(Server::csp(), context
.algorithm());
352 wrap
.override(context
);
353 wrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
354 wrap(keyToBeWrapped
, wrappedKey
, &descriptiveData
);
357 Key
&Connection::unwrapKey(Database
*db
, const Context
&context
, Key
*key
,
358 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
359 uint32 usage
, uint32 attrs
, const CssmKey wrappedKey
,
360 Key
*publicKey
, CssmData
*descriptiveData
)
363 context
.replace(CSSM_ATTRIBUTE_KEY
, key
->cssmKey());
364 CssmClient::UnwrapKey
unwrap(Server::csp(), context
.algorithm());
365 unwrap
.override(context
);
366 CssmKey unwrappedKey
;
367 unwrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
369 AclEntryInput
ownerInput(*owner
); //@@@ const trouble - fix in client/pod
370 unwrap
.aclEntry(ownerInput
);
373 // @@@ Invoking conversion operator to CssmKey & on *publicKey and take the address of the result.
374 unwrap(wrappedKey
, Key::KeySpec(usage
, attrs
), unwrappedKey
,
375 descriptiveData
, publicKey
? &static_cast<const CssmKey
&>(*publicKey
) : NULL
);
377 return *new Key(db
, unwrappedKey
, attrs
& Key::managedAttributes
, owner
);
382 // Miscellaneous CSSM functions
384 uint32
Connection::getOutputSize(const Context
&context
, Key
&key
, uint32 inputSize
, bool encrypt
)
386 // We're fudging here somewhat, since the context can be any type.
387 // ctx.override will fix the type, and no-one's the wiser.
388 context
.replace(CSSM_ATTRIBUTE_KEY
, key
.cssmKey());
389 CssmClient::Digest
ctx(Server::csp(), context
.algorithm());
390 ctx
.override(context
);
391 return ctx
.getOutputSize(inputSize
, encrypt
);