]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_cdsa_utilities/lib/cssmdata.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_cdsa_utilities / lib / cssmdata.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 // 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
37 namespace 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 //
45 class CssmData : public PodWrapper<CssmData, CSSM_DATA> {
46 public:
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
116 public:
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
162 inline 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 //
177 typedef 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 //
185 class StringData : public CssmData {
186 public:
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 //
195 template <size_t size>
196 struct 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 //
207 bool operator == (const CSSM_DATA &d1, const CSSM_DATA &d2);
208 inline 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 //
234 class CssmManagedData {
235 public:
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
252 inline bool operator == (const CssmManagedData &d1, const CssmData &d2)
253 { return d1.get() == d2; }
254
255 inline bool operator == (const CssmData &d1, const CssmManagedData &d2)
256 { return d1 == d2.get(); }
257
258 inline bool operator == (const CssmManagedData &d1, const CssmManagedData &d2)
259 { return d1.get() == d2.get(); }
260
261 inline bool operator != (const CssmManagedData &d1, const CssmData &d2)
262 { return d1.get() != d2; }
263
264 inline bool operator != (const CssmData &d1, const CssmManagedData &d2)
265 { return d1 != d2.get(); }
266
267 inline 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 //
275 class CssmOwnedData : public CssmManagedData {
276 public:
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 CssmAutoPtr<void> newData(allocator, memcpy(allocator.malloc(length), data, length));
355 reset();
356 referent = CssmData(newData.release(), length);
357 }
358
359 void copy(const CssmData &source)
360 { if (&source != &referent) copy(source.data(), source.length()); }
361 void copy(const CSSM_DATA &source)
362 { if (&source != &referent) copy(source.Data, source.Length); }
363 void copy(CssmManagedData &source) { copy(source.get()); }
364 template <class Data>
365 void copy(const Data &source) { copy(source.data(), source.length()); }
366
367
368 //
369 // Assignment conservatively uses copy if allocator unknown, set if known
370 //
371 void operator = (CssmManagedData &source) { set(source); }
372 void operator = (CssmOwnedData &source) { set(source); }
373 void operator = (const CSSM_DATA &source) { copy(source); }
374
375 CssmData &get() const throw();
376
377 public:
378 void fromOid(const char *oid); // fill from text OID form (1.2.3...)
379
380 protected:
381 CssmData &referent;
382 };
383
384
385 //
386 // A CssmAutoData is a CssmOwnedData that includes its CssmData object.
387 // This is the very simple case: The object includes ownership, data object,
388 // and data storage.
389 //
390 class CssmAutoData : public CssmOwnedData {
391 public:
392 CssmAutoData(Allocator &alloc) : CssmOwnedData(alloc, mData) { }
393
394 template <class Data>
395 CssmAutoData(Allocator &alloc, const Data &source) : CssmOwnedData(alloc, mData)
396 { *this = source; }
397
398 CssmAutoData(CssmAutoData &source) : CssmOwnedData(source.allocator, mData)
399 { set(source); }
400
401 explicit CssmAutoData(CssmManagedData &source) : CssmOwnedData(source.allocator, mData)
402 { set(source); }
403
404 CssmAutoData(Allocator &alloc, const void *data, size_t length)
405 : CssmOwnedData(alloc, mData) { copy(data, length); }
406
407 ~CssmAutoData() { allocator.free(mData); }
408
409 CssmData release();
410 void reset();
411
412 // assignment (not usefully inherited)
413 void operator = (CssmManagedData &source) { set(source); }
414 void operator = (CssmOwnedData &source) { set(source); }
415 void operator = (CssmAutoData &source) { set(source); }
416 template <class Data>
417 void operator = (const Data &source) { copy(source); }
418
419 private:
420 CssmData mData;
421 };
422
423
424 //
425 // A CssmRemoteData is a CssmOwnedData that uses an external CssmData object.
426 // Its release operation clears an internal ownership flag but does not clear
427 // the CssmData values so they can be used to return values to an outside scope.
428 //
429 class CssmRemoteData : public CssmOwnedData {
430 public:
431 CssmRemoteData(Allocator &alloc, CssmData &mine)
432 : CssmOwnedData(alloc, mine), iOwnTheData(true) { }
433
434 CssmRemoteData(Allocator &alloc, CSSM_DATA &mine)
435 : CssmOwnedData(alloc, mine), iOwnTheData(true) { }
436
437 ~CssmRemoteData()
438 { if (iOwnTheData) allocator.free(referent); }
439
440 CssmData release();
441 void reset();
442
443 // assignment (not usefully inherited)
444 void operator = (CssmManagedData &source) { set(source); }
445 void operator = (CssmOwnedData &source) { set(source); }
446 void operator = (CssmAutoData &source) { set(source); }
447 template <class Data>
448 void operator = (const Data &source) { copy(source); }
449
450 private:
451 bool iOwnTheData;
452 };
453
454
455 //
456 // CssmPolyData
457 //
458 // Used by functions that take a CssmData and would like to allow it to be
459 // initialized with a static string, int or other basic type. The function *must*
460 // copy the Data of the CssmPolyData when doing so if it is to be used
461 // after the function returns. (For example by creating a CssmDataContainer from it).
462 class CssmPolyData : public CssmData {
463 template <class T>
464 uint8 *set(const T &it)
465 { return const_cast<uint8 *>(reinterpret_cast<const uint8 *>(&it)); }
466 public:
467 template <class char_T>
468 CssmPolyData(const char_T *s) : CssmData(const_cast<char_T *>(s), strlen(s)) {}
469 CssmPolyData(const string &s) : CssmData(const_cast<char *>(s.c_str()), s.size()) {}
470 CssmPolyData(const CSSM_DATA &data) : CssmData(data.Data, data.Length) {}
471
472 // Don't use a template constructor (for T &) here - it would eat way too much
473 CssmPolyData(const bool &t) : CssmData(set(t), sizeof(t)) { }
474 CssmPolyData(const uint32 &t) : CssmData(set(t), sizeof(t)) { }
475 CssmPolyData(const sint32 &t) : CssmData(set(t), sizeof(t)) { }
476 CssmPolyData(const sint64 &t) : CssmData(set(t), sizeof(t)) { }
477 CssmPolyData(const double &t) : CssmData(set(t), sizeof(t)) { }
478 CssmPolyData(const unsigned long &t) : CssmData(set(t), sizeof(t)) { }
479 CssmPolyData(const CSSM_GUID &t) : CssmData(set(t), sizeof(t)) { }
480 CssmPolyData(const StringPtr s) : CssmData (reinterpret_cast<char*>(s + 1), uint32 (s[0])) {}
481 };
482
483 class CssmDateData : public CssmData
484 {
485 public:
486 CssmDateData(const CSSM_DATE &date);
487 private:
488 uint8 buffer[8];
489 };
490
491
492 //
493 // Non POD refcounted CssmData wrapper that own the data it refers to.
494 //
495 class CssmDataContainer : public CssmData, public RefCount
496 {
497 public:
498 CssmDataContainer(Allocator &inAllocator = Allocator::standard()) :
499 CssmData(), mAllocator(inAllocator) {}
500 template <class T>
501 CssmDataContainer(const T *data, size_t length, Allocator &inAllocator = Allocator::standard()) :
502 CssmData(inAllocator.malloc(length), length), mAllocator(inAllocator)
503 { if (length) ::memcpy(Data, data, length); }
504 void clear() { if (Data) { mAllocator.free(Data); Data = NULL; Length = 0; } }
505 void invalidate () {Data = NULL; Length = 0;}
506 ~CssmDataContainer() { if (Data) mAllocator.free(Data); }
507 void append(const CssmPolyData &data)
508 {
509 size_t newLength = Length + data.Length;
510 Data = reinterpret_cast<uint8 *>(mAllocator.realloc(Data, newLength));
511 memcpy(Data + Length, data.Data, data.Length);
512 Length = newLength;
513 }
514 CssmDataContainer(const CssmDataContainer &other)
515 : mAllocator(other.mAllocator)
516 {
517 Data = reinterpret_cast<uint8 *>(mAllocator.malloc(other.Length));
518 memcpy(Data, other.Data, other.Length);
519 Length = other.Length;
520 }
521 CssmDataContainer & operator = (const CSSM_DATA &other)
522 {
523 clear();
524 Data = reinterpret_cast<uint8 *>(mAllocator.malloc(other.Length));
525 memcpy(Data, other.Data, other.Length);
526 Length = other.Length;
527 return *this;
528 }
529
530 public:
531 Allocator &mAllocator;
532
533 private:
534 operator CssmDataContainer * () const; // prohibit conversion-to-my-pointer
535 };
536
537 //
538 // CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics.
539 //
540 typedef CssmDataContainer CssmOidContainer;
541
542 template <class Container>
543 class CssmBuffer : public RefPointer<Container>
544 {
545 public:
546 CssmBuffer() : RefPointer<Container>(new Container()) {} // XXX This should may just set ptr to NULL.
547 template <class T>
548 CssmBuffer(const T *data, size_t length, Allocator &inAllocator = Allocator::standard()) :
549 RefPointer<Container>(new Container(data, length, inAllocator)) {}
550 CssmBuffer(const CSSM_DATA &data, Allocator &inAllocator = Allocator::standard()) :
551 RefPointer<Container>(new Container(data.Data, data.Length, inAllocator)) {}
552 CssmBuffer(const CssmBuffer& other) : RefPointer<Container>(other) {}
553 CssmBuffer(Container *p) : RefPointer<Container>(p) {}
554 bool operator < (const CssmBuffer &other) const { return (**this) < (*other); }
555 };
556
557
558 } // end namespace Security
559
560 #endif // _H_CDSA_UTILITIES_CSSMDATA