2  * Copyright (c) 2000-2001,2008,2011-2012 Apple 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 // SSKey - reference keys for the security server 
  24 #include "SSCSPSession.h" 
  25 #include "SSCSPDLSession.h" 
  26 #include "SSDatabase.h" 
  27 #include "SSDLSession.h" 
  28 #include <security_cdsa_utilities/KeySchema.h> 
  29 #include <security_cdsa_plugin/cssmplugin.h> 
  31 using namespace CssmClient
; 
  32 using namespace SecurityServer
; 
  34 // Constructor for a Security Server generated key. 
  35 SSKey::SSKey(SSCSPSession 
&session
, KeyHandle keyHandle
, CssmKey 
&ioKey
, 
  36                          SSDatabase 
&inSSDatabase
, uint32 inKeyAttr
, 
  37                          const CssmData 
*inKeyLabel
) 
  38 : ReferencedKey(session
.mSSCSPDLSession
), 
  39 mAllocator(session
), mKeyHandle(keyHandle
), 
  40 mClientSession(session
.clientSession()) 
  42         CssmKey::Header 
&header 
= ioKey
.header(); 
  43         if (inKeyAttr 
& CSSM_KEYATTR_PERMANENT
) 
  46                         CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE
); 
  48                 // EncodeKey and store it in the db. 
  49                 CssmDataContainer 
blob(mAllocator
); 
  50                 clientSession().encodeKey(keyHandle
, blob
); 
  52                 assert(header
.HeaderVersion 
== CSSM_KEYHEADER_VERSION
); 
  53                 switch (header
.KeyClass
) 
  55                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
  56                         mRecordType 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
  58                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
  59                         mRecordType 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
  61                 case CSSM_KEYCLASS_SESSION_KEY
: 
  62                         mRecordType 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
  65                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
  73                 // We store the keys real CSP guid on disk 
  74                 CssmGuidData 
creatorGuid(header
.CspId
); 
  75                 CssmDateData 
startDate(header
.StartDate
); 
  76                 CssmDateData 
endDate(header
.EndDate
); 
  78                 DbAttributes 
attributes(inSSDatabase
); 
  79                 attributes
.recordType(mRecordType
); 
  80                 attributes
.add(KeySchema::KeyClass
, mRecordType
); 
  81                 attributes
.add(KeySchema::PrintName
, label
); 
  82                 attributes
.add(KeySchema::Alias
, none
); 
  83                 attributes
.add(KeySchema::Permanent
, 
  84                                            header
.attribute(CSSM_KEYATTR_PERMANENT
)); 
  85                 attributes
.add(KeySchema::Private
, 
  86                                            header
.attribute(CSSM_KEYATTR_PRIVATE
)); 
  87                 attributes
.add(KeySchema::Modifiable
, 
  88                                            header
.attribute(CSSM_KEYATTR_MODIFIABLE
)); 
  89                 attributes
.add(KeySchema::Label
, label
); 
  90                 attributes
.add(KeySchema::ApplicationTag
, none
); 
  91                 attributes
.add(KeySchema::KeyCreator
, creatorGuid
); 
  92                 attributes
.add(KeySchema::KeyType
, header
.AlgorithmId
); 
  93                 attributes
.add(KeySchema::KeySizeInBits
, header
.LogicalKeySizeInBits
); 
  94                 // @@@ Get the real effective key size. 
  95                 attributes
.add(KeySchema::EffectiveKeySize
, header
.LogicalKeySizeInBits
); 
  96                 attributes
.add(KeySchema::StartDate
, startDate
); 
  97                 attributes
.add(KeySchema::EndDate
, endDate
); 
  98                 attributes
.add(KeySchema::Sensitive
, 
  99                                            header
.attribute(CSSM_KEYATTR_SENSITIVE
)); 
 100                 attributes
.add(KeySchema::AlwaysSensitive
, 
 101                                            header
.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE
)); 
 102                 attributes
.add(KeySchema::Extractable
, 
 103                                            header
.attribute(CSSM_KEYATTR_EXTRACTABLE
)); 
 104                 attributes
.add(KeySchema::NeverExtractable
, 
 105                                            header
.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE
)); 
 106                 attributes
.add(KeySchema::Encrypt
, 
 107                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_ENCRYPT
)); 
 108                 attributes
.add(KeySchema::Decrypt
, 
 109                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_DECRYPT
)); 
 110                 attributes
.add(KeySchema::Derive
, 
 111                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_DERIVE
)); 
 112                 attributes
.add(KeySchema::Sign
, 
 113                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_SIGN
)); 
 114                 attributes
.add(KeySchema::Verify
, 
 115                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_VERIFY
)); 
 116                 attributes
.add(KeySchema::SignRecover
, 
 117                                            header
.useFor(CSSM_KEYUSE_ANY
 
 118                                                                          | CSSM_KEYUSE_SIGN_RECOVER
)); 
 119                 attributes
