cssmcontext.cpp
1 /* 2 * Copyright (c) 2000-2002,2004,2011,2014 Apple 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 - manage CSSM (cryptographic) contexts every which way. 27 // 28 // A note on memory management: 29 // Context attributes are allocated from application memory in big chunks comprising 30 // many attributes as well as the attribute array itself. The CSSM_CONTEXT fields 31 // NumberOfAttributes and ContextAttributes are handled as a group. Context::Builder 32 // and Context::copyFrom assume these fields are undefined and fill them. Context::clear 33 // assumes they are valid and invalides them, freeing memory. 34 // 35 #ifdef __MWERKS__ 36 #define _CPP_CSSMCONTEXT 37 #endif 38 #include "cssmcontext.h" 39 40 41 // 42 // Destroy a HandleContext. 43 // 44 HandleContext::~HandleContext() 45 { 46 attachment.free(extent); 47 attachment.free(ContextAttributes); 48 } 49 50 51 // 52 // Locking protocol for HandleContexts 53 // 54 void HandleContext::lock() 55 { attachment.enter(); } 56 57 bool HandleContext::tryLock() 58 { return attachment.tryEnter(); } 59 60 61 // 62 // Merge a new set of attributes into an existing HandleContext, copying 63 // the new values deeply while releasing corresponding old values. 64 // 65 // NOTE: This is a HandleContext method; it does not work on bare Contexts. 66 // 67 void HandleContext::mergeAttributes(const CSSM_CONTEXT_ATTRIBUTE *attributes, uint32 count) 68 { 69 // attempt to fast-path some simple or frequent cases 70 if (count == 1) { 71 if (Attr *attr = find(attributes[0].AttributeType)) { 72 if (attr->baseType() == CSSM_ATTRIBUTE_DATA_UINT32) { 73 // try quick replacement 74 Attr oldAttr = *attr; 75 *attr = attributes[0]; 76 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) { 77 // roll back and fail 78 *attr = oldAttr; 79 CssmError::throwMe(err); 80 } 81 return; // all done 82 } else { 83 // pointer value - does it fit into the space of the current value? 84 size_t oldSize = size(*attr); 85 size_t newSize = size(attributes[0]); 86 Attr oldAttr = *attr; 87 if (newSize <= oldSize) { // give it a try... 88 *attr = attributes[0]; 89 // NOTE that the CSP is getting a "temporary" pointer set to validate; 90 // If we commit, the final copy will be elsewhere. CSP writer beware! 91 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) { 92 // roll back and fail 93 *attr = oldAttr; 94 CssmError::throwMe(err); 95 } 96 // commit new value 97 CopyWalker copier(oldAttr.Attribute.String); 98 walk(copier, *attr); 99 return; 100 } 101 } 102 } else { // single change, new attribute 103 if (Attr *slot = find(CSSM_ATTRIBUTE_NONE)) { 104 const Attr *attr = static_cast<const Attr *>(&attributes[0]); 105 if (attr->baseType() == CSSM_ATTRIBUTE_DATA_UINT32) { // trivial 106 Attr oldSlot = *slot; 107 *slot = *attr; 108 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) { 109 *slot = oldSlot; 110 CssmError::throwMe(err); 111 } 112 // already ok 113 return; 114 } else if (extent == NULL) { // pointer value, allocate into extent 115 void *data = attachment.malloc(size(*attr)); 116 try { 117 Attr oldSlot = *slot; 118 *slot = attributes[0]; 119 CopyWalker copier(data); 120 walk(copier, *slot); 121 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) { 122 *slot = oldSlot; 123 CssmError::throwMe(err); 124 } 125 } catch (...) { 126 attachment.free(data); 127 throw; 128 } 129 extent = data; 130 return; 131 } 132 } 133 } 134 } 135 136 // slow form: build a new value table and get rid of the old one 137 Context::Builder builder(attachment); 138 for (unsigned n = 0; n < count; n++) 139 builder.setup(attributes[n]); 140 for (unsigned n = 0; n < attributesInUse(); n++) 141 if (!find(ContextAttributes[n].AttributeType, attributes, count)) 142 builder.setup(ContextAttributes[n]); 143 builder.make(); 144 for (unsigned n = 0; n < count; n++) 145 builder.put(attributes[n]); 146 for (unsigned n = 0; n < attributesInUse(); n++) 147 if (!find(ContextAttributes[n].AttributeType, attributes, count)) 148 builder.put(ContextAttributes[n]); 149 150 // Carefully, now! The CSP may yet tell us to back out. 151 // First, save the old values... 152 CSSM_CONTEXT_ATTRIBUTE *oldAttributes = ContextAttributes; 153 uint32 oldCount = NumberOfAttributes; 154 155 // ...install new blob into the context... 156 builder.done(ContextAttributes, NumberOfAttributes); 157 158 // ...and ask the CSP whether this is okay 159 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) { 160 // CSP refused; put everything back where it belongs 161 attachment.free(ContextAttributes); 162 ContextAttributes = oldAttributes; 163 NumberOfAttributes = oldCount; 164 CssmError::throwMe(err); 165 } 166 167 // we succeeded, so NOW delete the old attributes blob 168 attachment.free(oldAttributes); 169 } 170 171 172 // 173 // Ask the CSP to validate a proposed (and already implemented) change 174 // 175 CSSM_RETURN HandleContext::validateChange(CSSM_CONTEXT_EVENT event) 176 { 177 // lock down the module if it is not thread-safe 178 StLock<Module, &Module::safeLock, &Module::safeUnlock> _(attachment.module); 179 return attachment.downcalls.EventNotify(attachment.handle(), 180 event, handle(), this); 181 } 182 183 184 // 185 // Wrap up a deluxe context creation operation and return the new CC handle. 186 // 187 CSSM_CC_HANDLE HandleContext::Maker::operator () (CSSM_CONTEXT_TYPE type, 188 CSSM_ALGORITHMS algorithm) 189 { 190 // construct the HandleContext object 191 HandleContext &context = *new(attachment) HandleContext(attachment, type, algorithm); 192 context.CSPHandle = attachment.handle(); 193 done(context.ContextAttributes, context.NumberOfAttributes); 194 195 // ask the CSP for consent 196 if (CSSM_RETURN err = context.validateChange(CSSM_CONTEXT_EVENT_CREATE)) { 197 // CSP refused; clean up and fail 198 context.destroy(&context, context.attachment); 199 CssmError::throwMe(err); 200 } 201 202 // return the new handle (we have succeeded) 203 return context.handle(); 204 }