]> git.saurik.com Git - apple/security.git/blob - SecurityServer/connection.cpp
Security-177.tar.gz
[apple/security.git] / SecurityServer / connection.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // connection - manage connections to clients.
21 //
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.
26 //
27 #include "connection.h"
28 #include "key.h"
29 #include "server.h"
30 #include "session.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>
37
38
39 //
40 // Construct a Connection object.
41 //
42 Connection::Connection(Process &proc, Port rPort)
43 : process(proc), mClientPort(rPort), state(idle), agentWait(NULL),
44 aclUpdateTrigger(NULL)
45 {
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);
48
49 secdebug("SS", "New connection %p for process %d clientport=%d",
50 this, process.pid(), int(rPort));
51 }
52
53
54 //
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.
57 //
58 Connection::~Connection()
59 {
60 secdebug("SS", "Connection %p destroyed", this);
61 assert(!agentWait);
62 }
63
64
65 //
66 // Terminate a Connection normally.
67 // This is assumed to be properly sequenced, so no thread races are possible.
68 //
69 void Connection::terminate()
70 {
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);
76 }
77
78
79 //
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.
83 //
84 bool Connection::abort(bool keepReplyPort)
85 {
86 StLock<Mutex> _(lock);
87 if (!keepReplyPort)
88 mClientPort.destroy(); // dead as a doornail already
89 switch (state) {
90 case idle:
91 secdebug("SS", "Connection %p aborted", this);
92 return true; // just shoot me
93 case busy:
94 state = dying; // shoot me soon, please
95 if (agentWait)
96 agentWait->cancel();
97 secdebug("SS", "Connection %p abort deferred (busy)", this);
98 return false; // but not quite yet
99 default:
100 assert(false); // impossible (we hope)
101 return true; // placebo
102 }
103 }
104
105
106 //
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
110 // under them.
111 //
112 void Connection::beginWork()
113 {
114 switch (state) {
115 case idle:
116 state = busy;
117 process.beginConnection(*this);
118 break;
119 case busy:
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?
122 default:
123 assert(false);
124 }
125 }
126
127 void Connection::checkWork()
128 {
129 StLock<Mutex> _(lock);
130 switch (state) {
131 case busy:
132 return;
133 case dying:
134 agentWait = NULL; // obviously we're not waiting on this
135 throw this;
136 default:
137 assert(false);
138 }
139 }
140
141 bool Connection::endWork()
142 {
143 switch (state) {
144 case busy:
145 // process the n-step aclUpdateTrigger
146 if (aclUpdateTrigger) {
147 if (--aclUpdateTriggerCount == 0) {
148 aclUpdateTrigger = NULL;
149 secdebug("kcacl", "acl update trigger expires");
150 } else
151 secdebug("kcacl", "acl update trigger armed for %d calls",
152 aclUpdateTriggerCount);
153 }
154 // end involvement
155 state = idle;
156 process.endConnection(*this);
157 return false;
158 case dying:
159 secdebug("SS", "Connection %p abort resuming", this);
160 if (process.endConnection(*this))
161 delete &process;
162 return true;
163 default:
164 assert(false);
165 return true; // placebo
166 }
167 }
168
169
170 //
171 // Key creation and release
172 //
173 void Connection::releaseKey(Key::Handle key)
174 {
175 delete &Server::key(key);
176 }
177
178
179 //
180 // Key inquiries
181 //
182 CSSM_KEY_SIZE Connection::queryKeySize(Key &key)
183 {
184 CssmClient::Key theKey(Server::csp(), key);
185 return theKey.sizeInBits();
186 }
187
188
189 //
190 // Signatures and MACs
191 //
192 void Connection::generateSignature(const Context &context, Key &key,
193 CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature)
194 {
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);
200 }
201
202 void Connection::verifySignature(const Context &context, Key &key,
203 CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature)
204 {
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);
209 }
210
211 void Connection::generateMac(const Context &context, Key &key,
212 const CssmData &data, CssmData &mac)
213 {
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);
219 }
220
221 void Connection::verifyMac(const Context &context, Key &key,
222 const CssmData &data, const CssmData &mac)
223 {
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);
229 }
230
231
232 //
233 // Encryption/decryption
234 //
235 void Connection::encrypt(const Context &context, Key &key,
236 const CssmData &clear, CssmData &cipher)
237 {
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);
242 CssmData remData;
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
245 if (remData)
246 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
247 cipher.length(totalLength);
248 }
249
250 void Connection::decrypt(const Context &context, Key &key,
251 const CssmData &cipher, CssmData &clear)
252 {
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);
257 CssmData remData;
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
260 if (remData)
261 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
262 clear.length(totalLength);
263 }
264
265
266 //
267 // Key generation and derivation.
268 // Currently, we consider symmetric key generation to be fast, but
269 // asymmetric key generation to be (potentially) slow.
270 //
271 void Connection::generateKey(Database *db, const Context &context,
272 const AccessCredentials *cred, const AclEntryPrototype *owner,
273 uint32 usage, uint32 attrs, Key * &newKey)
274 {
275 // prepare a context
276 CssmClient::GenerateKey generate(Server::csp(), context.algorithm());
277 generate.override(context);
278
279 // generate key
280 // @@@ turn "none" return into reference if permanent (only)
281 CssmKey key;
282 generate(key, Key::KeySpec(usage, attrs));
283
284 // register and return the generated key
285 newKey = new Key(db, key, attrs & Key::managedAttributes, owner);
286 }
287
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)
292 {
293 // prepare a context
294 CssmClient::GenerateKey generate(Server::csp(), context.algorithm());
295 generate.override(context);
296
297 // this may take a while; let our server object know
298 Server::active().longTermActivity();
299
300 // generate keys
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));
305
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);
309 }
310
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)
314 {
315 // prepare a key-derivation context
316 if (baseKey) {
317 baseKey->validate(CSSM_ACL_AUTHORIZATION_DERIVE, cred);
318 context.replace(CSSM_ATTRIBUTE_KEY, baseKey->cssmKey());
319 }
320 CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE);
321 derive.override(context);
322
323 // derive key
324 // @@@ turn "none" return into reference if permanent (only)
325 CssmKey key;
326 derive(param, Key::KeySpec(usage, attrs), key);
327
328 // register and return the generated key
329 return *new Key(db, key, attrs & Key::managedAttributes, owner);
330 }
331
332
333 //
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.
337 //
338
339 void Connection::wrapKey(const Context &context, Key *key,
340 Key &keyToBeWrapped, const AccessCredentials *cred,
341 const CssmData &descriptiveData, CssmKey &wrappedKey)
342 {
343 keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ?
344 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
345 cred);
346 if(!(keyToBeWrapped.attributes() & CSSM_KEYATTR_EXTRACTABLE)) {
347 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
348 }
349 if (key)
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);
355 }
356
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)
361 {
362 if (key)
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
368 if (owner) {
369 AclEntryInput ownerInput(*owner); //@@@ const trouble - fix in client/pod
370 unwrap.aclEntry(ownerInput);
371 }
372
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);
376
377 return *new Key(db, unwrappedKey, attrs & Key::managedAttributes, owner);
378 }
379
380
381 //
382 // Miscellaneous CSSM functions
383 //
384 uint32 Connection::getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt)
385 {
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);
392 }
393