.add(KeySchema::VerifyRecover
, 
 120                                            header
.useFor(CSSM_KEYUSE_ANY
 
 121                                                                          | CSSM_KEYUSE_VERIFY_RECOVER
)); 
 122                 attributes
.add(KeySchema::Wrap
, 
 123                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_WRAP
)); 
 124                 attributes
.add(KeySchema::Unwrap
, 
 125                                            header
.useFor(CSSM_KEYUSE_ANY 
| CSSM_KEYUSE_UNWRAP
)); 
 128                 mUniqueId 
= inSSDatabase
->insert(mRecordType
, &attributes
, &blob
, 
 132         header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me. 
 133         makeReferenceKey(mAllocator
, keyReference(), ioKey
); 
 136 // Constructor for a key retrived from a Db. 
 137 SSKey::SSKey(SSDLSession 
&session
, CssmKey 
&ioKey
, SSDatabase 
&inSSDatabase
, 
 138                          const SSUniqueRecord 
&uniqueId
, CSSM_DB_RECORDTYPE recordType
, 
 140 : ReferencedKey(session
.mSSCSPDLSession
), 
 141 mAllocator(session
.allocator()), mKeyHandle(noKey
), mUniqueId(uniqueId
), 
 142 mRecordType(recordType
), 
 143 mClientSession(session
.clientSession()) 
 145         CssmKey::Header 
&header 
= ioKey
.header(); 
 146         memset(&header
, 0, sizeof(header
)); // Clear key header 
 148         if (!mUniqueId 
|| !mUniqueId
->database()) 
 149                 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); 
 151         header
.HeaderVersion 
= CSSM_KEYHEADER_VERSION
; 
 154         case CSSM_DL_DB_RECORD_PUBLIC_KEY
: 
 155                 header
.KeyClass 
= CSSM_KEYCLASS_PUBLIC_KEY
; 
 157         case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 158                 header
.KeyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
 160         case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 161                 header
.KeyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
 164                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 167         DbAttributes 
attributes(mUniqueId
->database()); 
 168         attributes
.recordType(mRecordType
); 
 169         attributes
.add(KeySchema::KeyClass
);                    // 0 
 170         attributes
.add(KeySchema::Permanent
);                   // 1 
 171         attributes
.add(KeySchema::Private
);                     // 2 
 172         attributes
.add(KeySchema::Modifiable
);                  // 3 
 173         attributes
.add(KeySchema::KeyCreator
);                  // 4 
 174         attributes
.add(KeySchema::KeyType
);                     // 5 
 175         attributes
.add(KeySchema::KeySizeInBits
);               // 6 
 176         attributes
.add(KeySchema::StartDate
);                   // 7 
 177         attributes
.add(KeySchema::EndDate
);                     // 8 
 178         attributes
.add(KeySchema::Sensitive
);                   // 9 
 179         attributes
.add(KeySchema::AlwaysSensitive
);     // 10 
 180         attributes
.add(KeySchema::Extractable
);         // 11 
 181         attributes
.add(KeySchema::NeverExtractable
);    // 12 
 182         attributes
.add(KeySchema::Encrypt
);                     // 13 
 183         attributes
.add(KeySchema::Decrypt
);                     // 14 
 184         attributes
.add(KeySchema::Derive
);                              // 15 
 185         attributes
.add(KeySchema::Sign
);                                // 16 
 186         attributes
.add(KeySchema::Verify
);                              // 17 
 187         attributes
.add(KeySchema::SignRecover
);         // 18 
 188         attributes
.add(KeySchema::VerifyRecover
);               // 19 
 189         attributes
.add(KeySchema::Wrap
);                                // 20 
 190         attributes
.add(KeySchema::Unwrap
);                              // 21 
 192         mUniqueId
->get(&attributes
, NULL
); 
 194         // Assert that the mRecordType matches the KeyClass attribute. 
 195         if (mRecordType 
!= uint32(attributes
[0])) 
 196                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 198         header
.AlgorithmId 
= attributes
[5]; // KeyType 
 199     header
.LogicalKeySizeInBits 
= attributes
[6]; // KeySizeInBits 
 201         if (attributes
[1]) header
.setAttribute(CSSM_KEYATTR_PERMANENT
); 
 202         if (attributes
[2]) header
.setAttribute(CSSM_KEYATTR_PRIVATE
); 
 203         if (attributes
[3]) header
.setAttribute(CSSM_KEYATTR_MODIFIABLE
); 
 204         if (attributes
[9]) header
.setAttribute(CSSM_KEYATTR_SENSITIVE
); 
 205         if (attributes
[11]) header
.setAttribute(CSSM_KEYATTR_EXTRACTABLE
); 
 206         if (attributes
[10]) header
.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE
); 
 207         if (attributes
[12]) header
.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE
); 
 209         if (attributes
[13]) header
.usage(CSSM_KEYUSE_ENCRYPT
); 
 210         if (attributes
[14]) header
.usage(CSSM_KEYUSE_DECRYPT
); 
 211         if (attributes
[15]) header
.usage(CSSM_KEYUSE_DERIVE
); 
 212         if (attributes
[16]) header
.usage(CSSM_KEYUSE_SIGN
); 
 213         if (attributes
[17]) header
.usage(CSSM_KEYUSE_VERIFY
); 
 214         if (attributes
[18]) header
.usage(CSSM_KEYUSE_SIGN_RECOVER
); 
 215         if (attributes
[19]) header
.usage(CSSM_KEYUSE_VERIFY_RECOVER
); 
 216         if (attributes
[20]) header
.usage(CSSM_KEYUSE_WRAP
); 
 217         if (attributes
[21]) header
.usage(CSSM_KEYUSE_UNWRAP
); 
 219         // If all usages are allowed set usage to CSSM_KEYUSE_ANY 
 220         if (header
.usage() == (CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT
 
 221                                                    | CSSM_KEYUSE_DERIVE 
| CSSM_KEYUSE_SIGN
 
 222                                                    | CSSM_KEYUSE_VERIFY 
| CSSM_KEYUSE_SIGN_RECOVER
 
 223                                                    | CSSM_KEYUSE_VERIFY_RECOVER 
| CSSM_KEYUSE_WRAP
 
 224                                                    | CSSM_KEYUSE_UNWRAP
)) 
 225                 header
