1/* 2 * Copyright (c) 2000-2004,2006-2007,2011,2013 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// acl_preauth - a subject type for modeling PINs and similar slot-specific 27// pre-authentication schemes. 28// 29#include "acl_preauth.h" 30#include <security_utilities/debugging.h> 31 32 33namespace Security { 34namespace PreAuthorizationAcls { 35 36 37// 38// Origin forms 39// 40AclSubject *OriginMaker::make(const TypedList &list) const 41{ 42 ListElement *args[1]; 43 crack(list, 1, args, CSSM_LIST_ELEMENT_WORDID); 44 return new OriginAclSubject(*args[0]); 45} 46 47AclSubject *OriginMaker::make(AclSubject::Version version, Reader &pub, Reader &) const 48{ 49 // just an integer containing the auth tag 50 Endian<uint32> auth; 51 pub(auth); 52 return new OriginAclSubject(AclAuthorization(auth)); 53} 54 55 56// 57// Validate the origin form. 58// This tries to find the source AclObject and hands the question off to it. 59// If anything isn't right, fail the validation. 60// 61bool OriginAclSubject::validate(const AclValidationContext &ctx) const 62{ 63 if (Environment *env = ctx.environment<Environment>()) 64 if (ObjectAcl *source = env->preAuthSource()) 65 if (source->validates(mAuthTag, ctx.cred(), ctx.environment())) 66 return true; 67 68 // no joy (the sad default) 69 return false; 70} 71 72 73CssmList OriginAclSubject::toList(Allocator &alloc) const 74{ 75 return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH, 76 new(alloc) ListElement(mAuthTag)); 77} 78 79OriginAclSubject::OriginAclSubject(AclAuthorization auth) 80 : AclSubject(CSSM_ACL_SUBJECT_TYPE_PREAUTH), mAuthTag(auth) 81{ 82 if (auth < CSSM_ACL_AUTHORIZATION_PREAUTH_BASE || auth >= CSSM_ACL_AUTHORIZATION_PREAUTH_END) 83 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); 84} 85 86 87// 88// Origin exported form is just a four-byte integer (preauth authorization tag) 89// 90void OriginAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv) 91{ 92 Endian<uint32> auth = mAuthTag; 93 pub(auth); 94} 95 96void OriginAclSubject::exportBlob(Writer &pub, Writer &priv) 97{ 98 Endian<uint32> auth = mAuthTag; 99 pub(auth); 100} 101 102 103// 104// Now for the other side of the coin. 105// SourceAclSubjects describe the unusual side (for ACL management) of this game. 106// The AclSubject of a preauth source MUST be of PREAUTH_SOURCE type. This subject 107// contains the actual validation conditions as a sub-subject, and may provide 108// additional information to represent known state of the preauth system. 109// 110// Think of the extra data in a PreAuthSource ACL as "current state informational" 111// that only exists internally, and in the CssmList view. It does not get put into 112// persistent (externalized) ACL storage at all. (After all, there's nothing persistent 113// about it.) 114// 115AclSubject *SourceMaker::make(const TypedList &list) const 116{ 117 // minimum requirement: item[1] = sub-subject (sublist) 118 if (list.length() < 2) 119 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); 120 ListElement &sub = list[1]; 121 RefPointer<AclSubject> subSubject = ObjectAcl::make(sub); 122 123 // anything else is interpreted as tracking state (defaulted if missing) 124 switch (list.length()) { 125 case 2: // no tracking state 126 return new SourceAclSubject(subSubject); 127 case 3: 128 if (list[2].type() == CSSM_LIST_ELEMENT_WORDID) 129 return new SourceAclSubject(subSubject, list[2]); 130 // fall through 131 default: 132 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); 133 } 134} 135 136AclSubject *SourceMaker::make(AclSubject::Version version, Reader &pub, Reader &priv) const 137{ 138 // external form does not contain tracking state - defaults to unknown 139 RefPointer<AclSubject> subSubject = ObjectAcl::importSubject(pub, priv); 140 return new SourceAclSubject(subSubject); 141} 142 143 144// 145// Source validation uses its own home-cooked validation context. 146// 147class SourceValidationContext : public AclValidationContext { 148public: 149 SourceValidationContext(const AclValidationContext &base) 150 : AclValidationContext(base), mCredTag(base.entryTag()) { } 151 152 uint32 count() const { return cred() ? cred()->samples().length() : 0; } 153 uint32 size() const { return count(); } 154 const TypedList &sample(uint32 n) const 155 { assert(n < count()); return cred()->samples()[n]; } 156 157 const char *credTag() const { return mCredTag; } // override 158 159 void matched(const TypedList *) const { } //@@@ prelim 160 161private: 162 const char *mCredTag; 163}; 164 165bool SourceAclSubject::SourceAclSubject::validate(const AclValidationContext &baseCtx) const 166{ 167 // try to authenticate our sub-subject 168 if (Environment *env = baseCtx.environment<Environment>()) { 169 AclAuthorization auth = baseCtx.authorization(); 170 if (!CSSM_ACL_AUTHORIZATION_IS_PREAUTH(auth)) // all muddled up; bail 171 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); 172 uint32 slot = CSSM_ACL_AUTHORIZATION_PREAUTH_SLOT(auth); 173 secdebug("preauth", "using state %d@%p", slot, &env->store(this)); 174 bool &accepted = env->store(this).attachment<AclState>((void *)((size_t) slot)).accepted; 175 if (!accepted) { 176 secdebug("preauth", "%p needs to authenticate its subject", this); 177 SourceValidationContext ctx(baseCtx); 178 if (mSourceSubject->validate(ctx)) { 179 secdebug("preauth", "%p pre-authenticated", this); 180 accepted = true; 181 } 182 } 183 return accepted; 184 } 185 return false; 186} 187 188 189CssmList SourceAclSubject::toList(Allocator &alloc) const 190{ 191 return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE, 192 new(alloc) ListElement(mSourceSubject->toList(alloc))); 193} 194 195 196SourceAclSubject::SourceAclSubject(AclSubject *subSubject, CSSM_ACL_PREAUTH_TRACKING_STATE state) 197 : AclSubject(CSSM_ACL_SUBJECT_TYPE_PREAUTH), 198 mSourceSubject(subSubject) 199{ 200} 201 202 203// 204// Export the subject to a memory blob 205// 206void SourceAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv) 207{ 208 mSourceSubject->exportBlob(pub, priv); 209} 210 211void SourceAclSubject::exportBlob(Writer &pub, Writer &priv) 212{ 213 mSourceSubject->exportBlob(pub, priv); 214 // tracking state is not exported 215} 216 217 218#ifdef DEBUGDUMP 219 220void OriginAclSubject::debugDump() const 221{ 222 Debug::dump("Preauth(to slot %d)", mAuthTag - CSSM_ACL_AUTHORIZATION_PREAUTH_BASE); 223} 224 225void SourceAclSubject::debugDump() const 226{ 227 Debug::dump("Preauth source: "); 228 if (mSourceSubject) 229 mSourceSubject->debugDump(); 230 else 231 Debug::dump("NULL?"); 232} 233 234#endif //DEBUGDUMP 235 236 237} // namespace PreAuthorizationAcls 238} // namespace Security 239