2  * Copyright (c) 2000-2008,2013 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26 // tokendatabase - software database container implementation. 
  28 #include "tokendatabase.h" 
  30 #include "tokenaccess.h" 
  33 #include "localkey.h"           // to retrieve local raw keys 
  34 #include <security_cdsa_client/wrapkey.h> 
  38 // Construct a TokenDbCommon 
  40 TokenDbCommon::TokenDbCommon(Session 
&ssn
, Token 
&tk
, const char *name
) 
  41         : DbCommon(ssn
), mDbName(name 
? name 
: ""), mHasAclState(false) 
  43         secinfo("tokendb", "creating tokendbcommon %p: with token %p", this, &tk
); 
  47 TokenDbCommon::~TokenDbCommon() 
  49         secinfo("tokendb", "destroying tokendbcommon %p", this); 
  50         token().removeCommon(*this);            // unregister from Token 
  53 Token 
&TokenDbCommon::token() const 
  55         return parent
<Token
>(); 
  58 std::string 
TokenDbCommon::dbName() const 
  60         return token().printName(); 
  65 // A TokenDbCommon holds per-session adornments for the ACL machine 
  67 Adornable 
&TokenDbCommon::store() 
  69         StLock
<Mutex
> _(*this); 
  71         // if this is the first one, hook for lifetime 
  73                 session().addReference(*this);          // hold and slave to SSN lifetime 
  74                 token().addCommon(*this);                       // register with Token 
  78         // return our (now active) adornments 
  82 void TokenDbCommon::resetAcls() 
  84         StLock
<Mutex
> _(*this); 
  86                 clearAdornments();                                      // clear ACL state 
  87                 session().removeReference(*this);       // unhook from SSN 
  90         token().removeCommon(*this);                    // unregister from Token 
  95 // Send out a "keychain" notification for this database 
  97 void TokenDbCommon::notify(NotificationEvent event
) 
  99         DbCommon::notify(event
, DLDbIdentifier(dbName().c_str(), gGuidAppleSdCSPDL
, 
 100                 subservice(), CSSM_SERVICE_DL 
| CSSM_SERVICE_CSP
)); 
 105 // Process (our part of) a "lock all" request. 
 106 // Smartcard tokens interpret a "lock" as a forced card reset, transmitted 
 107 // to tokend as an authenticate request. 
 108 // @@@ Virtual reset for multi-session tokens. Right now, we're using the sledge hammer. 
 110 void TokenDbCommon::lockProcessing() 
 112         Access 
access(token()); 
 113         access().authenticate(CSSM_DB_ACCESS_RESET
, NULL
); 
 117 // Construct a TokenDatabase given subservice information. 
 118 // We are currently ignoring the 'name' argument. 
 120 TokenDatabase::TokenDatabase(uint32 ssid
, Process 
&proc
, 
 121         const char *name
, const AccessCredentials 
*cred
) 
 124         // locate Token object 
 125         RefPointer
<Token
> token 
= Token::find(ssid
); 
 127         Session 
&session 
= process().session(); 
 128         StLock
