X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_client/lib/aclclient.cpp diff --git a/Security/libsecurity_cdsa_client/lib/aclclient.cpp b/Security/libsecurity_cdsa_client/lib/aclclient.cpp new file mode 100644 index 00000000..988943fd --- /dev/null +++ b/Security/libsecurity_cdsa_client/lib/aclclient.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2000-2001,2007,2011 Apple Inc. All Rights Reserved. + * + * The contents of this file constitute Original Code as defined in and are + * subject to the Apple Public Source License Version 1.2 (the 'License'). + * You may not use this file except in compliance with the License. Please obtain + * a copy of the License at http://www.apple.com/publicsource and read it before + * using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT + * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the + * specific language governing rights and limitations under the License. + */ + + +// +// aclclient +// +#include +#include +#include +#include +#include + + +namespace Security { +namespace CssmClient { + +static inline void check(CSSM_RETURN rc) +{ + ObjectImpl::check(rc); +} + + +// +// AclBearer methods (trivial) +// +AclBearer::~AclBearer() +{ } + + +// +// Variant forms of AclBearer implemented in terms of its canonical virtual methods +// +void AclBearer::addAcl(const AclEntryInput &input, const CSSM_ACCESS_CREDENTIALS *cred) +{ + changeAcl(AclEdit(input), cred); +} + +void AclBearer::changeAcl(CSSM_ACL_HANDLE handle, const AclEntryInput &input, + const CSSM_ACCESS_CREDENTIALS *cred) +{ + changeAcl(AclEdit(handle, input), cred); +} + +void AclBearer::deleteAcl(CSSM_ACL_HANDLE handle, const CSSM_ACCESS_CREDENTIALS *cred) +{ + changeAcl(AclEdit(handle), cred); +} + +void AclBearer::deleteAcl(const char *tag, const CSSM_ACCESS_CREDENTIALS *cred) +{ + AutoAclEntryInfoList entries; + getAcl(entries, tag); + for (uint32 n = 0; n < entries.count(); n++) + deleteAcl(entries[n].handle(), cred); +} + + +// +// KeyAclBearer implementation +// +void KeyAclBearer::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const +{ + aclInfos.allocator(allocator); + check(CSSM_GetKeyAcl(csp, &key, reinterpret_cast(selectionTag), aclInfos, aclInfos)); +} + +void KeyAclBearer::changeAcl(const CSSM_ACL_EDIT &aclEdit, const CSSM_ACCESS_CREDENTIALS *cred) +{ + check(CSSM_ChangeKeyAcl(csp, AccessCredentials::needed(cred), &aclEdit, &key)); +} + +void KeyAclBearer::getOwner(AutoAclOwnerPrototype &owner) const +{ + owner.allocator(allocator); + check(CSSM_GetKeyOwner(csp, &key, owner)); +} + +void KeyAclBearer::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner, + const CSSM_ACCESS_CREDENTIALS *cred) +{ + check(CSSM_ChangeKeyOwner(csp, AccessCredentials::needed(cred), &key, &newOwner)); +} + + +// +// A single global structure containing pseudo-static data +// +struct Statics { + Statics(); + Allocator &alloc; + + AutoCredentials nullCred; + AutoCredentials promptCred; + AutoCredentials unlockCred; + AutoCredentials cancelCred; + AutoCredentials promptedPINCred; + AutoCredentials promptedPINItemCred; + + AclOwnerPrototype anyOwner; + AclEntryInfo anyAcl; +}; + +namespace { + ModuleNexus statics; +} + + +// +// Make pseudo-statics. +// Note: This is an eternal object. It is not currently destroyed +// if the containing code is unloaded. +// +Statics::Statics() + : alloc(Allocator::standard()), + nullCred(alloc, 1), + promptCred(alloc, 3), + unlockCred(alloc, 1), + cancelCred(alloc, 1), + promptedPINCred(alloc, 1), + promptedPINItemCred(alloc, 1), + anyOwner(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY)), + anyAcl(AclEntryPrototype(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY), 1)) +{ + // nullCred: nothing at all + // contains: + // an empty THRESHOLD sample to match threshold subjects with "free" subjects + nullCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD); + + // promptCred: a credential permitting user prompt confirmations + // contains: + // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD + // a PROMPTED_PASSWORD sample + promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT); + promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD, + new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT))); + promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, + new(alloc) ListElement(alloc, CssmData())); + + // unlockCred: ??? + unlockCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, + new(alloc) ListElement(CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)); + + cancelCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, + new(alloc) ListElement(CSSM_WORDID_CANCELED)); + + /* + We don't set this: + + promptedPINCred.tag("PIN1"); + + here to avoid triggering code in TokenDatabase::getAcl in securityd that + would always show a PIN unlock dialog. This credential is used for an + unlock of the database, i.e. a dbauthenticate call to unlock the card. + */ + promptedPINCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, + new(alloc) ListElement(alloc, CssmData())); + + /* + This credential is used for items like non-repudiation keys that always + require an explicit entry of the PIN. We set this so that Token::authenticate + will recognize the number of the PIN we need to unlock. + */ + promptedPINItemCred.tag("PIN1"); + promptedPINItemCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, + new(alloc) ListElement(alloc, CssmData())); +} + + +// +// Make and break AclFactories +// +AclFactory::AclFactory() +{ } + +AclFactory::~AclFactory() +{ } + + +// +// Return basic pseudo-static values +// +const AccessCredentials *AclFactory::nullCred() const +{ return &statics().nullCred; } + +const AccessCredentials *AclFactory::promptCred() const +{ return &statics().promptCred; } + +const AccessCredentials *AclFactory::unlockCred() const +{ return &statics().unlockCred; } + + +const AccessCredentials *AclFactory::cancelCred() const +{ return &statics().cancelCred; } + +const AccessCredentials *AclFactory::promptedPINCred() const +{ return &statics().promptedPINCred; } + +const AccessCredentials *AclFactory::promptedPINItemCred() const +{ return &statics().promptedPINItemCred; } + + +// +// Manage the (pseudo) credentials used to explicitly provide a passphrase to a keychain. +// Use the eternal unlockCred() for normal (protected prompt) unlocking. +// +AclFactory::KeychainCredentials::~KeychainCredentials () +{ + DataWalkers::chunkFree(mCredentials, allocator); +} + +AclFactory::PassphraseUnlockCredentials::PassphraseUnlockCredentials (const CssmData& password, + Allocator& allocator) : KeychainCredentials(allocator) +{ + mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, + new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD), + new (allocator) ListElement (CssmAutoData(allocator, password).release())); +} + + +// +// Manage the (pseudo) credentials used to explicitly change a keychain's passphrase +// +AclFactory::PasswordChangeCredentials::PasswordChangeCredentials (const CssmData& password, + Allocator& allocator) : KeychainCredentials(allocator) +{ + mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, + new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD), + new (allocator) ListElement (CssmAutoData(allocator, password).release())); +} + + +// +// Wide open ("ANY") CSSM forms for owner and ACL entry +// +const AclOwnerPrototype &AclFactory::anyOwner() const +{ return statics().anyOwner; } + +const AclEntryInfo &AclFactory::anyAcl() const +{ return statics().anyAcl; } + + +// +// Create an ANY style AclEntryInput. +// This can be used to explicitly request wide-open authorization on a new CSSM object. +// +AclFactory::AnyResourceContext::AnyResourceContext(const CSSM_ACCESS_CREDENTIALS *cred) + : mAny(CSSM_ACL_SUBJECT_TYPE_ANY), mTag(CSSM_ACL_AUTHORIZATION_ANY) +{ + // set up an ANY/EVERYTHING AclEntryInput + input().proto().subject() += &mAny; + AuthorizationGroup &authGroup = input().proto().authorization(); + authGroup.NumberOfAuthTags = 1; + authGroup.AuthTags = &mTag; + + // install the cred (not copied) + credentials(cred); +} + + +// +// CSSM ACL makers +// +AclFactory::Subject::Subject(Allocator &alloc, CSSM_ACL_SUBJECT_TYPE type) + : TypedList(alloc, type) +{ } + + +AclFactory::PWSubject::PWSubject(Allocator &alloc) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD) +{ } + +AclFactory::PWSubject::PWSubject(Allocator &alloc, const CssmData &secret) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD) +{ + append(new(alloc) ListElement(alloc, secret)); +} + +AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD) +{ + append(new(alloc) ListElement(alloc, prompt)); +} + +AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt, const CssmData &secret) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD) +{ + append(new(alloc) ListElement(alloc, prompt)); + append(new(alloc) ListElement(alloc, secret)); +} + +AclFactory::ProtectedPWSubject::ProtectedPWSubject(Allocator &alloc) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROTECTED_PASSWORD) +{ } + +AclFactory::PinSubject::PinSubject(Allocator &alloc, uint32 slot) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH) +{ + append(new(alloc) ListElement(CSSM_ACL_AUTHORIZATION_PREAUTH(slot))); +} + +AclFactory::PinSourceSubject::PinSourceSubject(Allocator &alloc, const TypedList &form) + : Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE) +{ + append(new(alloc) ListElement(form)); +} + + +} // end namespace CssmClient +} // end namespace Security