X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utilities/lib/acl_preauth.cpp?ds=inline diff --git a/Security/libsecurity_cdsa_utilities/lib/acl_preauth.cpp b/Security/libsecurity_cdsa_utilities/lib/acl_preauth.cpp new file mode 100644 index 00000000..121b2a27 --- /dev/null +++ b/Security/libsecurity_cdsa_utilities/lib/acl_preauth.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2000-2004,2006-2007,2011,2013 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The 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. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// acl_preauth - a subject type for modeling PINs and similar slot-specific +// pre-authentication schemes. +// +#include "acl_preauth.h" +#include + + +namespace Security { +namespace PreAuthorizationAcls { + + +// +// Origin forms +// +AclSubject *OriginMaker::make(const TypedList &list) const +{ + ListElement *args[1]; + crack(list, 1, args, CSSM_LIST_ELEMENT_WORDID); + return new OriginAclSubject(*args[0]); +} + +AclSubject *OriginMaker::make(AclSubject::Version version, Reader &pub, Reader &) const +{ + // just an integer containing the auth tag + Endian auth; + pub(auth); + return new OriginAclSubject(AclAuthorization(auth)); +} + + +// +// Validate the origin form. +// This tries to find the source AclObject and hands the question off to it. +// If anything isn't right, fail the validation. +// +bool OriginAclSubject::validate(const AclValidationContext &ctx) const +{ + if (Environment *env = ctx.environment()) + if (ObjectAcl *source = env->preAuthSource()) + if (source->validates(mAuthTag, ctx.cred(), ctx.environment())) + return true; + + // no joy (the sad default) + return false; +} + + +CssmList OriginAclSubject::toList(Allocator &alloc) const +{ + return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH, + new(alloc) ListElement(mAuthTag)); +} + +OriginAclSubject::OriginAclSubject(AclAuthorization auth) + : AclSubject(CSSM_ACL_SUBJECT_TYPE_PREAUTH), mAuthTag(auth) +{ + if (auth < CSSM_ACL_AUTHORIZATION_PREAUTH_BASE || auth >= CSSM_ACL_AUTHORIZATION_PREAUTH_END) + CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); +} + + +// +// Origin exported form is just a four-byte integer (preauth authorization tag) +// +void OriginAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv) +{ + Endian auth = mAuthTag; + pub(auth); +} + +void OriginAclSubject::exportBlob(Writer &pub, Writer &priv) +{ + Endian auth = mAuthTag; + pub(auth); +} + + +// +// Now for the other side of the coin. +// SourceAclSubjects describe the unusual side (for ACL management) of this game. +// The AclSubject of a preauth source MUST be of PREAUTH_SOURCE type. This subject +// contains the actual validation conditions as a sub-subject, and may provide +// additional information to represent known state of the preauth system. +// +// Think of the extra data in a PreAuthSource ACL as "current state informational" +// that only exists internally, and in the CssmList view. It does not get put into +// persistent (externalized) ACL storage at all. (After all, there's nothing persistent +// about it.) +// +AclSubject *SourceMaker::make(const TypedList &list) const +{ + // minimum requirement: item[1] = sub-subject (sublist) + if (list.length() < 2) + CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); + ListElement &sub = list[1]; + RefPointer subSubject = ObjectAcl::make(sub); + + // anything else is interpreted as tracking state (defaulted if missing) + switch (list.length()) { + case 2: // no tracking state + return new SourceAclSubject(subSubject); + case 3: + if (list[2].type() == CSSM_LIST_ELEMENT_WORDID) + return new SourceAclSubject(subSubject, list[2]); + // fall through + default: + CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); + } +} + +AclSubject *SourceMaker::make(AclSubject::Version version, Reader &pub, Reader &priv) const +{ + // external form does not contain tracking state - defaults to unknown + RefPointer subSubject = ObjectAcl::importSubject(pub, priv); + return new SourceAclSubject(subSubject); +} + + +// +// Source validation uses its own home-cooked validation context. +// +class SourceValidationContext : public AclValidationContext { +public: + SourceValidationContext(const AclValidationContext &base) + : AclValidationContext(base), mCredTag(base.entryTag()) { } + + uint32 count() const { return cred() ? cred()->samples().length() : 0; } + uint32 size() const { return count(); } + const TypedList &sample(uint32 n) const + { assert(n < count()); return cred()->samples()[n]; } + + const char *credTag() const { return mCredTag; } // override + + void matched(const TypedList *) const { } //@@@ prelim + +private: + const char *mCredTag; +}; + +bool SourceAclSubject::SourceAclSubject::validate(const AclValidationContext &baseCtx) const +{ + // try to authenticate our sub-subject + if (Environment *env = baseCtx.environment()) { + AclAuthorization auth = baseCtx.authorization(); + if (!CSSM_ACL_AUTHORIZATION_IS_PREAUTH(auth)) // all muddled up; bail + CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); + uint32 slot = CSSM_ACL_AUTHORIZATION_PREAUTH_SLOT(auth); + secdebug("preauth", "using state %d@%p", slot, &env->store(this)); + bool &accepted = env->store(this).attachment((void *)((size_t) slot)).accepted; + if (!accepted) { + secdebug("preauth", "%p needs to authenticate its subject", this); + SourceValidationContext ctx(baseCtx); + if (mSourceSubject->validate(ctx)) { + secdebug("preauth", "%p pre-authenticated", this); + accepted = true; + } + } + return accepted; + } + return false; +} + + +CssmList SourceAclSubject::toList(Allocator &alloc) const +{ + return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE, + new(alloc) ListElement(mSourceSubject->toList(alloc))); +} + + +SourceAclSubject::SourceAclSubject(AclSubject *subSubject, CSSM_ACL_PREAUTH_TRACKING_STATE state) + : AclSubject(CSSM_ACL_SUBJECT_TYPE_PREAUTH), + mSourceSubject(subSubject) +{ +} + + +// +// Export the subject to a memory blob +// +void SourceAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv) +{ + mSourceSubject->exportBlob(pub, priv); +} + +void SourceAclSubject::exportBlob(Writer &pub, Writer &priv) +{ + mSourceSubject->exportBlob(pub, priv); + // tracking state is not exported +} + + +#ifdef DEBUGDUMP + +void OriginAclSubject::debugDump() const +{ + Debug::dump("Preauth(to slot %d)", mAuthTag - CSSM_ACL_AUTHORIZATION_PREAUTH_BASE); +} + +void SourceAclSubject::debugDump() const +{ + Debug::dump("Preauth source: "); + if (mSourceSubject) + mSourceSubject->debugDump(); + else + Debug::dump("NULL?"); +} + +#endif //DEBUGDUMP + + +} // namespace PreAuthorizationAcls +} // namespace Security