]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utilities/lib/acl_preauth.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_utilities / lib / acl_preauth.cpp
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
33 namespace Security {
34 namespace PreAuthorizationAcls {
35
36
37 //
38 // Origin forms
39 //
40 AclSubject *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
47 AclSubject *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 //
61 bool OriginAclSubject::validates(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
73 CssmList OriginAclSubject::toList(Allocator &alloc) const
74 {
75 return TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH,
76 new(alloc) ListElement(mAuthTag));
77 }
78
79 OriginAclSubject::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 //
90 void OriginAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv)
91 {
92 Endian<uint32> auth = mAuthTag;
93 pub(auth);
94 }
95
96 void 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 //
115 AclSubject *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
136 AclSubject *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 //
147 class SourceValidationContext : public AclValidationContext {
148 public:
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
161 private:
162 const char *mCredTag;
163 };
164
165 bool SourceAclSubject::SourceAclSubject::validates(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 secinfo("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 secinfo("preauth", "%p needs to authenticate its subject", this);
177 SourceValidationContext ctx(baseCtx);
178 if (mSourceSubject->validates(ctx)) {
179 secinfo("preauth", "%p pre-authenticated", this);
180 accepted = true;
181 }
182 }
183 return accepted;
184 }
185 return false;
186 }
187
188
189 CssmList 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
196 SourceAclSubject::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 //
206 void SourceAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv)
207 {
208 mSourceSubject->exportBlob(pub, priv);
209 }
210
211 void 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
220 void OriginAclSubject::debugDump() const
221 {
222 Debug::dump("Preauth(to slot %d)", mAuthTag - CSSM_ACL_AUTHORIZATION_PREAUTH_BASE);
223 }
224
225 void 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