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// context - CSSM cryptographic context objects 27// 28#ifndef _H_CONTEXT 29#define _H_CONTEXT 30 31#include <security_utilities/utilities.h> 32#include <security_utilities/debugging.h> 33#include <security_cdsa_utilities/cssmalloc.h> 34#include <security_cdsa_utilities/cssmwalkers.h> 35#include <security_cdsa_utilities/cssmacl.h> // to serialize/copy access credentials 36#include <security_cdsa_utilities/cssmdates.h> 37 38namespace Security { 39 40 41// 42// Context is a POD overlay for the CSSM_CONTEXT type. It does 43// add allocation functions and lots of good stuff. 44// Note that if you're outside CSSM proper, you are not supposed to 45// memory-manage Context structures on your own. Be a good boy and 46// call the CSSM API functions. 47// We also provide a POD overlay for CSSM_CONTEXT_ATTRIBUTE, with 48// the obvious semantics. 49// 50class Context : public PodWrapper<Context, CSSM_CONTEXT> { 51public: 52 Context(CSSM_CONTEXT_TYPE type, CSSM_ALGORITHMS algorithmId); 53 54 uint32 attributesInUse() const { return NumberOfAttributes; } 55 CSSM_CONTEXT_TYPE type() const { return ContextType; } 56 CSSM_ALGORITHMS algorithm() const { return AlgorithmType; } 57 CSSM_CSP_HANDLE cspHandle() const { return CSPHandle; } 58 59 void deleteAttribute(CSSM_ATTRIBUTE_TYPE type); 60 size_t copyAttributes(CSSM_CONTEXT_ATTRIBUTE * &attrs, uint32 &count, Allocator &alloc) const; 61 62 void copyFrom(const Context &source, Allocator &alloc) 63 { source.copyAttributes(ContextAttributes, NumberOfAttributes, alloc); } 64 65public: 66 class Attr : public PodWrapper<Attr, CSSM_CONTEXT_ATTRIBUTE> { 67 public: 68 Attr() { } 69 Attr(const CSSM_CONTEXT_ATTRIBUTE &attr) { (CSSM_CONTEXT_ATTRIBUTE &)*this = attr; } 70 71 template <class T> 72 Attr(CSSM_ATTRIBUTE_TYPE typ, T &value, size_t size = 0) 73 { 74 AttributeType = typ; 75 // attribute component pointers are stupidly non-const; allow const input 76 Attribute.String = const_cast<char *>(reinterpret_cast<const char *>(&value)); 77 AttributeLength = (uint32_t) (size ? size : sizeof(T)); 78 } 79 80 Attr(CSSM_ATTRIBUTE_TYPE typ, uint32 value) 81 { 82 AttributeType = typ; 83 Attribute.Uint32 = value; 84 AttributeLength = 0; 85 } 86 87 CSSM_ATTRIBUTE_TYPE type() const { return AttributeType; } 88 uint32 baseType() const { return AttributeType & CSSM_ATTRIBUTE_TYPE_MASK; } 89 90 operator char * () const 91 { assert(baseType() == CSSM_ATTRIBUTE_DATA_STRING); return Attribute.String; } 92 operator CssmData & () const 93 { assert(baseType() == CSSM_ATTRIBUTE_DATA_CSSM_DATA); 94 return CssmData::overlay(*Attribute.Data); } 95 operator CssmCryptoData & () const 96 { assert(baseType() == CSSM_ATTRIBUTE_DATA_CRYPTO_DATA); 97 return CssmCryptoData::overlay(*Attribute.CryptoData); } 98 operator CssmKey & () const 99 { assert(baseType() == CSSM_ATTRIBUTE_DATA_KEY); return CssmKey::overlay(*Attribute.Key); } 100 operator AccessCredentials & () const 101 { assert(baseType() == CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS); 102 return AccessCredentials::overlay(*Attribute.AccessCredentials); } 103 operator uint32 () const 104 { assert(baseType() == CSSM_ATTRIBUTE_DATA_UINT32); return Attribute.Uint32; } 105 operator CSSM_DL_DB_HANDLE &() const 106 { 107 assert(baseType() == CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE); 108 if (Attribute.DLDBHandle == NULL) 109 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE); 110 return *Attribute.DLDBHandle; 111 } 112 operator CssmDate & () const 113 { assert(baseType() == CSSM_ATTRIBUTE_DATA_DATE); 114 return CssmDate::overlay(*Attribute.Date); } 115 // @@@ etc. etc. - add yours today! 116 117 void operator = (uint32 value) { Attribute.Uint32 = value; } 118 template <class T> 119 void operator = (T *ptr) { Attribute.String = reinterpret_cast<char *>(ptr); } 120 121 IFDUMP(void dump() const;) // debug dump this Attr to stdout (one line) 122 }; 123 124 // Attributes by position 125 Attr *attributes() const { return Attr::overlay(ContextAttributes); } 126 Attr &operator [] (unsigned int ix) 127 { assert(ix < NumberOfAttributes); return static_cast<Attr &>(ContextAttributes[ix]); } 128 const Attr &operator [] (unsigned int ix) const 129 { assert(ix < NumberOfAttributes); return static_cast<Attr &>(ContextAttributes[ix]); } 130 131 // general attribute retrieval by type 132 Attr *find(CSSM_ATTRIBUTE_TYPE theType) const 133 { return find(theType, ContextAttributes, NumberOfAttributes); } 134 135 template <class Elem> 136 Elem &get(CSSM_ATTRIBUTE_TYPE type, CSSM_RETURN err) const 137 { 138 if (Attr *attr = find(type)) 139 return static_cast<Elem &>(*attr); 140 else 141 CssmError::throwMe(err); 142 } 143 144 template <class Elem> 145 Elem *get(CSSM_ATTRIBUTE_TYPE type) const 146 { 147 if (Attr *attr = find(type)) 148 // @@@ Invoking conversion operator to Elem & on *attr and taking address of result. 149 return &static_cast<Elem &>(*attr); 150 else 151 return NULL; 152 } 153 154 uint32 getInt(CSSM_ATTRIBUTE_TYPE type, CSSM_RETURN err) const 155 { 156 if (Attr *attr = find(type)) 157 return static_cast<uint32>(*attr); 158 else 159 CssmError::throwMe(err); 160 } 161 162 uint32 getInt(CSSM_ATTRIBUTE_TYPE type) const 163 { 164 if (Attr *attr = find(type)) 165 return static_cast<uint32>(*attr); 166 else 167 return 0; 168 } 169 170 bool getInt(CSSM_ATTRIBUTE_TYPE type, uint32 &value) const 171 { 172 if (Attr *attr = find(type)) { 173 value = static_cast<uint32>(*attr); 174 return true; 175 } else 176 return false; 177 } 178 179public: 180 template <class T> 181 void replace(CSSM_ATTRIBUTE_TYPE type, const T &newValue) const 182 { 183 if (Attr *attr = find(type)) 184 *attr = Attr(type, newValue); 185 else 186 CssmError::throwMe(CSSMERR_CSSM_ATTRIBUTE_NOT_IN_CONTEXT); 187 } 188 189public: 190 void *operator new (size_t size, Allocator &alloc) throw(std::bad_alloc) 191 { return alloc.malloc(size); } 192 void operator delete (void *addr, size_t, Allocator &alloc) throw() 193 { return alloc.free(addr); } 194 static void destroy(Context *context, Allocator &alloc) throw() 195 { alloc.free(context->ContextAttributes); alloc.free(context); } 196 197public: 198 // Post-IPC context fixup. 199 // This can only be called on a Built Context after IPC transmission. 200 void postIPC(void *base, CSSM_CONTEXT_ATTRIBUTE *ipcAttributes); 201 202public: 203 class Builder; 204 205 // dump to stdout, multiline format 206 IFDUMP(void dump(const char *title = NULL, 207 const CSSM_CONTEXT_ATTRIBUTE *attrs = NULL) const;) 208 209protected: 210 // find an attribute in a plain array of attribute structures (no context) 211 static Attr *find(CSSM_ATTRIBUTE_TYPE theType, 212 const CSSM_CONTEXT_ATTRIBUTE *attrs, unsigned int count); 213}; 214 215 216namespace DataWalkers { 217 218 219template <class Action> 220void walk(Action &operate, CSSM_CONTEXT_ATTRIBUTE &attr) 221{ 222 operate(attr); 223 if (attr.Attribute.String) // non-NULL pointer (imprecise but harmless) 224 switch (attr.AttributeType & CSSM_ATTRIBUTE_TYPE_MASK) { 225 case CSSM_ATTRIBUTE_DATA_CSSM_DATA: 226 walk(operate, attr.Attribute.Data); break; 227 case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA: 228 walk(operate, attr.Attribute.CryptoData); break; 229 case CSSM_ATTRIBUTE_DATA_KEY: 230 walk(operate, attr.Attribute.Key); break; 231 case CSSM_ATTRIBUTE_DATA_STRING: 232 walk(operate, attr.Attribute.String); break; 233 case CSSM_ATTRIBUTE_DATA_DATE: 234 walk(operate, attr.Attribute.Date); break; 235 case CSSM_ATTRIBUTE_DATA_RANGE: 236 walk(operate, attr.Attribute.Range); break; 237 case CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS: 238 walk(operate, attr.Attribute.AccessCredentials); break; 239 case CSSM_ATTRIBUTE_DATA_VERSION: 240 walk(operate, attr.Attribute.Version); break; 241 case CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE: 242 walk(operate, attr.Attribute.DLDBHandle); break; 243 case CSSM_ATTRIBUTE_NONE: 244 case CSSM_ATTRIBUTE_DATA_UINT32: 245 break; 246 default: 247 secdebug("walkers", "invalid attribute (%ux) in context", (unsigned)attr.AttributeType); 248 break; 249 } 250} 251 252template <class Action> 253void walk(Action &operate, Context::Attr &attr) 254{ 255 walk(operate, static_cast<CSSM_CONTEXT_ATTRIBUTE &>(attr)); 256} 257 258} // end namespace DataWalkers 259 260 261// 262// Context::Builder - make context attributes the fun way. 263// 264// A Context (aka CSSM_CONTEXT) has a pointer to an array of context attributes, 265// most of which contain pointers to other stuff with pointers to God Knows Where. 266// Instead of allocating this all over the heap, a Context::Builder performs 267// a two-pass algorithm that places all that stuff into a single heap node. 268// Specifically, the builder will allocate and create a vector of CSSM_CONTEXT_ATTRIBUTE 269// structures and all their subordinate heap storage. 270// A Builder does not deal in Context objects and does not care what you do with your 271// CSSM_CONTEXT_ATTRIBUTE array once it's delivered. Since it's a single heap node, 272// you can just free() it using the appropriate allocator when you're done with it. 273// 274// Theory of operation: 275// Builder works in two phases, called scan and build. During scan, you call setup() 276// with the desired data to be placed into the attribute vector. When done, call make() 277// to switch to build phase. Then call put() with the SAME sequence of values as in phase 1. 278// Finally, call done() to receive the pointer-and-count values. 279// @@@ Add comment about IPC use. 280// 281using namespace DataWalkers; 282 283class Context::Builder { 284protected: 285public: 286 Builder(Allocator &alloc) : allocator(alloc) 287 { slotCount = 0; attributes = NULL; } 288 ~Builder() { allocator.free(attributes); } 289 290 Allocator &allocator; 291 292 // switch to build phase 293 size_t make(); 294 // deliver result 295 void done(CSSM_CONTEXT_ATTRIBUTE * &attributes, uint32 &count); 296 297public: 298 // 299 // Phase 1 (scan) dispatch. Call once for each attribute needed. 300 // 301 template <class T> 302 void setup(T p, CSSM_RETURN invalidError = CSSM_OK) 303 { 304 if (p) { 305 slotCount++; 306 walk(sizer, unconst_ref_cast(p)); 307 } else if (invalidError) 308 CssmError::throwMe(invalidError); 309 } 310 311 void setup(uint32 n, CSSM_RETURN invalidError = CSSM_OK) 312 { 313 if (n) 314 slotCount++; 315 else if (invalidError) 316 CssmError::throwMe(invalidError); 317 } 318 319 void setup(CSSM_SIZE n, CSSM_RETURN invalidError = CSSM_OK) 320 { 321 if (n) 322 slotCount++; 323 else if (invalidError) 324 CssmError::throwMe(invalidError); 325 } 326 327 // dynamic attribute type 328 void setup(const CSSM_CONTEXT_ATTRIBUTE &attr) 329 { slotCount++; walk(sizer, const_cast<CSSM_CONTEXT_ATTRIBUTE &>(attr)); } 330 void setup(const Context::Attr &attr) { setup(static_cast<const CSSM_CONTEXT_ATTRIBUTE &>(attr)); } 331 332 // 333 // Phase 2 (copy) dispatch. Call once for each attribute, in same order as setup(). 334 // 335 template <class T> 336 void put(CSSM_ATTRIBUTE_TYPE type, const T *p) 337 { 338 if (p) { 339 assert(slot < slotCount); // check overflow 340 Attr &attribute = attributes[slot++]; 341 attribute.AttributeType = type; 342 attribute.AttributeLength = (uint32)size(p); //@@@ needed? how/when/what for? 343 T *tmp = const_cast<T *>(p); 344 attribute = walk(copier, tmp); 345 } 346 } 347 void put(CSSM_ATTRIBUTE_TYPE type, uint32 value) 348 { 349 if (value) { 350 assert(slot < slotCount); // check overflow 351 Attr &attribute = attributes[slot++]; 352 attribute.AttributeType = type; 353 attribute.AttributeLength = 0; //@@@ unclear what that should be 354 attribute = value; // no heap data (immediate value) 355 } 356 } 357 void put(const CSSM_CONTEXT_ATTRIBUTE &attr) 358 { 359 assert(slot < slotCount); 360 Attr &attribute = attributes[slot++]; 361 attribute = attr; // shallow copy 362 walk(copier, attribute); // deep copy 363 } 364 void put(const Context::Attr &attr) { put(static_cast<const CSSM_CONTEXT_ATTRIBUTE &>(attr)); } 365 366private: 367 // pass 1 state: collect sizes and counts 368 unsigned slotCount; // count of attribute slots in use 369 SizeWalker sizer; // memory size calculator 370 371 // pass 2 state: build the data set 372 Context::Attr *attributes; // attribute vector and start of block 373 CopyWalker copier; // data copy engine 374 uint32 slot; // writer slot position 375}; 376 377} // end namespace Security 378 379#endif //_H_CONTEXT 380