]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utilities/lib/context.h
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_utilities / lib / context.h
1 /*
2 * Copyright (c) 2000-2006,2011-2012,2014 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 // context - CSSM cryptographic context objects
27 //
28 #ifndef _H_CONTEXT
29 #define _H_CONTEXT
30
31 #include <security_utilities/utilities.h>
32 #include <security_utilities/debugging.h>
33 #include <security_cdsa_utilities/cssmalloc.h>
34 #include <security_cdsa_utilities/cssmwalkers.h>
35 #include <security_cdsa_utilities/cssmacl.h> // to serialize/copy access credentials
36 #include <security_cdsa_utilities/cssmdates.h>
37
38 namespace Security {
39
40
41 //
42 // Context is a POD overlay for the CSSM_CONTEXT type. It does
43 // add allocation functions and lots of good stuff.
44 // Note that if you're outside CSSM proper, you are not supposed to
45 // memory-manage Context structures on your own. Be a good boy and
46 // call the CSSM API functions.
47 // We also provide a POD overlay for CSSM_CONTEXT_ATTRIBUTE, with
48 // the obvious semantics.
49 //
50 class Context : public PodWrapper<Context, CSSM_CONTEXT> {
51 public:
52 Context(CSSM_CONTEXT_TYPE type, CSSM_ALGORITHMS algorithmId);
53
54 uint32 attributesInUse() const { return NumberOfAttributes; }
55 CSSM_CONTEXT_TYPE type() const { return ContextType; }
56 CSSM_ALGORITHMS algorithm() const { return AlgorithmType; }
57 CSSM_CSP_HANDLE cspHandle() const { return CSPHandle; }
58
59 void deleteAttribute(CSSM_ATTRIBUTE_TYPE type);
60 size_t copyAttributes(CSSM_CONTEXT_ATTRIBUTE * &attrs, uint32 &count, Allocator &alloc) const;
61
62 void copyFrom(const Context &source, Allocator &alloc)
63 { source.copyAttributes(ContextAttributes, NumberOfAttributes, alloc); }
64
65 public:
66 class Attr : public PodWrapper<Attr, CSSM_CONTEXT_ATTRIBUTE> {
67 public:
68 Attr() { }
69 Attr(const CSSM_CONTEXT_ATTRIBUTE &attr) { (CSSM_CONTEXT_ATTRIBUTE &)*this = attr; }
70
71 template <class T>
72 Attr(CSSM_ATTRIBUTE_TYPE typ, T &value, size_t size = 0)
73 {
74 AttributeType = typ;
75 // attribute component pointers are stupidly non-const; allow const input
76 Attribute.String = const_cast<char *>(reinterpret_cast<const char *>(&value));
77 AttributeLength = (uint32_t) (size ? size : sizeof(T));
78 }
79
80 Attr(CSSM_ATTRIBUTE_TYPE typ, uint32 value)
81 {
82 AttributeType = typ;
83 Attribute.Uint32 = value;
84 AttributeLength = 0;
85 }
86
87 CSSM_ATTRIBUTE_TYPE type() const { return AttributeType; }
88 uint32 baseType() const { return AttributeType & CSSM_ATTRIBUTE_TYPE_MASK; }
89
90 operator char * () const
91 { assert(baseType() == CSSM_ATTRIBUTE_DATA_STRING); return Attribute.String; }
92 operator CssmData & () const
93 { assert(baseType() == CSSM_ATTRIBUTE_DATA_CSSM_DATA);
94 return CssmData::overlay(*Attribute.Data); }
95 operator CssmCryptoData & () const
96 { assert(baseType() == CSSM_ATTRIBUTE_DATA_CRYPTO_DATA);
97 return CssmCryptoData::overlay(*Attribute.CryptoData); }
98 operator CssmKey & () const
99 { assert(baseType() == CSSM_ATTRIBUTE_DATA_KEY); return CssmKey::overlay(*Attribute.Key); }
100 operator AccessCredentials & () const
101 { assert(baseType() == CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS);
102 return AccessCredentials::overlay(*Attribute.AccessCredentials); }
103 operator uint32 () const
104 { assert(baseType() == CSSM_ATTRIBUTE_DATA_UINT32); return Attribute.Uint32; }
105 operator CSSM_DL_DB_HANDLE &() const
106 {
107 assert(baseType() == CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE);
108 if (Attribute.DLDBHandle == NULL)
109 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE);
110 return *Attribute.DLDBHandle;
111 }
112 operator CssmDate & () const
113 { assert(baseType() == CSSM_ATTRIBUTE_DATA_DATE);
114 return CssmDate::overlay(*Attribute.Date); }
115 // @@@ etc. etc. - add yours today!
116
117 void operator = (uint32 value) { Attribute.Uint32 = value; }
118 template <class T>
119 void operator = (T *ptr) { Attribute.String = reinterpret_cast<char *>(ptr); }
120
121 IFDUMP(void dump() const;) // debug dump this Attr to stdout (one line)
122 };
123
124 // Attributes by position
125 Attr *attributes() const { return Attr::overlay(ContextAttributes); }
126 Attr &operator [] (unsigned int ix)
127 { assert(ix < NumberOfAttributes); return static_cast<Attr &>(ContextAttributes[ix]); }
128 const Attr &operator [] (unsigned int ix) const
129 { assert(ix < NumberOfAttributes); return static_cast<Attr &>(ContextAttributes[ix]); }
130
131 // general attribute retrieval by type
132 Attr *find(CSSM_ATTRIBUTE_TYPE theType) const
133 { return find(theType, ContextAttributes, NumberOfAttributes); }
134
135 template <class Elem>
136 Elem &get(CSSM_ATTRIBUTE_TYPE type, CSSM_RETURN err) const
137 {
138 if (Attr *attr = find(type))
139 return static_cast<Elem &>(*attr);
140 else
141 CssmError::throwMe(err);
142 }
143
144 template <class Elem>
145 Elem *get(CSSM_ATTRIBUTE_TYPE type) const
146 {
147 if (Attr *attr = find(type))
148 // @@@ Invoking conversion operator to Elem & on *attr and taking address of result.
149 return &static_cast<Elem &>(*attr);
150 else
151 return NULL;
152 }
153
154 uint32 getInt(CSSM_ATTRIBUTE_TYPE type, CSSM_RETURN err) const
155 {
156 if (Attr *attr = find(type))
157 return static_cast<uint32>(*attr);
158 else
159 CssmError::throwMe(err);
160 }
161
162 uint32 getInt(CSSM_ATTRIBUTE_TYPE type) const
163 {
164 if (Attr *attr = find(type))
165 return static_cast<uint32>(*attr);
166 else
167 return 0;
168 }
169
170 bool getInt(CSSM_ATTRIBUTE_TYPE type, uint32 &value) const
171 {
172 if (Attr *attr = find(type)) {
173 value = static_cast<uint32>(*attr);
174 return true;
175 } else
176 return false;
177 }
178
179 public:
180 template <class T>
181 void replace(CSSM_ATTRIBUTE_TYPE type, const T &newValue) const
182 {
183 if (Attr *attr = find(type))
184 *attr = Attr(type, newValue);
185 else
186 CssmError::throwMe(CSSMERR_CSSM_ATTRIBUTE_NOT_IN_CONTEXT);
187 }
188
189 public:
190 void *operator new (size_t size, Allocator &alloc)
191 { return alloc.malloc(size); }
192 void operator delete (void *addr, size_t, Allocator &alloc) _NOEXCEPT
193 { return alloc.free(addr); }
194 static void destroy(Context *context, Allocator &alloc) _NOEXCEPT
195 { alloc.free(context->ContextAttributes); alloc.free(context); }
196
197 public:
198 // Post-IPC context fixup.
199 // This can only be called on a Built Context after IPC transmission.
200 void postIPC(void *base, CSSM_CONTEXT_ATTRIBUTE *ipcAttributes);
201
202 public:
203 class Builder;
204
205 // dump to stdout, multiline format
206 IFDUMP(void dump(const char *title = NULL,
207 const CSSM_CONTEXT_ATTRIBUTE *attrs = NULL) const;)
208
209 protected:
210 // find an attribute in a plain array of attribute structures (no context)
211 static Attr *find(CSSM_ATTRIBUTE_TYPE theType,
212 const CSSM_CONTEXT_ATTRIBUTE *attrs, unsigned int count);
213 };
214
215
216 namespace DataWalkers {
217
218
219 template <class Action>
220 void walk(Action &operate, CSSM_CONTEXT_ATTRIBUTE &attr)
221 {
222 operate(attr);
223 if (attr.Attribute.String) // non-NULL pointer (imprecise but harmless)
224 switch (attr.AttributeType & CSSM_ATTRIBUTE_TYPE_MASK) {
225 case CSSM_ATTRIBUTE_DATA_CSSM_DATA:
226 walk(operate, attr.Attribute.Data); break;
227 case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA:
228 walk(operate, attr.Attribute.CryptoData); break;
229 case CSSM_ATTRIBUTE_DATA_KEY:
230 walk(operate, attr.Attribute.Key); break;
231 case CSSM_ATTRIBUTE_DATA_STRING:
232 walk(operate, attr.Attribute.String); break;
233 case CSSM_ATTRIBUTE_DATA_DATE:
234 walk(operate, attr.Attribute.Date); break;
235 case CSSM_ATTRIBUTE_DATA_RANGE:
236 walk(operate, attr.Attribute.Range); break;
237 case CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS:
238 walk(operate, attr.Attribute.AccessCredentials); break;
239 case CSSM_ATTRIBUTE_DATA_VERSION:
240 walk(operate, attr.Attribute.Version); break;
241 case CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE:
242 walk(operate, attr.Attribute.DLDBHandle); break;
243 case CSSM_ATTRIBUTE_NONE:
244 case CSSM_ATTRIBUTE_DATA_UINT32:
245 break;
246 default:
247 secinfo("walkers", "invalid attribute (%ux) in context", (unsigned)attr.AttributeType);
248 break;
249 }
250 }
251
252 template <class Action>
253 void walk(Action &operate, Context::Attr &attr)
254 {
255 walk(operate, static_cast<CSSM_CONTEXT_ATTRIBUTE &>(attr));
256 }
257
258 } // end namespace DataWalkers
259
260
261 //
262 // Context::Builder - make context attributes the fun way.
263 //
264 // A Context (aka CSSM_CONTEXT) has a pointer to an array of context attributes,
265 // most of which contain pointers to other stuff with pointers to God Knows Where.
266 // Instead of allocating this all over the heap, a Context::Builder performs
267 // a two-pass algorithm that places all that stuff into a single heap node.
268 // Specifically, the builder will allocate and create a vector of CSSM_CONTEXT_ATTRIBUTE
269 // structures and all their subordinate heap storage.
270 // A Builder does not deal in Context objects and does not care what you do with your
271 // CSSM_CONTEXT_ATTRIBUTE array once it's delivered. Since it's a single heap node,
272 // you can just free() it using the appropriate allocator when you're done with it.
273 //
274 // Theory of operation:
275 // Builder works in two phases, called scan and build. During scan, you call setup()
276 // with the desired data to be placed into the attribute vector. When done, call make()
277 // to switch to build phase. Then call put() with the SAME sequence of values as in phase 1.
278 // Finally, call done() to receive the pointer-and-count values.
279 // @@@ Add comment about IPC use.
280 //
281 using namespace DataWalkers;
282
283 class Context::Builder {
284 protected:
285 public:
286 Builder(Allocator &alloc) : allocator(alloc)
287 { slotCount = 0; attributes = NULL; }
288 ~Builder() { allocator.free(attributes); }
289
290 Allocator &allocator;
291
292 // switch to build phase
293 size_t make();
294 // deliver result
295 void done(CSSM_CONTEXT_ATTRIBUTE * &attributes, uint32 &count);
296
297 public:
298 //
299 // Phase 1 (scan) dispatch. Call once for each attribute needed.
300 //
301 template <class T>
302 void setup(T p, CSSM_RETURN invalidError = CSSM_OK)
303 {
304 if (p) {
305 slotCount++;
306 walk(sizer, unconst_ref_cast(p));
307 } else if (invalidError)
308 CssmError::throwMe(invalidError);
309 }
310
311 void setup(uint32 n, CSSM_RETURN invalidError = CSSM_OK)
312 {
313 if (n)
314 slotCount++;
315 else if (invalidError)
316 CssmError::throwMe(invalidError);
317 }
318
319 void setup(CSSM_SIZE n, CSSM_RETURN invalidError = CSSM_OK)
320 {
321 if (n)
322 slotCount++;
323 else if (invalidError)
324 CssmError::throwMe(invalidError);
325 }
326
327 void setup(const CSSM_KEY *k, CSSM_RETURN invalidError = CSSM_OK)
328 {
329 if (!invalidError) {
330 if (k) {
331 slotCount++;
332 walk(sizer, unconst_ref_cast(k));
333 }
334 return; // no additional validation performed
335 }
336 // perform a basic sanity check of the input CSSM_KEY
337 if (!(k) || (k->KeyHeader.HeaderVersion > CSSM_KEYHEADER_VERSION)) {
338 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
339 }
340 // must not point to an odd address or NULL
341 if (!(k->KeyData.Data) || ((uint64_t)k->KeyData.Data & (uint64_t)1)) {
342 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_POINTER);
343 }
344 // simplistic key data length check
345 if ((k->KeyData.Length < 4) || (k->KeyData.Length > 32768)) {
346 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
347 }
348 slotCount++;
349 walk(sizer, unconst_ref_cast(k));
350 }
351
352 // dynamic attribute type
353 void setup(const CSSM_CONTEXT_ATTRIBUTE &attr)
354 { slotCount++; walk(sizer, const_cast<CSSM_CONTEXT_ATTRIBUTE &>(attr)); }
355 void setup(const Context::Attr &attr) { setup(static_cast<const CSSM_CONTEXT_ATTRIBUTE &>(attr)); }
356
357 //
358 // Phase 2 (copy) dispatch. Call once for each attribute, in same order as setup().
359 //
360 template <class T>
361 void put(CSSM_ATTRIBUTE_TYPE type, const T *p)
362 {
363 if (p) {
364 assert(slot < slotCount); // check overflow
365 Attr &attribute = attributes[slot++];
366 attribute.AttributeType = type;
367 attribute.AttributeLength = (uint32)size(p); //@@@ needed? how/when/what for?
368 T *tmp = const_cast<T *>(p);
369 attribute = walk(copier, tmp);
370 }
371 }
372 void put(CSSM_ATTRIBUTE_TYPE type, uint32 value)
373 {
374 if (value) {
375 assert(slot < slotCount); // check overflow
376 Attr &attribute = attributes[slot++];
377 attribute.AttributeType = type;
378 attribute.AttributeLength = 0; //@@@ unclear what that should be
379 attribute = value; // no heap data (immediate value)
380 }
381 }
382 void put(const CSSM_CONTEXT_ATTRIBUTE &attr)
383 {
384 assert(slot < slotCount);
385 Attr &attribute = attributes[slot++];
386 attribute = attr; // shallow copy
387 walk(copier, attribute); // deep copy
388 }
389 void put(const Context::Attr &attr) { put(static_cast<const CSSM_CONTEXT_ATTRIBUTE &>(attr)); }
390
391 private:
392 // pass 1 state: collect sizes and counts
393 unsigned slotCount; // count of attribute slots in use
394 SizeWalker sizer; // memory size calculator
395
396 // pass 2 state: build the data set
397 Context::Attr *attributes; // attribute vector and start of block
398 CopyWalker copier; // data copy engine
399 uint32 slot; // writer slot position
400 };
401
402 } // end namespace Security
403
404 #endif //_H_CONTEXT