#ifndef _H_UTILITIES
#define _H_UTILITIES
#include <Security/cssm.h>
#include <Security/utility_config.h>
#include <exception>
#include <new>
#include <string>
#include <errno.h>
#include <string.h>
#ifdef _CPP_UTILITIES
#pragma export on
#endif
namespace Security
{
#if defined(NDEBUG)
# define safe_cast static_cast
# define safer_cast static_cast
# define IFDEBUG(it)
# define IFNDEBUG(it) it
#else
template <class Derived, class Base>
inline Derived safer_cast(Base &base)
{
return dynamic_cast<Derived>(base);
}
template <class Derived, class Base>
inline Derived safe_cast(Base *base)
{
if (base == NULL)
return NULL; Derived p = dynamic_cast<Derived>(base);
assert(p);
return p;
}
# define IFDEBUG(it) it
# define IFNDEBUG(it)
#endif //NDEBUG
#define NOCOPY(Type) private: Type(const Type &); void operator = (const Type &);
class CssmCommonError : public std::exception {
protected:
CssmCommonError();
CssmCommonError(const CssmCommonError &source);
public:
virtual ~CssmCommonError() throw ();
virtual CSSM_RETURN cssmError() const = 0;
virtual CSSM_RETURN cssmError(CSSM_RETURN base) const;
virtual OSStatus osStatus() const;
virtual int unixError() const;
protected:
virtual void debugDiagnose(const void *id) const;
private:
IFDEBUG(mutable bool mCarrier); };
class CssmError : public CssmCommonError {
protected:
CssmError(CSSM_RETURN err);
public:
const CSSM_RETURN error;
virtual CSSM_RETURN cssmError() const;
virtual OSStatus osStatus() const;
virtual const char *what () const throw ();
static CSSM_RETURN merge(CSSM_RETURN error, CSSM_RETURN base);
static void check(CSSM_RETURN error) { if (error != CSSM_OK) throwMe(error); }
static void throwMe(CSSM_RETURN error) __attribute__((noreturn));
};
class UnixError : public CssmCommonError {
protected:
UnixError();
UnixError(int err);
public:
const int error;
virtual CSSM_RETURN cssmError() const;
virtual OSStatus osStatus() const;
virtual int unixError() const;
virtual const char *what () const throw ();
static void check(int result) { if (result == -1) throwMe(); }
static void throwMe(int err = errno) __attribute__((noreturn));
static UnixError make(int err = errno);
private:
IFDEBUG(void debugDiagnose(const void *id) const);
};
class MacOSError : public CssmCommonError {
protected:
MacOSError(int err);
public:
const int error;
virtual CSSM_RETURN cssmError() const;
virtual OSStatus osStatus() const;
virtual const char *what () const throw ();
static void check(OSStatus status) { if (status != noErr) throwMe(status); }
static void throwMe(int err) __attribute__((noreturn));
};
#define BEGIN_API try {
#define END_API(base) } \
catch (const CssmCommonError &err) { return err.cssmError(CSSM_ ## base ## _BASE_ERROR); } \
catch (const std::bad_alloc &) { return CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
catch (...) { return CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
return CSSM_OK;
#define END_API0 } catch (...) { return; }
#define END_API1(bad) } catch (...) { return bad; }
template <class T>
inline T &Required(T *ptr, CSSM_RETURN err = CSSM_ERRCODE_INVALID_POINTER)
{
if (ptr == NULL)
CssmError::throwMe(err);
return *ptr;
}
inline void Required(void *ptr, CSSM_RETURN err = CSSM_ERRCODE_INVALID_POINTER)
{
if (ptr == NULL)
CssmError::throwMe(err);
}
template <class Wrapper, class POD>
class PodWrapper : public POD {
public:
static Wrapper * &overlayVar(POD * &data)
{ return reinterpret_cast<Wrapper * &>(data); }
static const Wrapper * &overlayVar(const POD * &data)
{ return reinterpret_cast<const Wrapper * &>(data); }
static Wrapper *overlay(POD *data)
{ return static_cast<Wrapper *>(data); }
static const Wrapper *overlay(const POD *data)
{ return static_cast<const Wrapper *>(data); }
static Wrapper &overlay(POD &data)
{ return static_cast<Wrapper &>(data); }
static const Wrapper &overlay(const POD &data)
{ return static_cast<const Wrapper &>(data); }
static Wrapper &required(POD *data)
{ return overlay(Required(data)); }
static const Wrapper &required(const POD *data)
{ return overlay(Required(data)); }
static Wrapper *optional(POD *data)
{ return overlay(data); }
static const Wrapper *optional(const POD *data)
{ return overlay(data); }
void clearPod()
{ memset(static_cast<POD *>(this), 0, sizeof(POD)); }
};
template <class T>
struct Nonconst {
typedef T Type;
};
template <class U>
struct Nonconst<const U> {
typedef U Type;
};
class Guid : public PodWrapper<Guid, CSSM_GUID> {
public:
Guid() { memset(this, 0, sizeof(*this)) ; }
Guid(const CSSM_GUID &rGuid) { memcpy(this, &rGuid, sizeof(*this)); }
Guid &operator = (const CSSM_GUID &rGuid)
{ memcpy(this, &rGuid, sizeof(CSSM_GUID)); return *this; }
bool operator == (const CSSM_GUID &other) const
{ return (this == &other) || !memcmp(this, &other, sizeof(CSSM_GUID)); }
bool operator != (const CSSM_GUID &other) const
{ return (this != &other) && memcmp(this, &other, sizeof(CSSM_GUID)); }
bool operator < (const CSSM_GUID &other) const
{ return memcmp(this, &other, sizeof(CSSM_GUID)) < 0; }
size_t hash() const { return Data1 + Data2 << 3 + Data3 << 11 + Data4[3] + Data4[6] << 22;
}
static const unsigned stringRepLength = 38; char *toString(char buffer[stringRepLength+1]) const; Guid(const char *string);
};
class CssmSubserviceUid : public PodWrapper<CssmSubserviceUid, CSSM_SUBSERVICE_UID> {
public:
CssmSubserviceUid() { clearPod(); }
CssmSubserviceUid(const CSSM_SUBSERVICE_UID &rSSuid) { memcpy(this, &rSSuid, sizeof(*this)); }
CssmSubserviceUid &operator = (const CSSM_SUBSERVICE_UID &rSSuid)
{ memcpy(this, &rSSuid, sizeof(CSSM_SUBSERVICE_UID)); return *this; }
bool operator == (const CSSM_SUBSERVICE_UID &other) const;
bool operator != (const CSSM_SUBSERVICE_UID &other) const { return !(*this == other); }
bool operator < (const CSSM_SUBSERVICE_UID &other) const;
CssmSubserviceUid(const CSSM_GUID &guid, const CSSM_VERSION *version = NULL,
uint32 subserviceId = 0,
CSSM_SERVICE_TYPE subserviceType = CSSM_SERVICE_DL);
const ::Guid &guid() const { return ::Guid::overlay(Guid); }
uint32 subserviceId() const { return SubserviceId; }
CSSM_SERVICE_TYPE subserviceType() const { return SubserviceType; }
CSSM_VERSION version() const { return Version; }
};
class CssmData : public PodWrapper<CssmData, CSSM_DATA> {
public:
CssmData() { Data = 0; Length = 0; }
size_t length() const { return Length; }
void *data() const { return Data; }
void *end() const { return Data + Length; }
CssmData(void *data, size_t length)
{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
CssmData(char *data, size_t length)
{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
CssmData(unsigned char *data, size_t length)
{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
CssmData(signed char *data, size_t length)
{ Data = reinterpret_cast<UInt8 *>(data); Length = length; }
private: template <class T> CssmData(T *, size_t); public:
template <class T>
explicit CssmData(const T &obj)
{ Data = (UInt8 *)obj.data(); Length = obj.length(); }
template <class T>
static CssmData wrap(const T &it)
{ return CssmData(const_cast<void *>(reinterpret_cast<const void *>(&it)), sizeof(it)); }
template <class T>
static CssmData wrap(T *data, size_t length)
{ return CssmData(static_cast<void *>(data), length); }
operator signed char * () const { return reinterpret_cast<signed char *>(Data); }
operator unsigned char * () const { return reinterpret_cast<unsigned char *>(Data); }
operator char * () const { return reinterpret_cast<char *>(Data); }
operator void * () const { return reinterpret_cast<void *>(Data); }
template <class T>
T *interpretedAs() const { return reinterpret_cast<T *>(Data); }
template <class T>
T *interpretedAs(CSSM_RETURN error) const
{ return interpretedAs<T>(sizeof(T), error); }
template <class T>
T *interpretedAs(size_t len, CSSM_RETURN error) const
{
if (data() == NULL || length() != len) CssmError::throwMe(error);
return interpretedAs<T>();
}
public:
void length(size_t newLength) { assert(newLength <= Length); Length = newLength; }
void *at(off_t offset) const
{ assert(offset >= 0 && offset <= Length); return Data + offset; }
void *at(off_t offset, size_t size) const { assert(offset >= 0 && offset + size <= Length); return Data + offset; }
unsigned char operator [] (size_t pos) const
{ assert(pos < Length); return Data[pos]; }
void *use(size_t taken) { assert(taken <= Length); void *r = Data; Length -= taken; Data += taken; return r; }
void clear()
{ Data = NULL; Length = 0; }
string toString () const;
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); }
template <class T>
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) return Length < other.Length;
if (Length == 0) return false;
if (Data == NULL || other.Data == NULL) return Data < other.Data;
return memcmp(Data, other.Data, Length) < 0; }
class CryptoCallback {
public:
CryptoCallback(CSSM_CALLBACK func, void *ctx = NULL) : mFunction(func), mCtx(ctx) { }
CSSM_CALLBACK function() const { return mFunction; }
void *context() const { return mCtx; }
CssmData operator () () const
{
CssmData output;
if (CSSM_RETURN err = mFunction(&output, mCtx))
CssmError::throwMe(err);
return output;
}
private:
CSSM_CALLBACK mFunction;
void *mCtx;
};
class CssmCryptoData : public PodWrapper<CssmCryptoData, CSSM_CRYPTO_DATA> {
public:
CssmCryptoData() { }
CssmCryptoData(const CssmData ¶m, CSSM_CALLBACK callback = NULL, void *ctx = NULL)
{ Param = const_cast<CssmData &>(param); Callback = callback; CallerCtx = ctx; }
CssmCryptoData(const CssmData ¶m, CryptoCallback &cb)
{ Param = const_cast<CssmData &>(param); Callback = cb.function(); CallerCtx = cb.context(); }
CssmCryptoData(CSSM_CALLBACK callback, void *ctx = NULL)
{ Callback = callback; CallerCtx = ctx; }
explicit CssmCryptoData(CryptoCallback &cb)
{ Callback = cb.function(); CallerCtx = cb.context(); }
CssmData ¶m() { return CssmData::overlay(Param); }
const CssmData ¶m() const { return CssmData::overlay(Param); }
bool hasCallback() const { return Callback != NULL; }
CryptoCallback callback() const { return CryptoCallback(Callback, CallerCtx); }
CssmData operator () () const
{ return hasCallback() ? callback() () : param(); }
};
class CryptoDataClass : public CssmCryptoData {
public:
CryptoDataClass() : CssmCryptoData(callbackShim, this) { }
virtual ~CryptoDataClass();
protected:
virtual CssmData yield() = 0;
private:
static CSSM_RETURN callbackShim(CSSM_DATA *output, void *ctx)
{
BEGIN_API
*output = reinterpret_cast<CryptoDataClass *>(ctx)->yield();
END_API(CSSM)
}
};
typedef CssmData CssmOid;
class CssmKey : public PodWrapper<CssmKey, CSSM_KEY> {
public:
CssmKey() { clearPod(); KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION; }
CssmKey(const CSSM_KEY &key);
CssmKey(const CSSM_DATA &keyData);
CssmKey(uint32 length, void *data);
public:
class Header : public PodWrapper<Header, CSSM_KEYHEADER> {
public:
CSSM_KEYBLOB_TYPE blobType() const { return BlobType; }
void blobType(CSSM_KEYBLOB_TYPE blobType) { BlobType = blobType; }
CSSM_KEYBLOB_FORMAT blobFormat() const { return Format; }
void blobFormat(CSSM_KEYBLOB_FORMAT blobFormat) { Format = blobFormat; }
CSSM_KEYCLASS keyClass() const { return KeyClass; }
void keyClass(CSSM_KEYCLASS keyClass) { KeyClass = keyClass; }
CSSM_KEY_TYPE algorithm() const { return AlgorithmId; }
void algorithm(CSSM_KEY_TYPE algorithm) { AlgorithmId = algorithm; }
CSSM_KEY_TYPE wrapAlgorithm() const { return WrapAlgorithmId; }
void wrapAlgorithm(CSSM_KEY_TYPE wrapAlgorithm) { WrapAlgorithmId = wrapAlgorithm; }
CSSM_ENCRYPT_MODE wrapMode() const { return WrapMode; }
void wrapMode(CSSM_ENCRYPT_MODE mode) { WrapMode = mode; }
bool isWrapped() const { return WrapAlgorithmId != CSSM_ALGID_NONE; }
const Guid &cspGuid() const { return Guid::overlay(CspId); }
void cspGuid(const Guid &guid) { Guid::overlay(CspId) = guid; }
uint32 attributes() const { return KeyAttr; }
bool attribute(uint32 attr) const { return KeyAttr & attr; }
void setAttribute(uint32 attr) { KeyAttr |= attr; }
void clearAttribute(uint32 attr) { KeyAttr &= ~attr; }
uint32 usage() const { return KeyUsage; }
bool useFor(uint32 u) const { return KeyUsage & u; }
void usage(uint32 u) { KeyUsage |= u; }
void clearUsage(uint32 u) { u &= ~u; }
};
Header &header() { return Header::overlay(KeyHeader); }
const Header &header() const { return Header::overlay(KeyHeader); }
CSSM_KEYBLOB_TYPE blobType() const { return header().blobType(); }
void blobType(CSSM_KEYBLOB_TYPE blobType) { header().blobType(blobType); }
CSSM_KEYBLOB_FORMAT blobFormat() const { return header().blobFormat(); }
void blobFormat(CSSM_KEYBLOB_FORMAT blobFormat) { header().blobFormat(blobFormat); }
CSSM_KEYCLASS keyClass() const { return header().keyClass(); }
void keyClass(CSSM_KEYCLASS keyClass) { header().keyClass(keyClass); }
CSSM_KEY_TYPE algorithm() const { return header().algorithm(); }
void algorithm(CSSM_KEY_TYPE algorithm) { header().algorithm(algorithm); }
CSSM_KEY_TYPE wrapAlgorithm() const { return header().wrapAlgorithm(); }
void wrapAlgorithm(CSSM_KEY_TYPE wrapAlgorithm) { header().wrapAlgorithm(wrapAlgorithm); }
CSSM_ENCRYPT_MODE wrapMode() const { return header().wrapMode(); }
void wrapMode(CSSM_ENCRYPT_MODE mode) { header().wrapMode(mode); }
bool isWrapped() const { return header().isWrapped(); }
const Guid &cspGuid() const { return header().cspGuid(); }
uint32 attributes() const { return header().attributes(); }
bool attribute(uint32 a) const { return header().attribute(a); }
void setAttribute(uint32 attr) { header().setAttribute(attr); }
void clearAttribute(uint32 attr) { header().clearAttribute(attr); }
uint32 usage() const { return header().usage(); }
bool useFor(uint32 u) const { return header().useFor(u); }
void usage(uint32 u) { header().usage(u); }
void clearUsage(uint32 u) { header().clearUsage(u); }
public:
size_t length() const { return KeyData.Length; }
void *data() const { return KeyData.Data; }
operator void * () const { return data(); }
CssmData &keyData() { return CssmData::overlay(KeyData); }
const CssmData &keyData() const { return CssmData::overlay(KeyData); }
operator CssmData & () { return keyData(); }
operator const CssmData & () const { return keyData(); }
operator bool () const { return KeyData.Data != NULL; }
void operator = (const CssmData &data) { KeyData = data; }
};
typedef CssmKey CssmWrappedKey;
class CssmKeySize : public PodWrapper<CssmKeySize, CSSM_KEY_SIZE> {
public:
CssmKeySize() { }
CssmKeySize(uint32 nom, uint32 eff) { LogicalKeySizeInBits = nom; EffectiveKeySizeInBits = eff; }
CssmKeySize(uint32 size) { LogicalKeySizeInBits = EffectiveKeySizeInBits = size; }
uint32 logical() const { return LogicalKeySizeInBits; }
uint32 effective() const { return EffectiveKeySizeInBits; }
operator uint32 () const { return effective(); }
};
inline bool operator == (const CSSM_KEY_SIZE &s1, const CSSM_KEY_SIZE &s2)
{
return s1.LogicalKeySizeInBits == s2.LogicalKeySizeInBits
&& s1.EffectiveKeySizeInBits == s2.EffectiveKeySizeInBits;
}
inline bool operator != (const CSSM_KEY_SIZE &s1, const CSSM_KEY_SIZE &s2)
{ return !(s1 == s2); }
class QuerySizeData : public PodWrapper<QuerySizeData, CSSM_QUERY_SIZE_DATA> {
public:
QuerySizeData() { }
QuerySizeData(uint32 in) { SizeInputBlock = in; SizeOutputBlock = 0; }
uint32 inputSize() const { return SizeInputBlock; }
uint32 inputSize(uint32 size) { return SizeInputBlock = size; }
uint32 outputSize() const { return SizeOutputBlock; }
};
inline bool operator == (const CSSM_QUERY_SIZE_DATA &s1, const CSSM_QUERY_SIZE_DATA &s2)
{
return s1.SizeInputBlock == s2.SizeInputBlock
&& s1.SizeOutputBlock == s2.SizeOutputBlock;
}
inline bool operator != (const CSSM_QUERY_SIZE_DATA &s1, const CSSM_QUERY_SIZE_DATA &s2)
{ return !(s1 == s2); }
class CSPOperationalStatistics :
public PodWrapper<CSPOperationalStatistics, CSSM_CSP_OPERATIONAL_STATISTICS> {
public:
};
class DLQuery : public PodWrapper<DLQuery, CSSM_QUERY> {
public:
DLQuery() { memset(this, 0, sizeof(*this)) ; }
DLQuery(const CSSM_QUERY &q) { memcpy(this, &q, sizeof(*this)); }
DLQuery &operator = (const CSSM_QUERY &q)
{ memcpy(this, &q, sizeof(*this)); return *this; }
};
template <class In>
static inline void for_each_delete(In first, In last)
{
while (first != last)
delete *(first++);
}
template <class In>
static inline void for_each_map_delete(In first, In last)
{
while (first != last)
delete (first++)->second;
}
template <class T>
class auto_array
{
public:
auto_array() : mArray(NULL) {}
auto_array(size_t inSize) : mArray(new T[inSize]) {}
~auto_array() { if (mArray) delete[] mArray; }
T &operator[](size_t inIndex) { return mArray[inIndex]; }
void allocate(size_t inSize) { if (mArray) delete[] mArray; mArray = new T[inSize]; }
T *get() { return mArray; }
T *release() { T *anArray = mArray; mArray = NULL; return anArray; }
private:
T *mArray;
};
template <class _Tp>
class constVector
{
NOCOPY(constVector<_Tp>)
public:
typedef _Tp value_type;
typedef const value_type* const_pointer;
typedef const value_type* const_iterator;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
public:
const_iterator begin() const { return _M_start; }
const_iterator end() const { return _M_finish; }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(end()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(begin()); }
size_type size() const
{ return size_type(end() - begin()); }
bool empty() const
{ return begin() == end(); }
const_reference operator[](size_type __n) const { return *(begin() + __n); }
const_reference at(size_type n) const { return (*this)[n]; }
constVector(size_type __n, const _Tp* __value)
: _M_start(__value), _M_finish(__value + __n)
{}
constVector() : _M_start(NULL), _M_finish(NULL) {}
void overlay(size_type __n, const _Tp* __value) {
_M_start = __value;
_M_finish = __value + __n;
}
const_reference front() const { return *begin(); }
const_reference back() const { return *(end() - 1); }
private:
const _Tp *_M_start;
const _Tp *_M_finish;
};
}
#include "cfutilities.h"
#endif //_H_UTILITIES