]> git.saurik.com Git - apple/security.git/blob - SecurityServer/connection.cpp
Security-54.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 debug("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 debug("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 debug("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 debug("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 debug("SS", "Connection %p abort deferred (busy)", this);
98 return false; // but not quite yet
99 default:
100 assert(false); // impossible (we hope)
101 }
102 }
103
104
105 //
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
109 // under them.
110 //
111 void Connection::beginWork()
112 {
113 switch (state) {
114 case idle:
115 state = busy;
116 process.beginConnection(*this);
117 break;
118 case busy:
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?
121 default:
122 assert(false);
123 }
124 }
125
126 void Connection::checkWork()
127 {
128 StLock<Mutex> _(lock);
129 switch (state) {
130 case busy:
131 return;
132 case dying:
133 agentWait = NULL; // obviously we're not waiting on this
134 throw this;
135 default:
136 assert(false);
137 }
138 }
139
140 bool Connection::endWork()
141 {
142 switch (state) {
143 case busy:
144 // process the n-step aclUpdateTrigger
145 if (aclUpdateTrigger) {
146 if (--aclUpdateTriggerCount == 0) {
147 aclUpdateTrigger = NULL;
148 debug("kcacl", "acl update trigger expires");
149 } else
150 debug("kcacl", "acl update trigger armed for %d calls",
151 aclUpdateTriggerCount);
152 }
153 // end involvement
154 state = idle;
155 process.endConnection(*this);
156 return false;
157 case dying:
158 debug("SS", "Connection %p abort resuming", this);
159 if (process.endConnection(*this))
160 delete &process;
161 return true;
162 default:
163 assert(false);
164 }
165 }
166
167
168 //
169 // Key creation and release
170 //
171 void Connection::releaseKey(Key::Handle key)
172 {
173 delete &Server::key(key);
174 }
175
176
177 //
178 // Key inquiries
179 //
180 CSSM_KEY_SIZE Connection::queryKeySize(Key &key)
181 {
182 CssmClient::Key theKey(Server::csp(), key);
183 return theKey.sizeInBits();
184 }
185
186
187 //
188 // Signatures and MACs
189 //
190 void Connection::generateSignature(const Context &context, Key &key,
191 CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature)
192 {
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);
198 }
199
200 void Connection::verifySignature(const Context &context, Key &key,
201 CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature)
202 {
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);
207 }
208
209 void Connection::generateMac(const Context &context, Key &key,
210 const CssmData &data, CssmData &mac)
211 {
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);
217 }
218
219 void Connection::verifyMac(const Context &context, Key &key,
220 const CssmData &data, const CssmData &mac)
221 {
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);
227 }
228
229
230 //
231 // Encryption/decryption
232 //
233 void Connection::encrypt(const Context &context, Key &key,
234 const CssmData &clear, CssmData &cipher)
235 {
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);
240 CssmData remData;
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
243 if (remData)
244 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
245 cipher.length(totalLength);
246 }
247
248 void Connection::decrypt(const Context &context, Key &key,
249 const CssmData &cipher, CssmData &clear)
250 {
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);
255 CssmData remData;
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
258 if (remData)
259 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
260 clear.length(totalLength);
261 }
262
263
264 //
265 // Key generation and derivation.
266 // Currently, we consider symmetric key generation to be fast, but
267 // asymmetric key generation to be (potentially) slow.
268 //
269 void Connection::generateKey(Database *db, const Context &context,
270 const AccessCredentials *cred, const AclEntryPrototype *owner,
271 uint32 usage, uint32 attrs, Key * &newKey)
272 {
273 // prepare a context
274 CssmClient::GenerateKey generate(Server::csp(), context.algorithm());
275 generate.override(context);
276
277 // generate key
278 // @@@ turn "none" return into reference if permanent (only)
279 CssmKey key;
280 generate(key, Key::KeySpec(usage, attrs));
281
282 // register and return the generated key
283 newKey = new Key(db, key, attrs & Key::managedAttributes, owner);
284 }
285
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)
290 {
291 // prepare a context
292 CssmClient::GenerateKey generate(Server::csp(), context.algorithm());
293 generate.override(context);
294
295 // this may take a while; let our server object know
296 Server::active().longTermActivity();
297
298 // generate keys
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));
303
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);
307 }
308
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)
312 {
313 // prepare a key-derivation context
314 if (baseKey) {
315 baseKey->validate(CSSM_ACL_AUTHORIZATION_DERIVE, cred);
316 context.replace(CSSM_ATTRIBUTE_KEY, (CSSM_KEY &)*baseKey);
317 }
318 CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE);
319 derive.override(context);
320
321 // derive key
322 // @@@ turn "none" return into reference if permanent (only)
323 CssmKey key;
324 derive(param, Key::KeySpec(usage, attrs), key);
325
326 // register and return the generated key
327 return *new Key(db, key, attrs & Key::managedAttributes, owner);
328 }
329
330
331 //
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.
335 //
336 void Connection::wrapKey(const Context &context, Key *key,
337 Key &keyToBeWrapped, const AccessCredentials *cred,
338 const CssmData &descriptiveData, CssmKey &wrappedKey)
339 {
340 keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ?
341 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
342 cred);
343 if (key)
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);
349 }
350
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)
355 {
356 if (key)
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
362 if (owner) {
363 AclEntryInput ownerInput(*owner); //@@@ const trouble - fix in client/pod
364 unwrap.aclEntry(ownerInput);
365 }
366
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);
370
371 return *new Key(db, unwrappedKey, attrs & Key::managedAttributes, owner);
372 }
373
374
375 //
376 // Miscellaneous CSSM functions
377 //
378 uint32 Connection::getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt)
379 {
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);
386 }
387