1/*
2 * Copyright (c) 2000-2006 Apple Computer, 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
38namespace 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//
50class Context : public PodWrapper<Context, CSSM_CONTEXT> {
51public:
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
65public:
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
179public:
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
189public:
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
197public:
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
202public:
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
209protected:
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
216namespace DataWalkers {
217
218
219template <class Action>
220void 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			secdebug("walkers", "invalid attribute (%ux) in context", (unsigned)attr.AttributeType);
248			break;
249		}
250}
251
252template <class Action>
253void 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//
281using namespace DataWalkers;
282
283class Context::Builder {
284protected:
285public:
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
297public:
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	// dynamic attribute type
328    void setup(const CSSM_CONTEXT_ATTRIBUTE &attr)
329	{ slotCount++; walk(sizer, const_cast<CSSM_CONTEXT_ATTRIBUTE &>(attr)); }
330	void setup(const Context::Attr &attr) { setup(static_cast<const CSSM_CONTEXT_ATTRIBUTE &>(attr)); }
331
332    //
333    // Phase 2 (copy) dispatch. Call once for each attribute, in same order as setup().
334    //
335    template <class T>
336    void put(CSSM_ATTRIBUTE_TYPE type, const T *p)
337    {
338        if (p) {
339            assert(slot < slotCount);			// check overflow
340            Attr &attribute = attributes[slot++];
341            attribute.AttributeType = type;
342            attribute.AttributeLength =  (uint32)size(p); //@@@ needed? how/when/what for?
343            T *tmp = const_cast<T *>(p);
344            attribute = walk(copier, tmp);
345        }
346    }
347    void put(CSSM_ATTRIBUTE_TYPE type, uint32 value)
348    {
349        if (value) {
350            assert(slot < slotCount);			// check overflow
351            Attr &attribute = attributes[slot++];
352            attribute.AttributeType = type;
353            attribute.AttributeLength = 0;		//@@@ unclear what that should be
354            attribute = value;					// no heap data (immediate value)
355        }
356    }
357	void put(const CSSM_CONTEXT_ATTRIBUTE &attr)
358	{
359		assert(slot < slotCount);
360		Attr &attribute = attributes[slot++];
361		attribute = attr;	// shallow copy
362		walk(copier, attribute);	// deep copy
363	}
364	void put(const Context::Attr &attr) { put(static_cast<const CSSM_CONTEXT_ATTRIBUTE &>(attr)); }
365
366private:
367    // pass 1 state: collect sizes and counts
368    unsigned slotCount;					// count of attribute slots in use
369	SizeWalker sizer;					// memory size calculator
370
371    // pass 2 state: build the data set
372    Context::Attr *attributes;			// attribute vector and start of block
373	CopyWalker copier;					// data copy engine
374    uint32 slot;						// writer slot position
375};
376
377} // end namespace Security
378
379#endif //_H_CONTEXT
380