]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cssm/lib/cssmcontext.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_cssm / lib / 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 }