2 * Copyright (c) 2000-2002,2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // context - manage CSSM (cryptographic) contexts every which way.
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.
36 #define _CPP_CSSMCONTEXT
38 #include "cssmcontext.h"
42 // Destroy a HandleContext.
44 HandleContext::~HandleContext()
46 attachment
.free(extent
);
47 attachment
.free(ContextAttributes
);
52 // Locking protocol for HandleContexts
54 void HandleContext::lock()
55 { attachment
.enter(); }
57 bool HandleContext::tryLock()
58 { return attachment
.tryEnter(); }
62 // Merge a new set of attributes into an existing HandleContext, copying
63 // the new values deeply while releasing corresponding old values.
65 // NOTE: This is a HandleContext method; it does not work on bare Contexts.
67 void HandleContext::mergeAttributes(const CSSM_CONTEXT_ATTRIBUTE
*attributes
, uint32 count
)
69 // attempt to fast-path some simple or frequent cases
71 if (Attr
*attr
= find(attributes
[0].AttributeType
)) {
72 if (attr
->baseType() == CSSM_ATTRIBUTE_DATA_UINT32
) {
73 // try quick replacement
75 *attr
= attributes
[0];
76 if (CSSM_RETURN err
= validateChange(CSSM_CONTEXT_EVENT_UPDATE
)) {
79 CssmError::throwMe(err
);
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]);
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
)) {
94 CssmError::throwMe(err
);
97 CopyWalker
copier(oldAttr
.Attribute
.String
);
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
;
108 if (CSSM_RETURN err
= validateChange(CSSM_CONTEXT_EVENT_UPDATE
)) {
110 CssmError::throwMe(err
);
114 } else if (extent
== NULL
) { // pointer value, allocate into extent
115 void *data
= attachment
.malloc(size(*attr
));
117 Attr oldSlot
= *slot
;
118 *slot
= attributes
[0];
119 CopyWalker
copier(data
);
121 if (CSSM_RETURN err
= validateChange(CSSM_CONTEXT_EVENT_UPDATE
)) {
123 CssmError::throwMe(err
);
126 attachment
.free(data
);
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
]);
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
]);
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
;
155 // ...install new blob into the context...
156 builder
.done(ContextAttributes
, NumberOfAttributes
);
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
);
167 // we succeeded, so NOW delete the old attributes blob
168 attachment
.free(oldAttributes
);
173 // Ask the CSP to validate a proposed (and already implemented) change
175 CSSM_RETURN
HandleContext::validateChange(CSSM_CONTEXT_EVENT event
)
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);
185 // Wrap up a deluxe context creation operation and return the new CC handle.
187 CSSM_CC_HANDLE
HandleContext::Maker::operator () (CSSM_CONTEXT_TYPE type
,
188 CSSM_ALGORITHMS algorithm
)
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
);
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
);
202 // return the new handle (we have succeeded)
203 return context
.handle();