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