<Mutex
> _(session
); 
 129         if (TokenDbCommon 
*dbcom 
= session
.findFirst
<TokenDbCommon
, uint32
>(&TokenDbCommon::subservice
, ssid
)) { 
 131                 secinfo("tokendb", "open tokendb %p(%d) at known common %p", 
 132                         this, subservice(), dbcom
); 
 134                 // DbCommon not present; make a new one 
 135                 parent(*new TokenDbCommon(proc
.session(), *token
, name
)); 
 136                 secinfo("tokendb", "open tokendb %p(%d) with new common %p", 
 137                         this, subservice(), &common()); 
 139         mOpenCreds 
= copy(cred
, Allocator::standard()); 
 140         proc
.addReference(*this); 
 143 TokenDatabase::~TokenDatabase() 
 145         Allocator::standard().free(mOpenCreds
); 
 150 // Basic Database virtual implementations 
 152 TokenDbCommon 
&TokenDatabase::common() const 
 154         return parent
<TokenDbCommon
>(); 
 157 TokenDaemon 
&TokenDatabase::tokend() 
 159         return common().token().tokend(); 
 162 const char *TokenDatabase::dbName() const 
 164     //store dbName to ensure that will live outside function scope 
 165     mDbName 
= common().dbName(); 
 166         return mDbName
.c_str(); 
 169 bool TokenDatabase::transient() const 
 171         //@@@ let tokend decide? Are there any secure transient keystores? 
 177 // Our ObjectAcl resides in the Token object. 
 179 SecurityServerAcl 
&TokenDatabase::acl() 
 186 // We post-process the status version of getAcl to account for virtual (per-session) 
 189 void TokenDatabase::getAcl(const char *tag
, uint32 
&count
, AclEntryInfo 
*&acls
) 
 191         AclSource::getAcl(tag
, count
, acls
); 
 193         for (unsigned n 
= 0; n 
< count
; n
++) { 
 194                 AclEntryPrototype 
&proto 
= acls
[n
]; 
 195         uint32_t pin 
= pinFromAclTag(proto
.tag(), "?"); 
 196                 if (pin
) {      // pin state response 
 197                         secinfo("tokendb", "%p updating PIN%d state response", this, pin
); 
 198                         TypedList 
&subject 
= proto
.subject(); 
 199                         // subject == { CSSM_WORID_PIN, pin-number, status [, count ] } # all numbers 
 200                         if (subject
.length() > 2 
 201                                 && subject
[0].is(CSSM_LIST_ELEMENT_WORDID
) 
 202                                 && subject
[0] == CSSM_WORDID_PIN
 
 203                                 && subject
[1].is(CSSM_LIST_ELEMENT_WORDID
) 
 204                                 && subject
[2].is(CSSM_LIST_ELEMENT_WORDID
)) { 
 205                                 uint32_t pin 
= subject
[1]; 
 206 #pragma clang diagnostic push 
 207 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" 
 208                 // This is likely a bug, but we're trapped by CDSA types 
 209                                 if (!common().attachment
<PreAuthorizationAcls::AclState
>((void *) pin
).accepted
) { 
 210 #pragma clang diagnostic pop 
 211                                         // we are not pre-authorized in this session 
 212                                         secinfo("tokendb", "%p session state forces PIN%d reporting unauthorized", this, pin
); 
 213                                         uint32 status 
= subject
[2]; 
 214                                         status 
&= ~CSSM_ACL_PREAUTH_TRACKING_AUTHORIZED
;        // clear authorized bit 
 217                                 if (subject
.length() > 3 && subject
[3].is(CSSM_LIST_ELEMENT_WORDID
)) 
 218                                         secinfo("tokendb", "%p PIN%d count=%d", this, pin
, subject
[3].word()); 
 227 bool TokenDatabase::isLocked() 
 229         Access 
access(token()); 
 231         bool lockState 
= pinState(1); 
 232 //      bool lockState = access().isLocked(); 
 234         secinfo("tokendb", "returning isLocked=%d", lockState
); 
 238 bool TokenDatabase::pinState(uint32 pin
, int *pinCount 
/* = NULL */) 
 242         this->getAcl("PIN1?", count
, acls
); 
 243         bool locked 
= true;     // preset locked 
 245                 *pinCount 
= -1;         // preset unknown 
 248                 secinfo("tokendb", "PIN%d query returned no entries", pin
); 
 251                 secinfo("tokendb", "PIN%d query returned multiple entries", pin
); 
 255                         TypedList 
&subject 
= acls
[0].proto().subject(); 
 256                         if (subject
.length() > 2 
 257                                 && subject
[0].is(CSSM_LIST_ELEMENT_WORDID
) 
 258                                 && subject
[0] == CSSM_WORDID_PIN
 
 259                                 && subject
[1].is(CSSM_LIST_ELEMENT_WORDID
) 
 260                                 && subject
[2].is(CSSM_LIST_ELEMENT_WORDID
)) { 
 261                                 uint32 status 
= subject
[2]; 
 262                                 locked 
= !(status 
& CSSM_ACL_PREAUTH_TRACKING_AUTHORIZED
); 
 263                                 if (pinCount 
&& locked 
&& subject
.length() > 3 && subject
[3].is(CSSM_LIST_ELEMENT_WORDID
)) 
 264                                         *pinCount 
= subject
[3]; 
 270         // release memory allocated by getAcl 
 271         ChunkFreeWalker free
; 
 272         for (uint32 n 
= 0; n 
< count
; n
++) 
 274         Allocator::standard().free(acls
); 
 282 // TokenDatabases implement the dbName-setting function. 
 283 // This sets the print name of the token, which is persistently 
 284 // stored in the token cache. So this is a de-facto rename of 
 285 // the token, at least on this system. 
 287 void TokenDatabase::dbName(const char *name
) 
 289         CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
); 
 294 // Given a key handle and CssmKey returned from tokend, create a Key representing 
 295 // it. This takes care of raw returns by turning them into keys of the process's 
 296 // local transient store. 
 298 RefPointer
<Key
> TokenDatabase::makeKey(KeyHandle hKey
, const CssmKey 
*key
, 
 299         uint32 moreAttributes
, const AclEntryPrototype 
*owner
) 
 301         switch (key
->blobType()) { 
 302         case CSSM_KEYBLOB_REFERENCE
: 
 303                 return new TokenKey(*this, hKey
, key
->header()); 
 304         case CSSM_KEYBLOB_RAW
: 
 305                 return process().makeTemporaryKey(*key
, moreAttributes
, owner
); 
 307                 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);        // bad key return from tokend 
 309         //@@@ Server::releaseWhenDone(key); 
 314 // Adjust key attributes for newly created keys 
 316 static CSSM_KEYATTR_FLAGS 
modattrs(CSSM_KEYATTR_FLAGS attrs
) 
 318         static const CSSM_KEYATTR_FLAGS CSSM_KEYATTR_RETURN_FLAGS 
= 0xff000000; 
 319         switch (attrs 
& CSSM_KEYATTR_RETURN_FLAGS
) { 
 320         case CSSM_KEYATTR_RETURN_REF
: 
 321         case CSSM_KEYATTR_RETURN_DATA
: 
 322                 break;  // as requested 
 323         case CSSM_KEYATTR_RETURN_NONE
: 
 324                 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
); 
 325         case CSSM_KEYATTR_RETURN_DEFAULT
: 
 326                 if (attrs 
& CSSM_KEYATTR_PERMANENT
) 
 327                         attrs 
|= CSSM_KEYATTR_RETURN_REF
; 
 329                         attrs 
|= CSSM_KEYATTR_RETURN_DATA
; 
 337 // TokenDatabases support remote secret validation by sending a secret 
 338 // (aka passphrase et al) to tokend for processing. 
 340 bool TokenDatabase::validateSecret(const AclSubject 
*subject
, const AccessCredentials 
*cred
) 
 342         secinfo("tokendb", "%p attempting remote validation", this); 
 344                 Access 
access(token()); 
 345                 // @@@ Use cached mode 
 346                 access().authenticate(CSSM_DB_ACCESS_READ
, cred
); 
 347                 secinfo("tokendb", "%p remote validation successful", this); 
 351                 secinfo("tokendb", "%p remote validation failed", this); 
 353         throw;  // try not to mask error 
 361 void TokenDatabase::queryKeySizeInBits(Key 
&key
, CssmKeySize 
&result
) 
 363         Access 
access(token()); 
 366         access().queryKeySizeInBits(myKey(key
).tokenHandle(), result
); 
 372 // Signatures and MACs 
 374 void TokenDatabase::generateSignature(const Context 
&context
, Key 
&key
, 
 375         CSSM_ALGORITHMS signOnlyAlgorithm
, const CssmData 
&data
, CssmData 
&signature
) 
 377         Access 
access(token(), key
); 
 379         key
.validate(CSSM_ACL_AUTHORIZATION_SIGN
, context
); 
 381         access().generateSignature(context
, myKey(key
).tokenHandle(), data
, signature
, signOnlyAlgorithm
); 
 386 void TokenDatabase::verifySignature(const Context 
&context
, Key 
&key
, 
 387         CSSM_ALGORITHMS verifyOnlyAlgorithm
, const CssmData 
&data
, const CssmData 
&signature
) 
 389         Access 
access(token(), key
); 
 392         access().verifySignature(context
, myKey(key
).tokenHandle(), data
, signature
, verifyOnlyAlgorithm
); 
 396 void TokenDatabase::generateMac(const Context 
&context
, Key 
&key
, 
 397         const CssmData 
&data
, CssmData 
&mac
) 
 399         Access 
access(token()); 
 401         key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
); 
 403         access().generateMac(context
, myKey(key
).tokenHandle(), data
, mac
); 
 407 void TokenDatabase::verifyMac(const Context 
&context
, Key 
&key
, 
 408         const CssmData 
&data
, const CssmData 
&mac
) 
 410         Access 
access(token()); 
 412         key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
); 
 414         access().verifyMac(context
, myKey(key
).tokenHandle(), data
, mac
); 
 420 // Encryption/decryption 
 422 void TokenDatabase::encrypt(const Context 
&context
, Key 
&key
, 
 423         const CssmData 
&clear
, CssmData 
&cipher
) 
 425         Access 
access(token()); 
 427         key
.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
); 
 429         access().encrypt(context
, myKey(key
).tokenHandle(), clear
, cipher
); 
 434 void TokenDatabase::decrypt(const Context 
&context
, Key 
&key
, 
 435         const CssmData 
&cipher
, CssmData 
&clear
) 
 437         Access 
access(token()); 
 439         key
.validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
); 
 441         access().decrypt(context
, myKey(key
).tokenHandle(), cipher
, clear
); 
 447 // Key generation and derivation. 
 448 // Currently, we consider symmetric key generation to be fast, but 
 449 // asymmetric key generation to be (potentially) slow. 
 451 void TokenDatabase::generateKey(const Context 
&context
, 
 452                 const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 453                 CSSM_KEYUSE usage
, CSSM_KEYATTR_FLAGS attrs
, RefPointer
<Key
> &newKey
) 
 455         Access 
access(token()); 
 460         access().generateKey(context
, cred
, owner
, usage
, modattrs(attrs
), hKey
, result
); 
 461         newKey 
= makeKey(hKey
, result
, 0, owner
); 
 465 void TokenDatabase::generateKey(const Context 
&context
, 
 466         const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 467         CSSM_KEYUSE pubUsage
, CSSM_KEYATTR_FLAGS pubAttrs
, 
 468         CSSM_KEYUSE privUsage
, CSSM_KEYATTR_FLAGS privAttrs
, 
 469     RefPointer
<Key
> &publicKey
, RefPointer
<Key
> &privateKey
) 
 471         Access 
access(token()); 
 474         KeyHandle hPrivate
, hPublic
; 
 475         CssmKey 
*privKey
, *pubKey
; 
 476         access().generateKey(context
, cred
, owner
, 
 477                 pubUsage
, modattrs(pubAttrs
), privUsage
, modattrs(privAttrs
), 
 478                 hPublic
, pubKey
, hPrivate
, privKey
); 
 479         publicKey 
= makeKey(hPublic
, pubKey
, 0, owner
); 
 480         privateKey 
= makeKey(hPrivate
, privKey
, 0, owner
); 
 486 // Key wrapping and unwrapping. 
 487 // Note that the key argument (the key in the context) is optional because of the special 
 488 // case of "cleartext" (null algorithm) wrapping for import/export. 
 490 void TokenDatabase::wrapKey(const Context 
&context
, const AccessCredentials 
*cred
, 
 491                 Key 
*wrappingKey
, Key 
&subjectKey
, 
 492         const CssmData 
&descriptiveData
, CssmKey 
&wrappedKey
) 
 494         Access 
access(token()); 
 495         InputKey 
cWrappingKey(wrappingKey
); 
 496         InputKey 
cSubjectKey(subjectKey
); 
 498         subjectKey
.validate(context
.algorithm() == CSSM_ALGID_NONE 
? 
 499             CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR 
: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, 
 502                 wrappingKey
->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
); 
 504         CssmKey 
*rWrappedKey
; 
 505         access().wrapKey(context
, cred
, 
 506                 cWrappingKey
, cWrappingKey
, cSubjectKey
, cSubjectKey
, 
 507                 descriptiveData
, rWrappedKey
); 
 508         wrappedKey 
= *rWrappedKey
; 
 509         //@@@ ownership of wrappedKey.keyData() ?? 
 513 void TokenDatabase::unwrapKey(const Context 
&context
, 
 514                 const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 515                 Key 
*wrappingKey
, Key 
*publicKey
, CSSM_KEYUSE usage
, CSSM_KEYATTR_FLAGS attrs
, 
 516                 const CssmKey wrappedKey
, RefPointer
<Key
> &unwrappedKey
, CssmData 
&descriptiveData
) 
 518         Access 
access(token()); 
 519         InputKey 
cWrappingKey(wrappingKey
); 
 520         InputKey 
cPublicKey(publicKey
); 
 523                 wrappingKey
->validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
); 
 524         // we are not checking access on the public key, if any 
 528         access().unwrapKey(context
, cred
, owner
, 
 529                 cWrappingKey
, cWrappingKey
, cPublicKey
, cPublicKey
, 
 530                 wrappedKey
, usage
, modattrs(attrs
), descriptiveData
, hKey
, result
); 
 531         unwrappedKey 
