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
); 
 178 // Signatures and MACs 
 180 void Connection::generateSignature(const Context 
&context
, Key 
&key
, 
 181         const CssmData 
&data
, CssmData 
&signature
) 
 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
); 
 190 void Connection::verifySignature(const Context 
&context
, Key 
&key
, 
 191         const CssmData 
&data
, const CssmData 
&signature
) 
 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
); 
 199 void Connection::generateMac(const Context 
&context
, Key 
&key
, 
 200         const CssmData 
&data
, CssmData 
&mac
) 
 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
); 
 209 void Connection::verifyMac(const Context 
&context
, Key 
&key
, 
 210         const CssmData 
&data
, const CssmData 
&mac
) 
 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
); 
 221 // Encryption/decryption 
 223 void Connection::encrypt(const Context 
&context
, Key 
&key
, 
 224         const CssmData 
&clear
, CssmData 
&cipher
) 
 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
); 
 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 
 234                 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); 
 235         cipher
.length(totalLength
); 
 238 void Connection::decrypt(const Context 
&context
, Key 
&key
, 
 239         const CssmData 
&cipher
, CssmData 
&clear
) 
 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
); 
 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 
 249                 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); 
 250         clear
.length(totalLength
); 
 256 // Currently, we consider symmetric key generation to be fast, but 
 257 // asymmetric key generation to be (potentially) slow. 
 259 void Connection::generateKey(Database 
*db
, const Context 
&context
, 
 260                 const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 261                 uint32 usage
, uint32 attrs
, Key 
* &newKey
) 
 264         CssmClient::GenerateKey 
generate(Server::csp(), context
.algorithm()); 
 265         generate
.override(context
); 
 268         // @@@ turn "none" return into reference if permanent (only) 
 270         generate(key
, CssmClient::KeySpec(usage
, attrs 
& ~Key::managedAttributes
)); 
 272         // register and return the generated key 
 273     newKey 
= new Key(db
, key
, attrs 
& Key::managedAttributes
, owner
); 
 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
) 
 282         CssmClient::GenerateKey 
generate(Server::csp(), context
.algorithm()); 
 283         generate
.override(context
); 
 285         // this may take a while; let our server object know 
 286         Server::active().longTermActivity(); 
 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
)); 
 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
); 
 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. 
 305 void Connection::wrapKey(const Context 
&context
, Key 
*key
, 
 306     Key 
&keyToBeWrapped
, const AccessCredentials 
*cred
, 
 307     const CssmData 
&descriptiveData
, CssmKey 
&wrappedKey
) 
 309     keyToBeWrapped
.validate(context
.algorithm() == CSSM_ALGID_NONE 
? 
 310             CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR 
: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, 
 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
); 
 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
) 
 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 
 332         AclEntryInput 
ownerInput(*owner
);       //@@@ const trouble - fix in client/pod 
 333         unwrap
.aclEntry(ownerInput
); 
 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
); 
 340     return *new Key(db
, unwrappedKey
, attrs 
& Key::managedAttributes
, owner
);