]> git.saurik.com Git - apple/security.git/blob - cdsa/cssm/cssmcontext.cpp
Security-179.tar.gz
[apple/security.git] / cdsa / cssm / cssmcontext.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // context - manage CSSM (cryptographic) contexts every which way.
21 //
22 // A note on memory management:
23 // Context attributes are allocated from application memory in big chunks comprising
24 // many attributes as well as the attribute array itself. The CSSM_CONTEXT fields
25 // NumberOfAttributes and ContextAttributes are handled as a group. Context::Builder
26 // and Context::copyFrom assume these fields are undefined and fill them. Context::clear
27 // assumes they are valid and invalides them, freeing memory.
28 //
29 #ifdef __MWERKS__
30 #define _CPP_CSSMCONTEXT
31 #endif
32 #include "cssmcontext.h"
33
34
35 //
36 // Destroy a HandleContext.
37 //
38 HandleContext::~HandleContext()
39 {
40 attachment.free(extent);
41 attachment.free(ContextAttributes);
42 }
43
44
45 //
46 // Locking protocol for HandleContexts
47 //
48 void HandleContext::lock()
49 { attachment.enter(); }
50
51 bool HandleContext::tryLock()
52 { return attachment.tryEnter(); }
53
54
55 //
56 // Merge a new set of attributes into an existing HandleContext, copying
57 // the new values deeply while releasing corresponding old values.
58 //
59 // NOTE: This is a HandleContext method; it does not work on bare Contexts.
60 //
61 void HandleContext::mergeAttributes(const CSSM_CONTEXT_ATTRIBUTE *attributes, uint32 count)
62 {
63 // attempt to fast-path some simple or frequent cases
64 if (count == 1) {
65 if (Attr *attr = find(attributes[0].AttributeType)) {
66 if (attr->baseType() == CSSM_ATTRIBUTE_DATA_UINT32) {
67 // try quick replacement
68 Attr oldAttr = *attr;
69 *attr = attributes[0];
70 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
71 // roll back and fail
72 *attr = oldAttr;
73 CssmError::throwMe(err);
74 }
75 return; // all done
76 } else {
77 // pointer value - does it fit into the space of the current value?
78 size_t oldSize = size(*attr);
79 size_t newSize = size(attributes[0]);
80 Attr oldAttr = *attr;
81 if (newSize <= oldSize) { // give it a try...
82 *attr = attributes[0];
83 // NOTE that the CSP is getting a "temporary" pointer set to validate;
84 // If we commit, the final copy will be elsewhere. CSP writer beware!
85 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
86 // roll back and fail
87 *attr = oldAttr;
88 CssmError::throwMe(err);
89 }
90 // commit new value
91 CopyWalker copier(oldAttr.Attribute.String);
92 walk(copier, *attr);
93 return;
94 }
95 }
96 } else { // single change, new attribute
97 if (Attr *slot = find(CSSM_ATTRIBUTE_NONE)) {
98 const Attr *attr = static_cast<const Attr *>(&attributes[0]);
99 if (attr->baseType() == CSSM_ATTRIBUTE_DATA_UINT32) { // trivial
100 Attr oldSlot = *slot;
101 *slot = *attr;
102 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
103 *slot = oldSlot;
104 CssmError::throwMe(err);
105 }
106 // already ok
107 return;
108 } else if (extent == NULL) { // pointer value, allocate into extent
109 void *data = attachment.malloc(size(*attr));
110 try {
111 Attr oldSlot = *slot;
112 *slot = attributes[0];
113 CopyWalker copier(data);
114 walk(copier, *slot);
115 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
116 *slot = oldSlot;
117 CssmError::throwMe(err);
118 }
119 } catch (...) {
120 attachment.free(data);
121 throw;
122 }
123 extent = data;
124 return;
125 }
126 }
127 }
128 }
129
130 // slow form: build a new value table and get rid of the old one
131 Context::Builder builder(attachment);
132 for (unsigned n = 0; n < count; n++)
133 builder.setup(attributes[n]);
134 for (unsigned n = 0; n < attributesInUse(); n++)
135 if (!find(ContextAttributes[n].AttributeType, attributes, count))
136 builder.setup(ContextAttributes[n]);
137 builder.make();
138 for (unsigned n = 0; n < count; n++)
139 builder.put(attributes[n]);
140 for (unsigned n = 0; n < attributesInUse(); n++)
141 if (!find(ContextAttributes[n].AttributeType, attributes, count))
142 builder.put(ContextAttributes[n]);
143
144 // Carefully, now! The CSP may yet tell us to back out.
145 // First, save the old values...
146 CSSM_CONTEXT_ATTRIBUTE *oldAttributes = ContextAttributes;
147 uint32 oldCount = NumberOfAttributes;
148
149 // ...install new blob into the context...
150 builder.done(ContextAttributes, NumberOfAttributes);
151
152 // ...and ask the CSP whether this is okay
153 if (CSSM_RETURN err = validateChange(CSSM_CONTEXT_EVENT_UPDATE)) {
154 // CSP refused; put everything back where it belongs
155 attachment.free(ContextAttributes);
156 ContextAttributes = oldAttributes;
157 NumberOfAttributes = oldCount;
158 CssmError::throwMe(err);
159 }
160
161 // we succeeded, so NOW delete the old attributes blob
162 attachment.free(oldAttributes);
163 }
164
165
166 //
167 // Ask the CSP to validate a proposed (and already implemented) change
168 //
169 CSSM_RETURN HandleContext::validateChange(CSSM_CONTEXT_EVENT event)
170 {
171 // lock down the module if it is not thread-safe
172 StLock<Module, &Module::safeLock, &Module::safeUnlock> _(attachment.module);
173 return attachment.downcalls.EventNotify(attachment.handle(),
174 event, handle(), this);
175 }
176
177
178 //
179 // Wrap up a deluxe context creation operation and return the new CC handle.
180 //
181 CSSM_CC_HANDLE HandleContext::Maker::operator () (CSSM_CONTEXT_TYPE type,
182 CSSM_ALGORITHMS algorithm)
183 {
184 // construct the HandleContext object
185 HandleContext &context = *new(attachment) HandleContext(attachment, type, algorithm);
186 context.CSPHandle = attachment.handle();
187 done(context.ContextAttributes, context.NumberOfAttributes);
188
189 // ask the CSP for consent
190 if (CSSM_RETURN err = context.validateChange(CSSM_CONTEXT_EVENT_CREATE)) {
191 // CSP refused; clean up and fail
192 context.destroy(&context, context.attachment);
193 CssmError::throwMe(err);
194 }
195
196 // return the new handle (we have succeeded)
197 return context.handle();
198 }