= makeKey(hKey
, result
, modattrs(attrs
) & LocalKey::managedAttributes
, owner
); 
 539 void TokenDatabase::deriveKey(const Context 
&context
, Key 
*sourceKey
, 
 540         const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 541         CssmData 
*param
, CSSM_KEYUSE usage
, CSSM_KEYATTR_FLAGS attrs
, RefPointer
<Key
> &derivedKey
) 
 543         Access 
access(token()); 
 544         InputKey 
cSourceKey(sourceKey
); 
 547                 sourceKey
->validate(CSSM_ACL_AUTHORIZATION_DERIVE
, cred
); 
 551         CssmData params 
= param 
? *param 
: CssmData(); 
 552         access().deriveKey(noDb
, context
, 
 553                 cSourceKey
, cSourceKey
, 
 554                 usage
, modattrs(attrs
), params
, cred
, owner
, 
 558                 //@@@ leak? what's the rule here? 
 560         derivedKey 
= makeKey(hKey
, result
, 0, owner
); 
 566 // Miscellaneous CSSM functions 
 568 void TokenDatabase::getOutputSize(const Context 
&context
, Key 
&key
, 
 569         uint32 inputSize
, bool encrypt
, uint32 
&result
) 
 571         Access 
access(token()); 
 574         access().getOutputSize(context
, myKey(key
).tokenHandle(), inputSize
, encrypt
, result
); 
 580 // (Re-)Authenticate the database. 
 581 // We use dbAuthenticate as the catch-all "do something about authentication" call. 
 583 void TokenDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode
, const AccessCredentials 
*cred
) 
 585         Access 
