X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utilities/lib/context.h?ds=inline diff --git a/Security/libsecurity_cdsa_utilities/lib/context.h b/Security/libsecurity_cdsa_utilities/lib/context.h new file mode 100644 index 00000000..f5eb57d7 --- /dev/null +++ b/Security/libsecurity_cdsa_utilities/lib/context.h @@ -0,0 +1,404 @@ +/* + * 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@ + */ + + +// +// context - CSSM cryptographic context objects +// +#ifndef _H_CONTEXT +#define _H_CONTEXT + +#include +#include +#include +#include +#include // to serialize/copy access credentials +#include + +namespace Security { + + +// +// Context is a POD overlay for the CSSM_CONTEXT type. It does +// add allocation functions and lots of good stuff. +// Note that if you're outside CSSM proper, you are not supposed to +// memory-manage Context structures on your own. Be a good boy and +// call the CSSM API functions. +// We also provide a POD overlay for CSSM_CONTEXT_ATTRIBUTE, with +// the obvious semantics. +// +class Context : public PodWrapper { +public: + Context(CSSM_CONTEXT_TYPE type, CSSM_ALGORITHMS algorithmId); + + uint32 attributesInUse() const { return NumberOfAttributes; } + CSSM_CONTEXT_TYPE type() const { return ContextType; } + CSSM_ALGORITHMS algorithm() const { return AlgorithmType; } + CSSM_CSP_HANDLE cspHandle() const { return CSPHandle; } + + void deleteAttribute(CSSM_ATTRIBUTE_TYPE type); + size_t copyAttributes(CSSM_CONTEXT_ATTRIBUTE * &attrs, uint32 &count, Allocator &alloc) const; + + void copyFrom(const Context &source, Allocator &alloc) + { source.copyAttributes(ContextAttributes, NumberOfAttributes, alloc); } + +public: + class Attr : public PodWrapper { + public: + Attr() { } + Attr(const CSSM_CONTEXT_ATTRIBUTE &attr) { (CSSM_CONTEXT_ATTRIBUTE &)*this = attr; } + + template + Attr(CSSM_ATTRIBUTE_TYPE typ, T &value, size_t size = 0) + { + AttributeType = typ; + // attribute component pointers are stupidly non-const; allow const input + Attribute.String = const_cast(reinterpret_cast(&value)); + AttributeLength = (uint32_t) (size ? size : sizeof(T)); + } + + Attr(CSSM_ATTRIBUTE_TYPE typ, uint32 value) + { + AttributeType = typ; + Attribute.Uint32 = value; + AttributeLength = 0; + } + + CSSM_ATTRIBUTE_TYPE type() const { return AttributeType; } + uint32 baseType() const { return AttributeType & CSSM_ATTRIBUTE_TYPE_MASK; } + + operator char * () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_STRING); return Attribute.String; } + operator CssmData & () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_CSSM_DATA); + return CssmData::overlay(*Attribute.Data); } + operator CssmCryptoData & () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_CRYPTO_DATA); + return CssmCryptoData::overlay(*Attribute.CryptoData); } + operator CssmKey & () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_KEY); return CssmKey::overlay(*Attribute.Key); } + operator AccessCredentials & () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS); + return AccessCredentials::overlay(*Attribute.AccessCredentials); } + operator uint32 () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_UINT32); return Attribute.Uint32; } + operator CSSM_DL_DB_HANDLE &() const + { + assert(baseType() == CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE); + if (Attribute.DLDBHandle == NULL) + CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE); + return *Attribute.DLDBHandle; + } + operator CssmDate & () const + { assert(baseType() == CSSM_ATTRIBUTE_DATA_DATE); + return CssmDate::overlay(*Attribute.Date); } + // @@@ etc. etc. - add yours today! + + void operator = (uint32 value) { Attribute.Uint32 = value; } + template + void operator = (T *ptr) { Attribute.String = reinterpret_cast(ptr); } + + IFDUMP(void dump() const;) // debug dump this Attr to stdout (one line) + }; + + // Attributes by position + Attr *attributes() const { return Attr::overlay(ContextAttributes); } + Attr &operator [] (unsigned int ix) + { assert(ix < NumberOfAttributes); return static_cast(ContextAttributes[ix]); } + const Attr &operator [] (unsigned int ix) const + { assert(ix < NumberOfAttributes); return static_cast(ContextAttributes[ix]); } + + // general attribute retrieval by type + Attr *find(CSSM_ATTRIBUTE_TYPE theType) const + { return find(theType, ContextAttributes, NumberOfAttributes); } + + template + Elem &get(CSSM_ATTRIBUTE_TYPE type, CSSM_RETURN err) const + { + if (Attr *attr = find(type)) + return static_cast(*attr); + else + CssmError::throwMe(err); + } + + template + Elem *get(CSSM_ATTRIBUTE_TYPE type) const + { + if (Attr *attr = find(type)) + // @@@ Invoking conversion operator to Elem & on *attr and taking address of result. + return &static_cast(*attr); + else + return NULL; + } + + uint32 getInt(CSSM_ATTRIBUTE_TYPE type, CSSM_RETURN err) const + { + if (Attr *attr = find(type)) + return static_cast(*attr); + else + CssmError::throwMe(err); + } + + uint32 getInt(CSSM_ATTRIBUTE_TYPE type) const + { + if (Attr *attr = find(type)) + return static_cast(*attr); + else + return 0; + } + + bool getInt(CSSM_ATTRIBUTE_TYPE type, uint32 &value) const + { + if (Attr *attr = find(type)) { + value = static_cast(*attr); + return true; + } else + return false; + } + +public: + template + void replace(CSSM_ATTRIBUTE_TYPE type, const T &newValue) const + { + if (Attr *attr = find(type)) + *attr = Attr(type, newValue); + else + CssmError::throwMe(CSSMERR_CSSM_ATTRIBUTE_NOT_IN_CONTEXT); + } + +public: + void *operator new (size_t size, Allocator &alloc) throw(std::bad_alloc) + { return alloc.malloc(size); } + void operator delete (void *addr, size_t, Allocator &alloc) throw() + { return alloc.free(addr); } + static void destroy(Context *context, Allocator &alloc) throw() + { alloc.free(context->ContextAttributes); alloc.free(context); } + +public: + // Post-IPC context fixup. + // This can only be called on a Built Context after IPC transmission. + void postIPC(void *base, CSSM_CONTEXT_ATTRIBUTE *ipcAttributes); + +public: + class Builder; + + // dump to stdout, multiline format + IFDUMP(void dump(const char *title = NULL, + const CSSM_CONTEXT_ATTRIBUTE *attrs = NULL) const;) + +protected: + // find an attribute in a plain array of attribute structures (no context) + static Attr *find(CSSM_ATTRIBUTE_TYPE theType, + const CSSM_CONTEXT_ATTRIBUTE *attrs, unsigned int count); +}; + + +namespace DataWalkers { + + +template +void walk(Action &operate, CSSM_CONTEXT_ATTRIBUTE &attr) +{ + operate(attr); + if (attr.Attribute.String) // non-NULL pointer (imprecise but harmless) + switch (attr.AttributeType & CSSM_ATTRIBUTE_TYPE_MASK) { + case CSSM_ATTRIBUTE_DATA_CSSM_DATA: + walk(operate, attr.Attribute.Data); break; + case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA: + walk(operate, attr.Attribute.CryptoData); break; + case CSSM_ATTRIBUTE_DATA_KEY: + walk(operate, attr.Attribute.Key); break; + case CSSM_ATTRIBUTE_DATA_STRING: + walk(operate, attr.Attribute.String); break; + case CSSM_ATTRIBUTE_DATA_DATE: + walk(operate, attr.Attribute.Date); break; + case CSSM_ATTRIBUTE_DATA_RANGE: + walk(operate, attr.Attribute.Range); break; + case CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS: + walk(operate, attr.Attribute.AccessCredentials); break; + case CSSM_ATTRIBUTE_DATA_VERSION: + walk(operate, attr.Attribute.Version); break; + case CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE: + walk(operate, attr.Attribute.DLDBHandle); break; + case CSSM_ATTRIBUTE_NONE: + case CSSM_ATTRIBUTE_DATA_UINT32: + break; + default: + secdebug("walkers", "invalid attribute (%ux) in context", (unsigned)attr.AttributeType); + break; + } +} + +template +void walk(Action &operate, Context::Attr &attr) +{ + walk(operate, static_cast(attr)); +} + +} // end namespace DataWalkers + + +// +// Context::Builder - make context attributes the fun way. +// +// A Context (aka CSSM_CONTEXT) has a pointer to an array of context attributes, +// most of which contain pointers to other stuff with pointers to God Knows Where. +// Instead of allocating this all over the heap, a Context::Builder performs +// a two-pass algorithm that places all that stuff into a single heap node. +// Specifically, the builder will allocate and create a vector of CSSM_CONTEXT_ATTRIBUTE +// structures and all their subordinate heap storage. +// A Builder does not deal in Context objects and does not care what you do with your +// CSSM_CONTEXT_ATTRIBUTE array once it's delivered. Since it's a single heap node, +// you can just free() it using the appropriate allocator when you're done with it. +// +// Theory of operation: +// Builder works in two phases, called scan and build. During scan, you call setup() +// with the desired data to be placed into the attribute vector. When done, call make() +// to switch to build phase. Then call put() with the SAME sequence of values as in phase 1. +// Finally, call done() to receive the pointer-and-count values. +// @@@ Add comment about IPC use. +// +using namespace DataWalkers; + +class Context::Builder { +protected: +public: + Builder(Allocator &alloc) : allocator(alloc) + { slotCount = 0; attributes = NULL; } + ~Builder() { allocator.free(attributes); } + + Allocator &allocator; + + // switch to build phase + size_t make(); + // deliver result + void done(CSSM_CONTEXT_ATTRIBUTE * &attributes, uint32 &count); + +public: + // + // Phase 1 (scan) dispatch. Call once for each attribute needed. + // + template + void setup(T p, CSSM_RETURN invalidError = CSSM_OK) + { + if (p) { + slotCount++; + walk(sizer, unconst_ref_cast(p)); + } else if (invalidError) + CssmError::throwMe(invalidError); + } + + void setup(uint32 n, CSSM_RETURN invalidError = CSSM_OK) + { + if (n) + slotCount++; + else if (invalidError) + CssmError::throwMe(invalidError); + } + + void setup(CSSM_SIZE n, CSSM_RETURN invalidError = CSSM_OK) + { + if (n) + slotCount++; + else if (invalidError) + CssmError::throwMe(invalidError); + } + + void setup(const CSSM_KEY *k, CSSM_RETURN invalidError = CSSM_OK) + { + if (!invalidError) { + if (k) { + slotCount++; + walk(sizer, unconst_ref_cast(k)); + } + return; // no additional validation performed + } + // perform a basic sanity check of the input CSSM_KEY + if (!(k) || (k->KeyHeader.HeaderVersion > CSSM_KEYHEADER_VERSION)) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE); + } + // must not point to an odd address or NULL + if (!(k->KeyData.Data) || ((uint64_t)k->KeyData.Data & (uint64_t)1)) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_POINTER); + } + // simplistic key data length check + if ((k->KeyData.Length < 4) || (k->KeyData.Length > 32768)) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + slotCount++; + walk(sizer, unconst_ref_cast(k)); + } + + // dynamic attribute type + void setup(const CSSM_CONTEXT_ATTRIBUTE &attr) + { slotCount++; walk(sizer, const_cast(attr)); } + void setup(const Context::Attr &attr) { setup(static_cast(attr)); } + + // + // Phase 2 (copy) dispatch. Call once for each attribute, in same order as setup(). + // + template + void put(CSSM_ATTRIBUTE_TYPE type, const T *p) + { + if (p) { + assert(slot < slotCount); // check overflow + Attr &attribute = attributes[slot++]; + attribute.AttributeType = type; + attribute.AttributeLength = (uint32)size(p); //@@@ needed? how/when/what for? + T *tmp = const_cast(p); + attribute = walk(copier, tmp); + } + } + void put(CSSM_ATTRIBUTE_TYPE type, uint32 value) + { + if (value) { + assert(slot < slotCount); // check overflow + Attr &attribute = attributes[slot++]; + attribute.AttributeType = type; + attribute.AttributeLength = 0; //@@@ unclear what that should be + attribute = value; // no heap data (immediate value) + } + } + void put(const CSSM_CONTEXT_ATTRIBUTE &attr) + { + assert(slot < slotCount); + Attr &attribute = attributes[slot++]; + attribute = attr; // shallow copy + walk(copier, attribute); // deep copy + } + void put(const Context::Attr &attr) { put(static_cast(attr)); } + +private: + // pass 1 state: collect sizes and counts + unsigned slotCount; // count of attribute slots in use + SizeWalker sizer; // memory size calculator + + // pass 2 state: build the data set + Context::Attr *attributes; // attribute vector and start of block + CopyWalker copier; // data copy engine + uint32 slot; // writer slot position +}; + +} // end namespace Security + +#endif //_H_CONTEXT