]> git.saurik.com Git - apple/security.git/blob - SecurityServer/connection.cpp
Security-29.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 // Signatures and MACs
179 //
180 void Connection::generateSignature(const Context &context, Key &key,
181 const CssmData &data, CssmData &signature)
182 {
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);
188 }
189
190 void Connection::verifySignature(const Context &context, Key &key,
191 const CssmData &data, const CssmData &signature)
192 {
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);
197 }
198
199 void Connection::generateMac(const Context &context, Key &key,
200 const CssmData &data, CssmData &mac)
201 {
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);
207 }
208
209 void Connection::verifyMac(const Context &context, Key &key,
210 const CssmData &data, const CssmData &mac)
211 {
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);
217 }
218
219
220 //
221 // Encryption/decryption
222 //
223 void Connection::encrypt(const Context &context, Key &key,
224 const CssmData &clear, CssmData &cipher)
225 {
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);
230 CssmData remData;
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
233 if (remData)
234 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
235 cipher.length(totalLength);
236 }
237
238 void Connection::decrypt(const Context &context, Key &key,
239 const CssmData &cipher, CssmData &clear)
240 {
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);
245 CssmData remData;
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
248 if (remData)
249 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
250 clear.length(totalLength);
251 }
252
253
254 //
255 // Key generation.
256 // Currently, we consider symmetric key generation to be fast, but
257 // asymmetric key generation to be (potentially) slow.
258 //
259 void Connection::generateKey(Database *db, const Context &context,
260 const AccessCredentials *cred, const AclEntryPrototype *owner,
261 uint32 usage, uint32 attrs, Key * &newKey)
262 {
263 // prepare a context
264 CssmClient::GenerateKey generate(Server::csp(), context.algorithm());
265 generate.override(context);
266
267 // generate key
268 // @@@ turn "none" return into reference if permanent (only)
269 CssmKey key;
270 generate(key, CssmClient::KeySpec(usage, attrs & ~Key::managedAttributes));
271
272 // register and return the generated key
273 newKey = new Key(db, key, attrs & Key::managedAttributes, owner);
274 }
275
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)
280 {
281 // prepare a context
282 CssmClient::GenerateKey generate(Server::csp(), context.algorithm());
283 generate.override(context);
284
285 // this may take a while; let our server object know
286 Server::active().longTermActivity();
287
288 // generate keys
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));
293
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);
297 }
298
299
300 //
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.
304 //
305 void Connection::wrapKey(const Context &context, Key *key,
306 Key &keyToBeWrapped, const AccessCredentials *cred,
307 const CssmData &descriptiveData, CssmKey &wrappedKey)
308 {
309 keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ?
310 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
311 cred);
312 if (key)
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);
318 }
319
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)
324 {
325 if (key)
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
331 if (owner) {
332 AclEntryInput ownerInput(*owner); //@@@ const trouble - fix in client/pod
333 unwrap.aclEntry(ownerInput);
334 }
335
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);
339
340 return *new Key(db, unwrappedKey, attrs & Key::managedAttributes, owner);
341 }