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// cssmdata.h -- Manager different CssmData types
27//
28#ifndef _H_CDSA_UTILITIES_CSSMDATA
29#define _H_CDSA_UTILITIES_CSSMDATA
30
31#include <security_utilities/alloc.h>
32#include <security_utilities/refcount.h>
33#include <security_cdsa_utilities/cssmerrors.h>
34#include <Security/cssmerr.h>
35#include <CoreFoundation/CoreFoundation.h>
36
37namespace Security {
38
39
40//
41// User-friendlier CSSM_DATA thingies.
42// CssmData is a PODWrapper for CSSM_DATA, but is also used throughout
43// the security code as a "byte blob" representation.
44//
45class CssmData : public PodWrapper<CssmData, CSSM_DATA> {
46public:
47    CssmData() { Data = 0; Length = 0; }
48
49    size_t length() const { return Length; }
50    void *data() const { return Data; }
51    void *end() const { return Data + Length; }
52
53	//
54	// Create a CssmData from any pointer-to-byte-sized-object and length.
55	//
56	CssmData(void *data, size_t length)
57	{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
58	CssmData(char *data, size_t length)
59	{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
60	CssmData(unsigned char *data, size_t length)
61	{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
62	CssmData(signed char *data, size_t length)
63	{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
64
65	CssmData(CFDataRef cf)
66	{ Data = const_cast<UInt8 *>(CFDataGetBytePtr(cf)); Length = CFDataGetLength(cf); }
67
68	// the void * form accepts too much; explicitly deny all other types
69	private: template <class T> CssmData(T *, size_t); public:
70
71	// explicitly construct from a data-oid source
72	template <class T>
73	explicit CssmData(const T &obj)
74	{ Data = (UInt8 *)obj.data(); Length = obj.length(); }
75
76	//
77	// Do allow generic "wrapping" of any data structure, but make it conspicuous
78	// since it's not necessarily the Right Thing (alignment and byte order wise).
79	// Also note that the T & form removes const-ness, since there is no ConstCssmData.
80	//
81	template <class T>
82	static CssmData wrap(const T &it)
83	{ return CssmData(const_cast<void *>(reinterpret_cast<const void *>(&it)), sizeof(it)); }
84
85	template <class T>
86	static CssmData wrap(T *data, size_t length)
87	{ return CssmData(const_cast<void *>(static_cast<const void *>(data)), length); }
88
89	//
90	// Automatically convert a CssmData to any pointer-to-byte-sized-type.
91	//
92	operator signed char * () const { return reinterpret_cast<signed char *>(Data); }
93	operator unsigned char * () const { return reinterpret_cast<unsigned char *>(Data); }
94	operator char * () const { return reinterpret_cast<char *>(Data); }
95	operator void * () const { return reinterpret_cast<void *>(Data); }
96
97	//
98	// If you want to interpret the contents of a CssmData blob as a particular
99	// type, you have to be more explicit to show that you know what you're doing.
100	// See wrap() above.
101	//
102	template <class T>
103	T *interpretedAs() const		{ return reinterpret_cast<T *>(Data); }
104
105	template <class T>
106	T *interpretedAs(CSSM_RETURN error) const
107	{ return interpretedAs<T>(sizeof(T), error); }
108
109	template <class T>
110	T *interpretedAs(size_t len, CSSM_RETURN error) const
111	{
112		if (data() == NULL || length() != len) CssmError::throwMe(error);
113		return interpretedAs<T>();
114	}
115
116public:
117    void length(size_t newLength)	// shorten only
118    { assert(newLength <= Length); Length = newLength; }
119
120	void *at(off_t offset) const
121	{ assert(offset >= 0 && (CSSM_SIZE)offset <= Length); return Data + offset; }
122	void *at(off_t offset, size_t size) const	// length-checking version
123	{ assert(offset >= 0 && (CSSM_SIZE)offset + size <= Length); return Data + offset; }
124
125	template <class T> T *at(off_t offset) const { return reinterpret_cast<T *>(at(offset)); }
126	template <class T> T *at(off_t offset, size_t size) const
127	{ return reinterpret_cast<T *>(at(offset, size)); }
128
129	unsigned char byte(off_t offset) const { return *at<unsigned char>(offset); }
130	unsigned char &byte(off_t offset) { return *at<unsigned char>(offset); }
131
132    void *use(size_t taken)			// logically remove some bytes
133    { assert(taken <= Length); void *r = Data; Length -= taken; Data += taken; return r; }
134
135	void clear()
136	{ Data = NULL; Length = 0; }
137
138    string toString () const;	// convert to string type (no trailing null)
139	string toHex() const;		// hex string of binary blob
140	string toOid() const;		// standard OID string encoding (1.2.3...)
141	void fromHex(const char *digits); // fill myself with hex data (no allocation)
142
143    operator bool () const { return Data != NULL; }
144    bool operator ! () const { return Data == NULL; }
145    bool operator < (const CssmData &other) const;
146	bool operator == (const CssmData &other) const
147	{ return length() == other.length() && !memcmp(data(), other.data(), length()); }
148	bool operator != (const CssmData &other) const
149	{ return !(*this == other); }
150
151    // Extract fixed-format data from a CssmData. Fixes any alignment trouble for you.
152    template <class T>
153    void extract(T &destination, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA) const
154    {
155        if (length() != sizeof(destination) || data() == NULL)
156            CssmError::throwMe(error);
157        memcpy(&destination, data(), sizeof(destination));
158    }
159};
160
161
162inline bool CssmData::operator < (const CssmData &other) const
163{
164    if (Length != other.Length) // If lengths are not equal the shorter data is smaller.
165        return Length < other.Length;
166    if (Length == 0) // If lengths are both zero ignore the Data.
167        return false;
168    if (Data == NULL || other.Data == NULL)	// arbitrary (but consistent) ordering
169        return Data < other.Data;
170    return memcmp(Data, other.Data, Length) < 0; // Do a lexicographic compare on equal sized Data.
171}
172
173
174//
175// CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics.
176//
177typedef CssmData CssmOid;
178
179
180//
181// A convenient way to make a CssmData from a (const) string.
182// Note that the underlying string is not memory-managed, so it
183// should either be static or of sufficient (immutable) lifetime.
184//
185class StringData : public CssmData {
186public:
187    StringData(const char *s) : CssmData(const_cast<char *>(s), strlen(s)) { }
188	StringData(const std::string &s) : CssmData(const_cast<char *>(s.c_str()), s.size()) { }
189};
190
191
192//
193// A CssmData bundled up with a data buffer it refers to
194//
195template <size_t size>
196struct DataBuffer : public CssmData {
197	unsigned char buffer[size];
198	DataBuffer() : CssmData(buffer, size) { }
199};
200
201
202//
203// Comparing CssmDatas for equality.
204// Note: No ordering is established here.
205// Both CSSM_DATAs have to exist.
206//
207bool operator == (const CSSM_DATA &d1, const CSSM_DATA &d2);
208inline bool operator != (const CSSM_DATA &d1, const CSSM_DATA &d2)
209{ return !(d1 == d2); }
210
211
212//
213// The following pseudo-code describes what (at minimum) is required for a class
214// to be a "PseudoData". PseudoData arguments ("DataOids") are used in templates.
215//
216// class PseudoData {
217//	void *data() const ...
218//  size_t length() const ...
219//  operator const CssmData &() const ...
220// }
221//
222// All this can be satisfied, of course, by inheriting from CssmData.
223//
224
225
226//
227// A common virtual parent for CssmData-like objects that actively manage the
228// allocation status of their data blob. Note that this is about allocating
229// the data(), not the CssmData structure itself.
230// The ManagedData layer provides for little active memory management, since
231// the underlying strategies are potentially very disparate. It does however
232// have a well defined interface for *yielding up* its data for copying or transfer.
233//
234class CssmManagedData {
235public:
236	CssmManagedData(Allocator &alloc) : allocator(alloc) { }
237	virtual ~CssmManagedData();
238
239	Allocator &allocator;
240
241	virtual operator const CssmData & () const { return get(); }
242	template <class T> T *data() const	{ return reinterpret_cast<T *>(data()); }
243	void *data() const					{ return get().data(); }
244	size_t length() const				{ return get().length(); }
245
246	virtual CssmData &get() const throw() = 0; // get shared copy, no ownership change
247	virtual CssmData release() = 0;		// give up copy, ownership is transferred
248	virtual void reset() = 0;			// give up copy, data is discarded
249};
250
251
252inline bool operator == (const CssmManagedData &d1, const CssmData &d2)
253{ return d1.get() == d2; }
254
255inline bool operator == (const CssmData &d1, const CssmManagedData &d2)
256{ return d1 == d2.get(); }
257
258inline bool operator == (const CssmManagedData &d1, const CssmManagedData &d2)
259{ return d1.get() == d2.get(); }
260
261inline bool operator != (const CssmManagedData &d1, const CssmData &d2)
262{ return d1.get() != d2; }
263
264inline bool operator != (const CssmData &d1, const CssmManagedData &d2)
265{ return d1 != d2.get(); }
266
267inline bool operator != (const CssmManagedData &d1, const CssmManagedData &d2)
268{ return d1.get() != d2.get(); }
269
270
271//
272// A CssmOwnedData is a CssmManagedData that unilaterally owns its data storage.
273// It has its CssmData object provided during construction.
274//
275class CssmOwnedData : public CssmManagedData {
276public:
277	CssmOwnedData(Allocator &alloc, CssmData &mine) : CssmManagedData(alloc), referent(mine) { }
278
279	CssmOwnedData(Allocator &alloc, CSSM_DATA &mine)
280	: CssmManagedData(alloc), referent(CssmData::overlay(mine)) { referent.clear(); }
281
282	//
283	// Basic retrievals (this echoes features of CssmData)
284	//
285	operator void * () const		{ return referent; }
286	operator char * () const		{ return referent; }
287	operator signed char * () const	 { return referent; }
288	operator unsigned char * () const { return referent; }
289
290	operator bool () const			{ return referent; }
291	bool operator ! () const		{ return !referent; }
292
293	size_t length() const			{ return referent.length(); }
294
295
296	//
297	// Basic allocators
298	//
299	void *malloc(size_t len)
300	{
301		// pseudo-atomic reallocation semantics
302		CssmAutoPtr<uint8> alloc(allocator, allocator.malloc<uint8>(len));
303		reset();
304		return referent = CssmData(alloc.release(), len);
305	}
306
307	void *realloc(size_t newLen)
308	{
309		// Allocator::realloc() should be pseudo-atomic (i.e. throw on error)
310		return referent = CssmData(allocator.realloc<uint8>(referent.data(), newLen), newLen);
311	}
312
313	void length(size_t len)			{ realloc(len); }
314
315
316	//
317	// Manipulate existing data
318	//
319	void *append(const void *addData, size_t addLength)
320	{
321		size_t oldLength = length();
322		realloc(oldLength + addLength);
323		return memcpy(referent.at(oldLength), addData, addLength);
324	}
325
326	void *append(const CssmData &data)
327	{ return append(data.data(), data.length()); }
328
329
330	//
331	// set() replaces current data with new, taking over ownership to the extent possible.
332	//
333	template <class T>
334	void set(T *data, size_t length)
335	{
336		// assume that data was allocated by our allocator -- we can't be sure
337		reset();
338		referent = CssmData(data, length);
339	}
340
341	void set(CssmManagedData &source);
342	void set(const CSSM_DATA &source)	{ set(source.Data, source.Length); }
343	// NOTE: General template set() cannot be used because all subclasses of CssmManagedData
344	// need to receive the special handling above. Use set(*.data(), *.length()) instead.
345
346
347	//
348	// copy() replaces current data with new, making a copy and leaving
349	// the source intact.
350	//
351	template <class T>
352	void copy(const T *data, size_t length)
353	{
354		// don't leave any open windows for Mr. Murphy
355		CssmAutoPtr<void> newData(allocator, memcpy(allocator.malloc(length), data, length));
356		reset();
357		referent = CssmData(newData.release(), length);
358	}
359
360	void copy(const CssmData &source)
361	{ if (&source != &referent) copy(source.data(), source.length()); }
362	void copy(const CSSM_DATA &source)
363	{ if (&source != &referent) copy(source.Data, source.Length); }
364	void copy(CssmManagedData &source)		{ copy(source.get()); }
365	template <class Data>
366	void copy(const Data &source)			{ copy(source.data(), source.length()); }
367
368
369	//
370	// Assignment conservatively uses copy if allocator unknown, set if known
371	//
372	void operator = (CssmManagedData &source) { set(source); }
373	void operator = (CssmOwnedData &source) { set(source); }
374	void operator = (const CSSM_DATA &source) { copy(source); }
375
376	CssmData &get() const throw();
377
378public:
379	void fromOid(const char *oid);		// fill from text OID form (1.2.3...)
380
381protected:
382	CssmData &referent;
383};
384
385
386//
387// A CssmAutoData is a CssmOwnedData that includes its CssmData object.
388// This is the very simple case: The object includes ownership, data object,
389// and data storage.
390//
391class CssmAutoData : public CssmOwnedData {
392public:
393	CssmAutoData(Allocator &alloc) : CssmOwnedData(alloc, mData) { }
394
395	template <class Data>
396	CssmAutoData(Allocator &alloc, const Data &source) : CssmOwnedData(alloc, mData)
397	{ *this = source; }
398
399    CssmAutoData(CssmAutoData &source) : CssmOwnedData(source.allocator, mData)
400    { set(source); }
401
402	explicit CssmAutoData(CssmManagedData &source) : CssmOwnedData(source.allocator, mData)
403	{ set(source); }
404
405	CssmAutoData(Allocator &alloc, const void *data, size_t length)
406	: CssmOwnedData(alloc, mData)	{ copy(data, length); }
407
408	~CssmAutoData()					{ allocator.free(mData); }
409
410	CssmData release();
411	void reset();
412
413	// assignment (not usefully inherited)
414	void operator = (CssmManagedData &source)		{ set(source); }
415	void operator = (CssmOwnedData &source)			{ set(source); }
416	void operator = (CssmAutoData &source)			{ set(source); }
417	template <class Data>
418	void operator = (const Data &source)			{ copy(source); }
419
420private:
421	CssmData mData;
422};
423
424
425//
426// A CssmRemoteData is a CssmOwnedData that uses an external CssmData object.
427// Its release operation clears an internal ownership flag but does not clear
428// the CssmData values so they can be used to return values to an outside scope.
429//
430class CssmRemoteData : public CssmOwnedData {
431public:
432	CssmRemoteData(Allocator &alloc, CssmData &mine)
433	: CssmOwnedData(alloc, mine), iOwnTheData(true) { }
434
435	CssmRemoteData(Allocator &alloc, CSSM_DATA &mine)
436	: CssmOwnedData(alloc, mine), iOwnTheData(true) { }
437
438	~CssmRemoteData()
439	{ if (iOwnTheData) allocator.free(referent); }
440
441	CssmData release();
442	void reset();
443
444	// assignment (not usefully inherited)
445	void operator = (CssmManagedData &source)		{ set(source); }
446	void operator = (CssmOwnedData &source)			{ set(source); }
447	void operator = (CssmAutoData &source)			{ set(source); }
448	template <class Data>
449	void operator = (const Data &source)			{ copy(source); }
450
451private:
452	bool iOwnTheData;
453};
454
455
456//
457// CssmPolyData
458//
459// Used by functions that take a CssmData and would like to allow it to be
460// initialized with a static string, int or other basic type.  The function *must*
461// copy the Data of the CssmPolyData when doing so if it is to be used
462// after the function returns.  (For example by creating a CssmDataContainer from it).
463class CssmPolyData : public CssmData {
464	template <class T>
465	uint8 *set(const T &it)
466	{ return const_cast<uint8 *>(reinterpret_cast<const uint8 *>(&it)); }
467public:
468	template <class char_T>
469	CssmPolyData(const char_T *s) : CssmData(const_cast<char_T *>(s), strlen(s)) {}
470	CssmPolyData(const string &s) : CssmData(const_cast<char *>(s.c_str()), s.size()) {}
471	CssmPolyData(const CSSM_DATA &data) : CssmData(data.Data, data.Length) {}
472
473	// Don't use a template constructor (for T &) here - it would eat way too much
474	CssmPolyData(const bool &t) : CssmData(set(t), sizeof(t)) { }
475	CssmPolyData(const uint32 &t) : CssmData(set(t), sizeof(t)) { }
476	CssmPolyData(const sint32 &t) : CssmData(set(t), sizeof(t)) { }
477	CssmPolyData(const sint64 &t) : CssmData(set(t), sizeof(t)) { }
478	CssmPolyData(const double &t) : CssmData(set(t), sizeof(t)) { }
479	CssmPolyData(const unsigned long &t) : CssmData(set(t), sizeof(t)) { }
480	CssmPolyData(const CSSM_GUID &t) : CssmData(set(t), sizeof(t)) { }
481	CssmPolyData(const StringPtr s) : CssmData (reinterpret_cast<char*>(s + 1), uint32 (s[0])) {}
482};
483
484class CssmDateData : public CssmData
485{
486public:
487	CssmDateData(const CSSM_DATE &date);
488private:
489	uint8 buffer[8];
490};
491
492
493//
494// Non POD refcounted CssmData wrapper that own the data it refers to.
495//
496class CssmDataContainer : public CssmData, public RefCount
497{
498public:
499    CssmDataContainer(Allocator &inAllocator = Allocator::standard()) :
500	CssmData(), mAllocator(inAllocator) {}
501	template <class T>
502    CssmDataContainer(const T *data, size_t length, Allocator &inAllocator = Allocator::standard()) :
503	CssmData(inAllocator.malloc(length), length), mAllocator(inAllocator)
504	{ if (length) ::memcpy(Data, data, length); }
505	void clear() { if (Data) { mAllocator.free(Data); Data = NULL; Length = 0; } }
506	void invalidate () {Data = NULL; Length = 0;}
507	~CssmDataContainer() { if (Data) mAllocator.free(Data); }
508	void append(const CssmPolyData &data)
509	{
510		size_t newLength = Length + data.Length;
511		Data = reinterpret_cast<uint8 *>(mAllocator.realloc(Data, newLength));
512		memcpy(Data + Length, data.Data, data.Length);
513		Length = newLength;
514	}
515	CssmDataContainer(const CssmDataContainer &other)
516	: mAllocator(other.mAllocator)
517	{
518		Data = reinterpret_cast<uint8 *>(mAllocator.malloc(other.Length));
519		memcpy(Data, other.Data, other.Length);
520		Length = other.Length;
521	}
522	CssmDataContainer & operator = (const CSSM_DATA &other)
523	{
524		clear();
525		Data = reinterpret_cast<uint8 *>(mAllocator.malloc(other.Length));
526		memcpy(Data, other.Data, other.Length);
527		Length = other.Length;
528		return *this;
529	}
530
531public:
532	Allocator &mAllocator;
533
534private:
535	operator CssmDataContainer * () const;  // prohibit conversion-to-my-pointer
536};
537
538//
539// CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics.
540//
541typedef CssmDataContainer CssmOidContainer;
542
543template <class Container>
544class CssmBuffer : public RefPointer<Container>
545{
546public:
547    CssmBuffer() : RefPointer<Container>(new Container()) {} // XXX This should may just set ptr to NULL.
548	template <class T>
549    CssmBuffer(const T *data, size_t length, Allocator &inAllocator = Allocator::standard()) :
550	RefPointer<Container>(new Container(data, length, inAllocator)) {}
551    CssmBuffer(const CSSM_DATA &data, Allocator &inAllocator = Allocator::standard()) :
552	RefPointer<Container>(new Container(data.Data, data.Length, inAllocator)) {}
553	CssmBuffer(const CssmBuffer& other) : RefPointer<Container>(other) {}
554	CssmBuffer(Container *p) : RefPointer<Container>(p) {}
555	bool operator < (const CssmBuffer &other) const { return (**this) < (*other); }
556};
557
558
559} // end namespace Security
560
561#endif // _H_CDSA_UTILITIES_CSSMDATA
562