]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2006,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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)); | |
427c49bc | 77 | AttributeLength = (uint32_t) (size ? size : sizeof(T)); |
b1ab9ed8 A |
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) throw(std::bad_alloc) | |
191 | { return alloc.malloc(size); } | |
192 | void operator delete (void *addr, size_t, Allocator &alloc) throw() | |
193 | { return alloc.free(addr); } | |
194 | static void destroy(Context *context, Allocator &alloc) throw() | |
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: | |
fa7225c8 | 247 | secinfo("walkers", "invalid attribute (%ux) in context", (unsigned)attr.AttributeType); |
b1ab9ed8 A |
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 | ||
d8f41ccd A |
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 | ||
b1ab9ed8 A |
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; | |
427c49bc | 367 | attribute.AttributeLength = (uint32)size(p); //@@@ needed? how/when/what for? |
b1ab9ed8 A |
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 |