aclclient.cpp
1 /* 2 * Copyright (c) 2000-2001,2007,2011 Apple 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 // aclclient 21 // 22 #include <security_cdsa_client/cssmclient.h> 23 #include <security_cdsa_client/aclclient.h> 24 #include <security_cdsa_client/keyclient.h> 25 #include <security_cdsa_client/keychainacl.h> 26 #include <security_cdsa_utilities/cssmwalkers.h> 27 #include <security_cdsa_utilities/cssmdata.h> 28 #include <security_cdsa_utilities/cssmendian.h> 29 #include <securityd_client/handletypes.h> 30 31 namespace Security { 32 namespace CssmClient { 33 34 static inline void check(CSSM_RETURN rc) 35 { 36 ObjectImpl::check(rc); 37 } 38 39 40 // 41 // AclBearer methods (trivial) 42 // 43 AclBearer::~AclBearer() 44 { } 45 46 47 // 48 // Variant forms of AclBearer implemented in terms of its canonical virtual methods 49 // 50 void AclBearer::addAcl(const AclEntryInput &input, const CSSM_ACCESS_CREDENTIALS *cred) 51 { 52 changeAcl(AclEdit(input), cred); 53 } 54 55 void AclBearer::changeAcl(CSSM_ACL_HANDLE handle, const AclEntryInput &input, 56 const CSSM_ACCESS_CREDENTIALS *cred) 57 { 58 changeAcl(AclEdit(handle, input), cred); 59 } 60 61 void AclBearer::deleteAcl(CSSM_ACL_HANDLE handle, const CSSM_ACCESS_CREDENTIALS *cred) 62 { 63 changeAcl(AclEdit(handle), cred); 64 } 65 66 void AclBearer::deleteAcl(const char *tag, const CSSM_ACCESS_CREDENTIALS *cred) 67 { 68 AutoAclEntryInfoList entries; 69 getAcl(entries, tag); 70 for (uint32 n = 0; n < entries.count(); n++) 71 deleteAcl(entries[n].handle(), cred); 72 } 73 74 75 // 76 // KeyAclBearer implementation 77 // 78 void KeyAclBearer::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const 79 { 80 aclInfos.allocator(allocator); 81 check(CSSM_GetKeyAcl(csp, &key, reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos)); 82 } 83 84 void KeyAclBearer::changeAcl(const CSSM_ACL_EDIT &aclEdit, const CSSM_ACCESS_CREDENTIALS *cred) 85 { 86 check(CSSM_ChangeKeyAcl(csp, AccessCredentials::needed(cred), &aclEdit, &key)); 87 } 88 89 void KeyAclBearer::getOwner(AutoAclOwnerPrototype &owner) const 90 { 91 owner.allocator(allocator); 92 check(CSSM_GetKeyOwner(csp, &key, owner)); 93 } 94 95 void KeyAclBearer::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner, 96 const CSSM_ACCESS_CREDENTIALS *cred) 97 { 98 check(CSSM_ChangeKeyOwner(csp, AccessCredentials::needed(cred), &key, &newOwner)); 99 } 100 101 102 // 103 // A single global structure containing pseudo-static data 104 // 105 struct Statics { 106 Statics(); 107 Allocator &alloc; 108 109 AutoCredentials nullCred; 110 AutoCredentials promptCred; 111 AutoCredentials unlockCred; 112 AutoCredentials cancelCred; 113 AutoCredentials promptedPINCred; 114 AutoCredentials promptedPINItemCred; 115 116 AclOwnerPrototype anyOwner; 117 AclEntryInfo anyAcl; 118 }; 119 120 namespace { 121 ModuleNexus<Statics> statics; 122 } 123 124 125 // 126 // Make pseudo-statics. 127 // Note: This is an eternal object. It is not currently destroyed 128 // if the containing code is unloaded. 129 // 130 Statics::Statics() 131 : alloc(Allocator::standard()), 132 nullCred(alloc, 1), 133 promptCred(alloc, 3), 134 unlockCred(alloc, 1), 135 cancelCred(alloc, 1), 136 promptedPINCred(alloc, 1), 137 promptedPINItemCred(alloc, 1), 138 anyOwner(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY)), 139 anyAcl(AclEntryPrototype(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY), 1)) 140 { 141 // nullCred: nothing at all 142 // contains: 143 // an empty THRESHOLD sample to match threshold subjects with "free" subjects 144 nullCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD); 145 146 // promptCred: a credential permitting user prompt confirmations 147 // contains: 148 // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD 149 // a PROMPTED_PASSWORD sample 150 promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT); 151 promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD, 152 new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT))); 153 promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, 154 new(alloc) ListElement(alloc, CssmData())); 155 156 // unlockCred: ??? 157 unlockCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, 158 new(alloc) ListElement(CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)); 159 160 cancelCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, 161 new(alloc) ListElement(CSSM_WORDID_CANCELED)); 162 163 /* 164 We don't set this: 165 166 promptedPINCred.tag("PIN1"); 167 168 here to avoid triggering code in TokenDatabase::getAcl in securityd that 169 would always show a PIN unlock dialog. This credential is used for an 170 unlock of the database, i.e. a dbauthenticate call to unlock the card. 171 */ 172 promptedPINCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, 173 new(alloc) ListElement(alloc, CssmData())); 174 175 /* 176 This credential is used for items like non-repudiation keys that always 177 require an explicit entry of the PIN. We set this so that Token::authenticate 178 will recognize the number of the PIN we need to unlock. 179 */ 180 promptedPINItemCred.tag("PIN1"); 181 promptedPINItemCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, 182 new(alloc) ListElement(alloc, CssmData())); 183 } 184 185 186 // 187 // Make and break AclFactories 188 // 189 AclFactory::AclFactory() 190 { } 191 192 AclFactory::~AclFactory() 193 { } 194 195 196 // 197 // Return basic pseudo-static values 198 // 199 const AccessCredentials *AclFactory::nullCred() const 200 { return &statics().nullCred; } 201 202 const AccessCredentials *AclFactory::promptCred() const 203 { return &statics().promptCred; } 204 205 const AccessCredentials *AclFactory::unlockCred() const 206 { return &statics().unlockCred; } 207 208 209 const AccessCredentials *AclFactory::cancelCred() const 210 { return &statics().cancelCred; } 211 212 const AccessCredentials *AclFactory::promptedPINCred() const 213 { return &statics().promptedPINCred; } 214 215 const AccessCredentials *AclFactory::promptedPINItemCred() const 216 { return &statics().promptedPINItemCred; } 217 218 219 // 220 // Manage the (pseudo) credentials used to explicitly provide a passphrase to a keychain. 221 // Use the eternal unlockCred() for normal (protected prompt) unlocking. 222 // 223 AclFactory::KeychainCredentials::~KeychainCredentials () 224 { 225 DataWalkers::chunkFree(mCredentials, allocator); 226 } 227 228 AclFactory::PassphraseUnlockCredentials::PassphraseUnlockCredentials (const CssmData& password, 229 Allocator& allocator) : KeychainCredentials(allocator) 230 { 231 mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, 232 new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD), 233 new (allocator) ListElement (CssmAutoData(allocator, password).release())); 234 } 235 236 237 // 238 // Manage the (pseudo) credentials used to explicitly change a keychain's passphrase 239 // 240 AclFactory::PasswordChangeCredentials::PasswordChangeCredentials (const CssmData& password, 241 Allocator& allocator) : KeychainCredentials(allocator) 242 { 243 mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, 244 new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD), 245 new (allocator) ListElement (CssmAutoData(allocator, password).release())); 246 } 247 248 249 // 250 // Manage the (pseudo) credentials used to explicitly provide a master key to a keychain. 251 // 252 AclFactory::MasterKeyUnlockCredentials::MasterKeyUnlockCredentials (const CssmClient::Key& key, 253 Allocator& allocator) : KeychainCredentials(allocator) 254 { 255 // Flatten out this key into: 256 // { h2ni(CSSM_KEY) : raw data for CSSM_KEY } 257 // which is also (on x86_64): 258 // { h2ni(CSSM_KEYHEADER) : 4 byte align : CSSM_DATA{0:0} : raw data for CSSM_KEY } 259 // (placement of alignment bytes uncertain) 260 // 261 // Data format is for consumption by kcdatabase.cpp:unflattenKey() 262 263 size_t dataLen = sizeof(CSSM_KEY) + key->keyData().length(); 264 CssmAutoData flattenedKey(allocator); 265 flattenedKey.malloc(dataLen); 266 memset(flattenedKey, 0, dataLen); 267 268 // The key header must be in network-byte order for some reason 269 CSSM_KEYHEADER header = key->header(); 270 Security::h2ni(header); 271 memcpy(flattenedKey, &header, sizeof(CSSM_KEYHEADER)); 272 memcpy(((uint8_t*) flattenedKey.data()) + sizeof(CSSM_KEY), key->keyData().data(), key->keyData().length()); 273 274 mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, 275 new (allocator) ListElement(CSSM_SAMPLE_TYPE_SYMMETRIC_KEY), 276 new (allocator) ListElement(CssmAutoData(allocator, CssmData::wrap((SecurityServer::KeyHandle) 0)).release()), 277 new (allocator) ListElement(CssmAutoData(allocator, CssmData::wrap(*((const CssmKey*) key))).release()), 278 new (allocator) ListElement(flattenedKey.release())); 279 } 280 281 282 283 // 284 // Wide open ("ANY") CSSM forms for owner and ACL entry 285 // 286 const AclOwnerPrototype &AclFactory::anyOwner() const 287 { return statics().anyOwner; } 288 289 const AclEntryInfo &AclFactory::anyAcl() const 290 { return statics().anyAcl; } 291 292 293 // 294 // Create an ANY style AclEntryInput. 295 // This can be used to explicitly request wide-open authorization on a new CSSM object. 296 // 297 AclFactory::AnyResourceContext::AnyResourceContext(const CSSM_ACCESS_CREDENTIALS *cred) 298 : mAny(CSSM_ACL_SUBJECT_TYPE_ANY), mTag(CSSM_ACL_AUTHORIZATION_ANY) 299 { 300 // set up an ANY/EVERYTHING AclEntryInput 301 input().proto().subject() += &mAny; 302 AuthorizationGroup &authGroup = input().proto().authorization(); 303 authGroup.NumberOfAuthTags = 1; 304 authGroup.AuthTags = &mTag; 305 306 // install the cred (not copied) 307 credentials(cred); 308 } 309 310 311 // 312 // CSSM ACL makers 313 // 314 AclFactory::Subject::Subject(Allocator &alloc, CSSM_ACL_SUBJECT_TYPE type) 315 : TypedList(alloc, type) 316 { } 317 318 319 AclFactory::PWSubject::PWSubject(Allocator &alloc) 320 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD) 321 { } 322 323 AclFactory::PWSubject::PWSubject(Allocator &alloc, const CssmData &secret) 324 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD) 325 { 326 append(new(alloc) ListElement(alloc, secret)); 327 } 328 329 AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt) 330 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD) 331 { 332 append(new(alloc) ListElement(alloc, prompt)); 333 } 334 335 AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt, const CssmData &secret) 336 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD) 337 { 338 append(new(alloc) ListElement(alloc, prompt)); 339 append(new(alloc) ListElement(alloc, secret)); 340 } 341 342 AclFactory::ProtectedPWSubject::ProtectedPWSubject(Allocator &alloc) 343 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROTECTED_PASSWORD) 344 { } 345 346 AclFactory::PinSubject::PinSubject(Allocator &alloc, uint32 slot) 347 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH) 348 { 349 append(new(alloc) ListElement(CSSM_ACL_AUTHORIZATION_PREAUTH(slot))); 350 } 351 352 AclFactory::PinSourceSubject::PinSourceSubject(Allocator &alloc, const TypedList &form) 353 : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE) 354 { 355 append(new(alloc) ListElement(form)); 356 } 357 358 359 } // end namespace CssmClient 360 } // end namespace Security