-/*
- * Copyright (c) 2000-2002,2004,2011,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 - manage CSSM (cryptographic) contexts every which way.
-//
-// A note on memory management:
-// Context attributes are allocated from application memory in big chunks comprising
-// many attributes as well as the attribute array itself. The CSSM_CONTEXT fields
-// NumberOfAttributes and ContextAttributes are handled as a group. Context::Builder
-// and Context::copyFrom assume these fields are undefined and fill them. Context::clear
-// assumes they are valid and invalides them, freeing memory.
-//
-#ifdef __MWERKS__
-#define _CPP_CSSMCONTEXT
-#endif
-#include "cssmcontext.h"
-
-
-//
-// Destroy a HandleContext.
-//
-HandleContext::~HandleContext()
-{
- attachment.free(extent);
- attachment.free(ContextAttributes);
-}
-
-
-//
-// Locking protocol for HandleContexts
-//
-void HandleContext::lock()
-{ attachment.enter(); }
-
-bool HandleContext::tryLock()
-{ return attachment.tryEnter(); }
-
-
-//
-// Merge a new set of attributes into an existing HandleContext, copying
-// the new values deeply while releasing corresponding old values.
-//
-// NOTE: This is a HandleContext method; it does not work on bare Contexts.
-//
-void HandleContext::mergeAttributes(const CSSM_CONTEXT_ATTRIBUTE *attributes, uint32 count)
-{
- // attempt to fast-path some simple or frequent cases
- if (count == 1) {
- if (Attr *attr = find(attributes[0].AttributeType)) {
- if (attr->baseType() == CSSM_ATTRIBUTE_DATA_UINT32) {
- // try quick replacement
- Attr oldAttr = *attr;
- *attr = attributes[0];
- if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
- // roll back and fail
- *attr = oldAttr;
- CssmError::throwMe(err);
- }
- return; // all done
- } else {
- // pointer value - does it fit into the space of the current value?
- size_t oldSize = size(*attr);
- size_t newSize = size(attributes[0]);
- Attr oldAttr = *attr;
- if (newSize <= oldSize) { // give it a try...
- *attr = attributes[0];
- // NOTE that the CSP is getting a "temporary" pointer set to validate;
- // If we commit, the final copy will be elsewhere. CSP writer beware!
- if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
- // roll back and fail
- *attr = oldAttr;
- CssmError::throwMe(err);
- }
- // commit new value
- CopyWalker copier(oldAttr.Attribute.String);
- walk(copier, *attr);
- return;
- }
- }
- } else { // single change, new attribute
- if (Attr *slot = find(CSSM_ATTRIBUTE_NONE)) {
- const Attr *attr = static_cast<const Attr *>(&attributes[0]);
- if (attr->baseType() == CSSM_ATTRIBUTE_DATA_UINT32) { // trivial
- Attr oldSlot = *slot;
- *slot = *attr;
- if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
- *slot = oldSlot;
- CssmError::throwMe(err);
- }
- // already ok
- return;
- } else if (extent == NULL) { // pointer value, allocate into extent
- void *data = attachment.malloc(size(*attr));
- try {
- Attr oldSlot = *slot;
- *slot = attributes[0];
- CopyWalker copier(data);
- walk(copier, *slot);
- if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
- *slot = oldSlot;
- CssmError::throwMe(err);
- }
- } catch (...) {
- attachment.free(data);
- throw;
- }
- extent = data;
- return;
- }
- }
- }
- }
-
- // slow form: build a new value table and get rid of the old one
- Context::Builder builder(attachment);
- for (unsigned n = 0; n < count; n++)
- builder.setup(attributes[n]);
- for (unsigned n = 0; n < attributesInUse(); n++)
- if (!find(ContextAttributes[n].AttributeType, attributes, count))
- builder.setup(ContextAttributes[n]);
- builder.make();
- for (unsigned n = 0; n < count; n++)
- builder.put(attributes[n]);
- for (unsigned n = 0; n < attributesInUse(); n++)
- if (!find(ContextAttributes[n].AttributeType, attributes, count))
- builder.put(ContextAttributes[n]);
-
- // Carefully, now! The CSP may yet tell us to back out.
- // First, save the old values...
- CSSM_CONTEXT_ATTRIBUTE *oldAttributes = ContextAttributes;
- uint32 oldCount = NumberOfAttributes;
-
- // ...install new blob into the context...
- builder.done(ContextAttributes, NumberOfAttributes);
-
- // ...and ask the CSP whether this is okay
- if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
- // CSP refused; put everything back where it belongs
- attachment.free(ContextAttributes);
- ContextAttributes = oldAttributes;
- NumberOfAttributes = oldCount;
- CssmError::throwMe(err);
- }
-
- // we succeeded, so NOW delete the old attributes blob
- attachment.free(oldAttributes);
-}
-
-
-//
-// Ask the CSP to validate a proposed (and already implemented) change
-//
-CSSM_RETURN HandleContext::validateChange(CSSM_CONTEXT_EVENT event)
-{
- // lock down the module if it is not thread-safe
- StLock<Module, &Module::safeLock, &Module::safeUnlock> _(attachment.module);
- return attachment.downcalls.EventNotify(attachment.handle(),
- event, handle(), this);
-}
-
-
-//
-// Wrap up a deluxe context creation operation and return the new CC handle.
-//
-CSSM_CC_HANDLE HandleContext::Maker::operator () (CSSM_CONTEXT_TYPE type,
- CSSM_ALGORITHMS algorithm)
-{
- // construct the HandleContext object
- HandleContext &context = *new(attachment) HandleContext(attachment, type, algorithm);
- context.CSPHandle = attachment.handle();
- done(context.ContextAttributes, context.NumberOfAttributes);
-
- // ask the CSP for consent
- if (CSSM_RETURN err = context.validateChange(CSSM_CONTEXT_EVENT_CREATE)) {
- // CSP refused; clean up and fail
- context.destroy(&context, context.attachment);
- CssmError::throwMe(err);
- }
-
- // return the new handle (we have succeeded)
- return context.handle();
-}