/ OSX / libsecurity_cssm / lib / cssmcontext.cpp
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  }