X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_cdsa_utilities/lib/cssmdata.h diff --git a/OSX/libsecurity_cdsa_utilities/lib/cssmdata.h b/OSX/libsecurity_cdsa_utilities/lib/cssmdata.h new file mode 100644 index 00000000..eee84a0a --- /dev/null +++ b/OSX/libsecurity_cdsa_utilities/lib/cssmdata.h @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2000-2006,2011-2012,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// cssmdata.h -- Manager different CssmData types +// +#ifndef _H_CDSA_UTILITIES_CSSMDATA +#define _H_CDSA_UTILITIES_CSSMDATA + +#include +#include +#include +#include +#include + +namespace Security { + + +// +// User-friendlier CSSM_DATA thingies. +// CssmData is a PODWrapper for CSSM_DATA, but is also used throughout +// the security code as a "byte blob" representation. +// +class CssmData : public PodWrapper { +public: + CssmData() { Data = 0; Length = 0; } + + size_t length() const { return Length; } + void *data() const { return Data; } + void *end() const { return Data + Length; } + + // + // Create a CssmData from any pointer-to-byte-sized-object and length. + // + CssmData(void *data, size_t length) + { Data = reinterpret_cast(data); Length = length; } + CssmData(char *data, size_t length) + { Data = reinterpret_cast(data); Length = length; } + CssmData(unsigned char *data, size_t length) + { Data = reinterpret_cast(data); Length = length; } + CssmData(signed char *data, size_t length) + { Data = reinterpret_cast(data); Length = length; } + + CssmData(CFDataRef cf) + { Data = const_cast(CFDataGetBytePtr(cf)); Length = CFDataGetLength(cf); } + + // the void * form accepts too much; explicitly deny all other types + private: template CssmData(T *, size_t); public: + + // explicitly construct from a data-oid source + template + explicit CssmData(const T &obj) + { Data = (UInt8 *)obj.data(); Length = obj.length(); } + + // + // Do allow generic "wrapping" of any data structure, but make it conspicuous + // since it's not necessarily the Right Thing (alignment and byte order wise). + // Also note that the T & form removes const-ness, since there is no ConstCssmData. + // + template + static CssmData wrap(const T &it) + { return CssmData(const_cast(reinterpret_cast(&it)), sizeof(it)); } + + template + static CssmData wrap(T *data, size_t length) + { return CssmData(const_cast(static_cast(data)), length); } + + // + // Automatically convert a CssmData to any pointer-to-byte-sized-type. + // + operator signed char * () const { return reinterpret_cast(Data); } + operator unsigned char * () const { return reinterpret_cast(Data); } + operator char * () const { return reinterpret_cast(Data); } + operator void * () const { return reinterpret_cast(Data); } + + // + // If you want to interpret the contents of a CssmData blob as a particular + // type, you have to be more explicit to show that you know what you're doing. + // See wrap() above. + // + template + T *interpretedAs() const { return reinterpret_cast(Data); } + + template + T *interpretedAs(CSSM_RETURN error) const + { return interpretedAs(sizeof(T), error); } + + template + T *interpretedAs(size_t len, CSSM_RETURN error) const + { + if (data() == NULL || length() != len) CssmError::throwMe(error); + return interpretedAs(); + } + +public: + void length(size_t newLength) // shorten only + { assert(newLength <= Length); Length = newLength; } + + void *at(off_t offset) const + { assert(offset >= 0 && (CSSM_SIZE)offset <= Length); return Data + offset; } + void *at(off_t offset, size_t size) const // length-checking version + { assert(offset >= 0 && (CSSM_SIZE)offset + size <= Length); return Data + offset; } + + template T *at(off_t offset) const { return reinterpret_cast(at(offset)); } + template T *at(off_t offset, size_t size) const + { return reinterpret_cast(at(offset, size)); } + + unsigned char byte(off_t offset) const { return *at(offset); } + unsigned char &byte(off_t offset) { return *at(offset); } + + void *use(size_t taken) // logically remove some bytes + { assert(taken <= Length); void *r = Data; Length -= taken; Data += taken; return r; } + + void clear() + { Data = NULL; Length = 0; } + + string toString () const; // convert to string type (no trailing null) + string toHex() const; // hex string of binary blob + string toOid() const; // standard OID string encoding (1.2.3...) + void fromHex(const char *digits); // fill myself with hex data (no allocation) + + operator bool () const { return Data != NULL; } + bool operator ! () const { return Data == NULL; } + bool operator < (const CssmData &other) const; + bool operator == (const CssmData &other) const + { return length() == other.length() && !memcmp(data(), other.data(), length()); } + bool operator != (const CssmData &other) const + { return !(*this == other); } + + // Extract fixed-format data from a CssmData. Fixes any alignment trouble for you. + template + void extract(T &destination, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA) const + { + if (length() != sizeof(destination) || data() == NULL) + CssmError::throwMe(error); + memcpy(&destination, data(), sizeof(destination)); + } +}; + + +inline bool CssmData::operator < (const CssmData &other) const +{ + if (Length != other.Length) // If lengths are not equal the shorter data is smaller. + return Length < other.Length; + if (Length == 0) // If lengths are both zero ignore the Data. + return false; + if (Data == NULL || other.Data == NULL) // arbitrary (but consistent) ordering + return Data < other.Data; + return memcmp(Data, other.Data, Length) < 0; // Do a lexicographic compare on equal sized Data. +} + + +// +// CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics. +// +typedef CssmData CssmOid; + + +// +// A convenient way to make a CssmData from a (const) string. +// Note that the underlying string is not memory-managed, so it +// should either be static or of sufficient (immutable) lifetime. +// +class StringData : public CssmData { +public: + StringData(const char *s) : CssmData(const_cast(s), strlen(s)) { } + StringData(const std::string &s) : CssmData(const_cast(s.c_str()), s.size()) { } +}; + + +// +// A CssmData bundled up with a data buffer it refers to +// +template +struct DataBuffer : public CssmData { + unsigned char buffer[size]; + DataBuffer() : CssmData(buffer, size) { } +}; + + +// +// Comparing CssmDatas for equality. +// Note: No ordering is established here. +// Both CSSM_DATAs have to exist. +// +bool operator == (const CSSM_DATA &d1, const CSSM_DATA &d2); +inline bool operator != (const CSSM_DATA &d1, const CSSM_DATA &d2) +{ return !(d1 == d2); } + + +// +// The following pseudo-code describes what (at minimum) is required for a class +// to be a "PseudoData". PseudoData arguments ("DataOids") are used in templates. +// +// class PseudoData { +// void *data() const ... +// size_t length() const ... +// operator const CssmData &() const ... +// } +// +// All this can be satisfied, of course, by inheriting from CssmData. +// + + +// +// A common virtual parent for CssmData-like objects that actively manage the +// allocation status of their data blob. Note that this is about allocating +// the data(), not the CssmData structure itself. +// The ManagedData layer provides for little active memory management, since +// the underlying strategies are potentially very disparate. It does however +// have a well defined interface for *yielding up* its data for copying or transfer. +// +class CssmManagedData { +public: + CssmManagedData(Allocator &alloc) : allocator(alloc) { } + virtual ~CssmManagedData(); + + Allocator &allocator; + + virtual operator const CssmData & () const { return get(); } + template T *data() const { return reinterpret_cast(data()); } + void *data() const { return get().data(); } + size_t length() const { return get().length(); } + + virtual CssmData &get() const throw() = 0; // get shared copy, no ownership change + virtual CssmData release() = 0; // give up copy, ownership is transferred + virtual void reset() = 0; // give up copy, data is discarded +}; + + +inline bool operator == (const CssmManagedData &d1, const CssmData &d2) +{ return d1.get() == d2; } + +inline bool operator == (const CssmData &d1, const CssmManagedData &d2) +{ return d1 == d2.get(); } + +inline bool operator == (const CssmManagedData &d1, const CssmManagedData &d2) +{ return d1.get() == d2.get(); } + +inline bool operator != (const CssmManagedData &d1, const CssmData &d2) +{ return d1.get() != d2; } + +inline bool operator != (const CssmData &d1, const CssmManagedData &d2) +{ return d1 != d2.get(); } + +inline bool operator != (const CssmManagedData &d1, const CssmManagedData &d2) +{ return d1.get() != d2.get(); } + + +// +// A CssmOwnedData is a CssmManagedData that unilaterally owns its data storage. +// It has its CssmData object provided during construction. +// +class CssmOwnedData : public CssmManagedData { +public: + CssmOwnedData(Allocator &alloc, CssmData &mine) : CssmManagedData(alloc), referent(mine) { } + + CssmOwnedData(Allocator &alloc, CSSM_DATA &mine) + : CssmManagedData(alloc), referent(CssmData::overlay(mine)) { referent.clear(); } + + // + // Basic retrievals (this echoes features of CssmData) + // + operator void * () const { return referent; } + operator char * () const { return referent; } + operator signed char * () const { return referent; } + operator unsigned char * () const { return referent; } + + operator bool () const { return referent; } + bool operator ! () const { return !referent; } + + size_t length() const { return referent.length(); } + + + // + // Basic allocators + // + void *malloc(size_t len) + { + // pseudo-atomic reallocation semantics + CssmAutoPtr alloc(allocator, allocator.malloc(len)); + reset(); + return referent = CssmData(alloc.release(), len); + } + + void *realloc(size_t newLen) + { + // Allocator::realloc() should be pseudo-atomic (i.e. throw on error) + return referent = CssmData(allocator.realloc(referent.data(), newLen), newLen); + } + + void length(size_t len) { realloc(len); } + + + // + // Manipulate existing data + // + void *append(const void *addData, size_t addLength) + { + size_t oldLength = length(); + realloc(oldLength + addLength); + return memcpy(referent.at(oldLength), addData, addLength); + } + + void *append(const CssmData &data) + { return append(data.data(), data.length()); } + + + // + // set() replaces current data with new, taking over ownership to the extent possible. + // + template + void set(T *data, size_t length) + { + // assume that data was allocated by our allocator -- we can't be sure + reset(); + referent = CssmData(data, length); + } + + void set(CssmManagedData &source); + void set(const CSSM_DATA &source) { set(source.Data, source.Length); } + // NOTE: General template set() cannot be used because all subclasses of CssmManagedData + // need to receive the special handling above. Use set(*.data(), *.length()) instead. + + + // + // copy() replaces current data with new, making a copy and leaving + // the source intact. + // + template + void copy(const T *data, size_t length) + { + CssmAutoPtr newData(allocator, memcpy(allocator.malloc(length), data, length)); + reset(); + referent = CssmData(newData.release(), length); + } + + void copy(const CssmData &source) + { if (&source != &referent) copy(source.data(), source.length()); } + void copy(const CSSM_DATA &source) + { if (&source != &referent) copy(source.Data, source.Length); } + void copy(CssmManagedData &source) { copy(source.get()); } + template + void copy(const Data &source) { copy(source.data(), source.length()); } + + + // + // Assignment conservatively uses copy if allocator unknown, set if known + // + void operator = (CssmManagedData &source) { set(source); } + void operator = (CssmOwnedData &source) { set(source); } + void operator = (const CSSM_DATA &source) { copy(source); } + + CssmData &get() const throw(); + +public: + void fromOid(const char *oid); // fill from text OID form (1.2.3...) + +protected: + CssmData &referent; +}; + + +// +// A CssmAutoData is a CssmOwnedData that includes its CssmData object. +// This is the very simple case: The object includes ownership, data object, +// and data storage. +// +class CssmAutoData : public CssmOwnedData { +public: + CssmAutoData(Allocator &alloc) : CssmOwnedData(alloc, mData) { } + + template + CssmAutoData(Allocator &alloc, const Data &source) : CssmOwnedData(alloc, mData) + { *this = source; } + + CssmAutoData(CssmAutoData &source) : CssmOwnedData(source.allocator, mData) + { set(source); } + + explicit CssmAutoData(CssmManagedData &source) : CssmOwnedData(source.allocator, mData) + { set(source); } + + CssmAutoData(Allocator &alloc, const void *data, size_t length) + : CssmOwnedData(alloc, mData) { copy(data, length); } + + ~CssmAutoData() { allocator.free(mData); } + + CssmData release(); + void reset(); + + // assignment (not usefully inherited) + void operator = (CssmManagedData &source) { set(source); } + void operator = (CssmOwnedData &source) { set(source); } + void operator = (CssmAutoData &source) { set(source); } + template + void operator = (const Data &source) { copy(source); } + +private: + CssmData mData; +}; + + +// +// A CssmRemoteData is a CssmOwnedData that uses an external CssmData object. +// Its release operation clears an internal ownership flag but does not clear +// the CssmData values so they can be used to return values to an outside scope. +// +class CssmRemoteData : public CssmOwnedData { +public: + CssmRemoteData(Allocator &alloc, CssmData &mine) + : CssmOwnedData(alloc, mine), iOwnTheData(true) { } + + CssmRemoteData(Allocator &alloc, CSSM_DATA &mine) + : CssmOwnedData(alloc, mine), iOwnTheData(true) { } + + ~CssmRemoteData() + { if (iOwnTheData) allocator.free(referent); } + + CssmData release(); + void reset(); + + // assignment (not usefully inherited) + void operator = (CssmManagedData &source) { set(source); } + void operator = (CssmOwnedData &source) { set(source); } + void operator = (CssmAutoData &source) { set(source); } + template + void operator = (const Data &source) { copy(source); } + +private: + bool iOwnTheData; +}; + + +// +// CssmPolyData +// +// Used by functions that take a CssmData and would like to allow it to be +// initialized with a static string, int or other basic type. The function *must* +// copy the Data of the CssmPolyData when doing so if it is to be used +// after the function returns. (For example by creating a CssmDataContainer from it). +class CssmPolyData : public CssmData { + template + uint8 *set(const T &it) + { return const_cast(reinterpret_cast(&it)); } +public: + template + CssmPolyData(const char_T *s) : CssmData(const_cast(s), strlen(s)) {} + CssmPolyData(const string &s) : CssmData(const_cast(s.c_str()), s.size()) {} + CssmPolyData(const CSSM_DATA &data) : CssmData(data.Data, data.Length) {} + + // Don't use a template constructor (for T &) here - it would eat way too much + CssmPolyData(const bool &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const uint32 &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const sint32 &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const sint64 &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const double &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const unsigned long &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const CSSM_GUID &t) : CssmData(set(t), sizeof(t)) { } + CssmPolyData(const StringPtr s) : CssmData (reinterpret_cast(s + 1), uint32 (s[0])) {} +}; + +class CssmDateData : public CssmData +{ +public: + CssmDateData(const CSSM_DATE &date); +private: + uint8 buffer[8]; +}; + + +// +// Non POD refcounted CssmData wrapper that own the data it refers to. +// +class CssmDataContainer : public CssmData, public RefCount +{ +public: + CssmDataContainer(Allocator &inAllocator = Allocator::standard()) : + CssmData(), mAllocator(inAllocator) {} + template + CssmDataContainer(const T *data, size_t length, Allocator &inAllocator = Allocator::standard()) : + CssmData(inAllocator.malloc(length), length), mAllocator(inAllocator) + { if (length) ::memcpy(Data, data, length); } + void clear() { if (Data) { mAllocator.free(Data); Data = NULL; Length = 0; } } + void invalidate () {Data = NULL; Length = 0;} + ~CssmDataContainer() { if (Data) mAllocator.free(Data); } + void append(const CssmPolyData &data) + { + size_t newLength = Length + data.Length; + Data = reinterpret_cast(mAllocator.realloc(Data, newLength)); + memcpy(Data + Length, data.Data, data.Length); + Length = newLength; + } + CssmDataContainer(const CssmDataContainer &other) + : mAllocator(other.mAllocator) + { + Data = reinterpret_cast(mAllocator.malloc(other.Length)); + memcpy(Data, other.Data, other.Length); + Length = other.Length; + } + CssmDataContainer & operator = (const CSSM_DATA &other) + { + clear(); + Data = reinterpret_cast(mAllocator.malloc(other.Length)); + memcpy(Data, other.Data, other.Length); + Length = other.Length; + return *this; + } + +public: + Allocator &mAllocator; + +private: + operator CssmDataContainer * () const; // prohibit conversion-to-my-pointer +}; + +// +// CSSM_OIDs are CSSM_DATAs but will probably have different wrapping characteristics. +// +typedef CssmDataContainer CssmOidContainer; + +template +class CssmBuffer : public RefPointer +{ +public: + CssmBuffer() : RefPointer(new Container()) {} // XXX This should may just set ptr to NULL. + template + CssmBuffer(const T *data, size_t length, Allocator &inAllocator = Allocator::standard()) : + RefPointer(new Container(data, length, inAllocator)) {} + CssmBuffer(const CSSM_DATA &data, Allocator &inAllocator = Allocator::standard()) : + RefPointer(new Container(data.Data, data.Length, inAllocator)) {} + CssmBuffer(const CssmBuffer& other) : RefPointer(other) {} + CssmBuffer(Container *p) : RefPointer(p) {} + bool operator < (const CssmBuffer &other) const { return (**this) < (*other); } +}; + + +} // end namespace Security + +#endif // _H_CDSA_UTILITIES_CSSMDATA