.usage(CSSM_KEYUSE_ANY
);  
 227         if (!attributes
[7].size() || !attributes
[8].size()) 
 228                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 230     header
.StartDate 
= attributes
[7].at
<CSSM_DATE
>(0); 
 231     header
.EndDate 
= attributes
[8].at
<CSSM_DATE
>(0); 
 233         makeReferenceKey(mAllocator
, keyReference(), ioKey
); 
 234         header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me. 
 239         if (mKeyHandle 
!= noKey
) 
 240                 clientSession().releaseKey(mKeyHandle
); 
 244 SSKey::free(const AccessCredentials 
*accessCred
, CssmKey 
&ioKey
, 
 247         freeReferenceKey(mAllocator
, ioKey
); 
 250                 if (!mUniqueId 
|| !mUniqueId
->database()) 
 251                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 253                 // @@@ Evaluate accessCred against Db acl. 
 254                 // What should we do with accessCred?  Reauthenticate 
 255                 // mUniqueId->database()? 
 256                 mUniqueId
->deleteRecord(); 
 259         if (mKeyHandle 
!= noKey
) 
 261                 clientSession().releaseKey(mKeyHandle
); 
 266 SecurityServer::ClientSession 
& 
 267 SSKey::clientSession() 
 269         return mClientSession
; 
 272 KeyHandle 
SSKey::optionalKeyHandle() const 
 280         if (mKeyHandle 
== noKey
) 
 282                 // Deal with uninstantiated keys. 
 283                 if (!mUniqueId 
|| !mUniqueId
->database()) 
 284                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 286                 CssmDataContainer 
blob(mAllocator
); 
 287                 mUniqueId
->get(NULL
, &blob
); 
 288                 CssmKey::Header dummyHeader
; // @@@ Unused 
 290                         clientSession().decodeKey(mUniqueId
->database().dbHandle(), blob
, 
 293                 // @@@ Check decoded header against returned header 
 300 // ACL retrieval and change operations 
 303 SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE 
&owner
, Allocator 
&allocator
) 
 305         clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner
), 
 310 SSKey::changeOwner(const AccessCredentials 
&accessCred
, 
 311                                    const AclOwnerPrototype 
&newOwner
) 
 313         clientSession().changeKeyOwner(keyHandle(), accessCred
, newOwner
); 
 318 SSKey::getAcl(const char *selectionTag
, uint32 
&numberOfAclInfos
, 
 319                           AclEntryInfo 
*&aclInfos
, Allocator 
&allocator
) 
 321         clientSession().getKeyAcl(keyHandle(), selectionTag
, numberOfAclInfos
, 
 322                                                           aclInfos
, allocator
); 
 326 SSKey::changeAcl(const AccessCredentials 
&accessCred
, const AclEdit 
&aclEdit
) 
 328         clientSession().changeKeyAcl(keyHandle(), accessCred
, aclEdit
); 
 333 SSKey::didChangeAcl() 
 335         if (mUniqueId 
== true) 
 337             secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle
); 
 338                 // The key is persistent, make the change on disk. 
 339                 CssmDataContainer 
keyBlob(mAllocator
); 
 340                 clientSession().encodeKey(keyHandle(), keyBlob
); 
 341                 mUniqueId
->modify(mRecordType
, NULL
, &keyBlob
, CSSM_DB_MODIFY_ATTRIBUTE_NONE
); 
 345             secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle
);