access(token()); 
 588         if (mode 
!= CSSM_DB_ACCESS_RESET 
&& cred
) { 
 589                 secinfo("tokendb", "%p authenticate calling validate", this); 
 590                 if (unsigned pin 
= pinFromAclTag(cred
->EntryTag
)) { 
 591                         validate(CSSM_ACL_AUTHORIZATION_PREAUTH(pin
), cred
); 
 592                         notify(kNotificationEventUnlocked
); 
 597         access().authenticate(mode
, cred
); 
 599         case CSSM_DB_ACCESS_RESET
: 
 600                 // this mode is known to trigger "lockdown" (i.e. reset) 
 601                 common().resetAcls(); 
 602                 notify(kNotificationEventLocked
); 
 606                         // no idea what that did to the token;  
 607                         // But let's remember the new creds for our own sake. 
 608                         AccessCredentials 
*newCred 
= copy(cred
, Allocator::standard()); 
 609                         Allocator::standard().free(mOpenCreds
); 
 610                         mOpenCreds 
= newCred
; 
 618 // Data access interface. 
 620 // Note that the attribute vectors are passed between our two IPC interfaces 
 621 // as relocated but contiguous memory blocks (to avoid an extra copy). This means 
 622 // you can read them at will, but can't change them in transit unless you're 
 623 // willing to repack them right here. 
 625 void TokenDatabase::findFirst(const CssmQuery 
&query
, 
 626                 CssmDbRecordAttributeData 
*inAttributes
, mach_msg_type_number_t inAttributesLength
, 
 627                 CssmData 
*data
, RefPointer
<Key
> &key
, 
 628                 RefPointer
<Database::Search
> &rSearch
, RefPointer
<Database::Record
> &rRecord
, 
 629                 CssmDbRecordAttributeData 
* &outAttributes
, mach_msg_type_number_t 
&outAttributesLength
) 
 631         Access 
access(token()); 
 632         RefPointer
<Search
> search 
= new Search(*this); 
 633         RefPointer
<Record
> record 
= new Record(*this); 
 635         KeyHandle hKey 
= noKey
; 
 636     validate(CSSM_ACL_AUTHORIZATION_DB_READ
, openCreds()); 
 638         record
->tokenHandle() = access().Tokend::ClientSession::findFirst(query
, 
 639                 inAttributes
, inAttributesLength
, search
->tokenHandle(), NULL
, hKey
, 
 640                 outAttributes
, outAttributesLength
); 
 641         if (!record
->tokenHandle()) {   // no match (but no other error) 
 642                 rRecord 
= NULL
;                         // return null record 
 647                         record
->validate(CSSM_ACL_AUTHORIZATION_DB_READ
, openCreds()); 
 648                 CssmDbRecordAttributeData 
*noAttributes
; 
 649                 mach_msg_type_number_t noAttributesLength
; 
 650                 access().Tokend::ClientSession::findRecordHandle(record
->tokenHandle(), 
 651                         NULL
, 0, data
, hKey
, noAttributes
, noAttributesLength
); 
 652                 if (hKey
) {             // tokend returned a key reference & data 
 653                         CssmKey 
&keyForm 
= *data
->interpretedAs
<CssmKey
>(CSSMERR_CSP_INVALID_KEY
); 
 654                         key 
= new TokenKey(*this, hKey
, keyForm
.header()); 
 657         rSearch 
= search
->commit(); 
 658         rRecord 
= record
->commit(); 
 662 void TokenDatabase::findNext(Database::Search 
*rSearch
, 
 663         CssmDbRecordAttributeData 
*inAttributes
, mach_msg_type_number_t inAttributesLength
, 
 664         CssmData 
*data
, RefPointer
<Key
> &key
, RefPointer
<Database::Record
> &rRecord
, 
 665         CssmDbRecordAttributeData 
* &outAttributes
, mach_msg_type_number_t 
&outAttributesLength
) 
 667         Access 
access(token()); 
 668         RefPointer
<Record
> record 
= new Record(*this); 
 669         Search 
*search 
= safe_cast
<Search 
*>(rSearch
); 
 671         KeyHandle hKey 
= noKey
; 
 672         validate(CSSM_ACL_AUTHORIZATION_DB_READ
, openCreds()); 
 674         record
->tokenHandle() = access().Tokend::ClientSession::findNext( 
 675                 search
->tokenHandle(), inAttributes
, inAttributesLength
, 
 676                 NULL
, hKey
, outAttributes
, outAttributesLength
); 
 677         if (!record
->tokenHandle()) {   // no more matches 
 678                 releaseSearch(*search
);         // release search handle (consumed by EOD) 
 679                 rRecord 
= NULL
;                         // return null record 
 684                         record
->validate(CSSM_ACL_AUTHORIZATION_DB_READ
, openCreds()); 
 685                 CssmDbRecordAttributeData 
*noAttributes
; 
 686                 mach_msg_type_number_t noAttributesLength
; 
 687                 access().Tokend::ClientSession::findRecordHandle(record
->tokenHandle(), 
 688                         NULL
, 0, data
, hKey
, noAttributes
, noAttributesLength
); 
 689                 if (hKey
) {             // tokend returned a key reference & data 
 690                         CssmKey 
&keyForm 
= *data
->interpretedAs
<CssmKey
>(CSSMERR_CSP_INVALID_KEY
); 
 691                         key 
= new TokenKey(*this, hKey
, keyForm
.header()); 
 694         rRecord 
= record
->commit(); 
 698 void TokenDatabase::findRecordHandle(Database::Record 
*rRecord
, 
 699         CssmDbRecordAttributeData 
*inAttributes
, mach_msg_type_number_t inAttributesLength
, 
 700         CssmData 
*data
, RefPointer
<Key
> &key
, 
 701         CssmDbRecordAttributeData 
* &outAttributes
, mach_msg_type_number_t 
&outAttributesLength
) 
 703         Access 
access(token()); 
 704         Record 
*record 
= safe_cast
<Record 
*>(rRecord
); 
 707         KeyHandle hKey 
= noKey
; 
 708     validate(CSSM_ACL_AUTHORIZATION_DB_READ
, openCreds()); 
 710         record
->validate(CSSM_ACL_AUTHORIZATION_DB_READ
, openCreds()); 
 712         access().Tokend::ClientSession::findRecordHandle(record
->tokenHandle(), 
 713                 inAttributes
, inAttributesLength
, data
, hKey
, outAttributes
, outAttributesLength
); 
 715         if (hKey 
!= noKey 
&& data
) {            // tokend returned a key reference & data 
 716                 CssmKey 
&keyForm 
= *data
->interpretedAs
<CssmKey
>(CSSMERR_CSP_INVALID_KEY
); 
 717                 key 
= new TokenKey(*this, hKey
, keyForm
.header()); 
 722 void TokenDatabase::tokenInsertRecord(CSSM_DB_RECORDTYPE recordType
, 
 723         const CssmDbRecordAttributeData 
*attributes
, mach_msg_type_number_t attributesLength
, 
 724         const CssmData 
&data
, RefPointer
<Database::Record
> &rRecord
) 
 726         Access 
access(token()); 
 727         RefPointer
<Record
> record 
= new Record(*this); 
 730         validate(CSSM_ACL_AUTHORIZATION_DB_INSERT
, openCreds()); 
 732         access().Tokend::ClientSession::insertRecord(recordType
, 
 733                 attributes
, attributesLength
, data
, record
->tokenHandle()); 
 738 void TokenDatabase::modifyRecord(CSSM_DB_RECORDTYPE recordType
, Database::Record 
*rRecord
, 
 739         const CssmDbRecordAttributeData 
*attributes
, mach_msg_type_number_t attributesLength
, 
 740         const CssmData 
*data
, CSSM_DB_MODIFY_MODE modifyMode
) 
 742         Access 
access(token()); 
 743     TokenDatabase::Record 
*record 
= safe_cast
<TokenDatabase::Record 
*>(rRecord
); 
 746         validate(CSSM_ACL_AUTHORIZATION_DB_MODIFY
, openCreds()); 
 747         record
->validate(CSSM_ACL_AUTHORIZATION_DB_MODIFY
, openCreds()); 
 749         access().Tokend::ClientSession::modifyRecord(recordType
, 
 750                 record
->tokenHandle(), attributes
, attributesLength
, data
, modifyMode
); 
 754 void TokenDatabase::deleteRecord(Database::Record 
*rRecord
) 
 756         Access 
access(token(), *this); 
 757         Record 
*record 
= safe_cast
<Record 
*>(rRecord
); 
 760         validate(CSSM_ACL_AUTHORIZATION_DB_DELETE
, openCreds()); 
 761         record
->validate(CSSM_ACL_AUTHORIZATION_DB_DELETE
, openCreds()); 
 763         access().Tokend::ClientSession::deleteRecord(record
->tokenHandle()); 
 769 // Record/Search object handling 
 771 TokenDatabase::Search::~Search() 
 775                         database().token().tokend().Tokend::ClientSession::releaseSearch(mHandle
); 
 777                         secinfo("tokendb", "%p release search handle %u threw (ignored)", 
 782 TokenDatabase::Record::~Record() 
 786                         database().token().tokend().Tokend::ClientSession::releaseRecord(mHandle
); 
 788                         secinfo("tokendb", "%p release record handle %u threw (ignored)", 
 795 // TokenAcl personality of Record 
 797 AclKind 
TokenDatabase::Record::aclKind() const 
 802 Token 
&TokenDatabase::Record::token() 
 804         return safer_cast
<TokenDatabase 
&>(database()).token(); 
 807 GenericHandle 
TokenDatabase::Record::tokenHandle() const 
 809         return Handler::tokenHandle(); 
 814 // Local utility classes 
 816 void TokenDatabase::InputKey::setup(Key 
*key
) 
 818         if (TokenKey 
*myKey 
= dynamic_cast<TokenKey 
*>(key
)) { 
 820                 mKeyHandle 
= myKey
->tokenHandle(); 
 822         } else if (LocalKey 
*hisKey 
= dynamic_cast<LocalKey 
*>(key
)) { 
 823                 // a local key - turn into raw form 
 824                 CssmClient::WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 825                 wrap(hisKey
->cssmKey(), mKey
); 
 836 TokenDatabase::InputKey::~InputKey() 
 839                 //@@@ Server::csp().freeKey(mKey) ?? 
 840                 Server::csp()->allocator().free(mKey
.keyData());