1/*
2 * Copyright (c) 2000-2001,2003-2004,2006,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// You may also want to look at cssmcontext.h in CSSM proper, where CSSM's internal Context
36// objects are built on top of our Context class.
37//
38#include <security_cdsa_utilities/context.h>
39
40
41//
42// Construct Context objects
43//
44Context::Context(CSSM_CONTEXT_TYPE type, CSSM_ALGORITHMS algorithmId)
45{
46	clearPod();
47	ContextType = type;
48	AlgorithmType = algorithmId;
49}
50
51
52//
53// Delete a single attribute from a Context by type.
54// We implement this by simply nulling out the slot - the memory is not released,
55// and will not be reclaimed until the Context is deleted or reconstructed for some reason.
56//
57void Context::deleteAttribute(CSSM_ATTRIBUTE_TYPE type)
58{
59    for (uint32 n = 0; n < attributesInUse(); n++)
60        if (ContextAttributes[n].AttributeType == type) {
61            ContextAttributes[n].AttributeType = CSSM_ATTRIBUTE_NONE;
62            ContextAttributes[n].AttributeLength = 0;
63            return;
64        }
65    // not found
66    CssmError::throwMe(CSSMERR_CSSM_ATTRIBUTE_NOT_IN_CONTEXT);
67}
68
69
70//
71// This swiss-army-knife function performs a deep copy of all of a Context's attributes,
72// bundling them up into a single memory node and storing them into a pointer/count pair.
73// It also returns the size of the memory block allocated, in case you care (IPC does).
74//
75size_t Context::copyAttributes(CSSM_CONTEXT_ATTRIBUTE * &attrs, uint32 &count,
76							   Allocator &alloc) const
77{
78    Context::Builder builder(alloc);
79    for (unsigned n = 0; n < attributesInUse(); n++)
80        builder.setup(ContextAttributes[n]);
81    size_t size = builder.make();
82    for (unsigned n = 0; n < attributesInUse(); n++)
83        builder.put(ContextAttributes[n]);
84    builder.done(attrs, count);
85	return size;
86}
87
88
89//
90// Locate attribute values by type.
91// This function deals in attribute vectors, not contexts; hence the explicit count argument.
92// Returns NULL for attribute not found.
93//
94Context::Attr *Context::find(CSSM_ATTRIBUTE_TYPE theType,
95                             const CSSM_CONTEXT_ATTRIBUTE *attrs, unsigned int count)
96{
97    for (unsigned n = 0; n < count; n++)
98        if (attrs[n].AttributeType == theType)
99            return (Attr *)&attrs[n];
100    return NULL;
101}
102
103
104//
105// Post-IPC context fixup.
106// A Context is transmitted via IPC as a two-element blob. The first is the Context
107// structure itself, which is taken as flat. The second is the flattened attribute
108// vector blob as produced by the Context::Builder class. Since IPC will relocate
109// each blob, we need to offset all internal pointers to compensate.
110//
111void Context::postIPC(void *base, CSSM_CONTEXT_ATTRIBUTE *ipcAttributes)
112{
113	ReconstituteWalker relocator(LowLevelMemoryUtilities::difference(ipcAttributes, base));
114	ContextAttributes = ipcAttributes;	// fix context->attr vector link
115	for (uint32 n = 0; n < attributesInUse(); n++)
116		walk(relocator, (*this)[n]);
117}
118
119
120//
121// Context Builders
122//
123size_t Context::Builder::make()
124{
125    size_t vectorSize =
126		LowLevelMemoryUtilities::alignUp(slotCount * sizeof(CSSM_CONTEXT_ATTRIBUTE));
127    size_t totalSize = vectorSize + sizer;
128    attributes = reinterpret_cast<Attr *>(allocator.malloc(totalSize));
129    copier = LowLevelMemoryUtilities::increment(attributes, vectorSize);
130    slot = 0;
131	return totalSize;
132}
133
134void Context::Builder::done(CSSM_CONTEXT_ATTRIBUTE * &attributes, uint32 &count)
135{
136    assert(slot == slotCount);	// match pass profiles
137    attributes = this->attributes;
138    count = slotCount;
139    this->attributes = NULL;	// delivered the goods, no longer our responsibility
140}
141
142
143//
144// Debugging support
145//
146#if defined(DEBUGDUMP)
147
148static void dumpData(CSSM_DATA *data)
149{
150	if (data == NULL)
151		Debug::dump("[NULL]");
152	else
153		Debug::dump("[%p,%ld]@%p", data->Data, data->Length, data);
154}
155
156void Context::Attr::dump() const
157{
158    Debug::dump(" Attr{type=%x, size=%d, value=", int(AttributeType), int(AttributeLength));
159    switch (AttributeType & CSSM_ATTRIBUTE_TYPE_MASK) {
160        case CSSM_ATTRIBUTE_DATA_UINT32:
161            Debug::dump("%ld", long(Attribute.Uint32)); break;
162        case CSSM_ATTRIBUTE_DATA_STRING:
163            Debug::dump("%s@%p", Attribute.String, Attribute.String); break;
164		case CSSM_ATTRIBUTE_DATA_CSSM_DATA:
165			dumpData(Attribute.Data);
166			break;
167		case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA:
168			dumpData(&Attribute.CryptoData->Param);
169			break;
170        default:
171            Debug::dump("%p", Attribute.String); break;	// (slightly unclean)
172    };
173    Debug::dump("}\n");
174}
175
176void Context::dump(const char *title, const CSSM_CONTEXT_ATTRIBUTE *attrs) const
177{
178	if (attrs == NULL)
179		attrs = ContextAttributes;
180    Debug::dump("Context %s{type=%d, alg=%d, CSP=%u, %d attributes@%p:\n",
181		   title ? title : "",
182           int(ContextType), int(AlgorithmType), (unsigned int)CSPHandle,
183           int(NumberOfAttributes), attrs);
184    for (unsigned int n = 0; n < NumberOfAttributes; n++)
185        Attr::overlay(attrs[n]).dump();
186    Debug::dump("} // end Context\n");
187}
188
189#endif //DEBUGDUMP
190