1/*
2 * Copyright (c) 2000-2002,2011-2012,2014 Apple 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// cspclient - client interface to CSSM CSPs and their operations
21//
22#include <security_cdsa_client/cspclient.h>
23
24namespace Security {
25namespace CssmClient {
26
27
28//
29// Manage CSP attachments
30//
31CSPImpl::CSPImpl(const Guid &guid) : AttachmentImpl(guid, CSSM_SERVICE_CSP)
32{
33}
34
35CSPImpl::CSPImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_CSP)
36{
37}
38
39CSPImpl::~CSPImpl()
40{
41}
42
43
44//
45// Delete a key explicitly
46//
47void CSPImpl::freeKey(CssmKey &key, const AccessCredentials *cred, bool permanent)
48{
49    check(CSSM_FreeKey(handle(), cred, &key, permanent));
50}
51
52
53//
54// Manage generic context objects
55//
56Context::Context(const CSP &csp, CSSM_ALGORITHMS alg)
57: ObjectImpl(csp), mAlgorithm(alg), mStaged(false), mCred(NULL)
58{
59}
60
61Context::~Context()
62{
63	try
64	{
65		deactivate();
66	} catch(...) {}
67}
68
69void Context::init()
70{
71	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
72}
73
74void Context::deactivate()
75{
76    StLock<Mutex> _(mActivateMutex);
77	if (mActive)
78	{
79		mActive = false;
80		check(CSSM_DeleteContext(mHandle));
81	}
82}
83
84
85void Context::algorithm(CSSM_ALGORITHMS alg)
86{
87	if (isActive())
88		abort();	//@@@ can't (currently?) change algorithm with active context
89	mAlgorithm = alg;
90}
91
92
93void Context::cred(const CSSM_ACCESS_CREDENTIALS *cred)
94{
95	mCred = AccessCredentials::overlay(cred);
96    set(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, *mCred);
97}
98
99
100//
101// Query context operation output sizes.
102//
103uint32 Context::getOutputSize(uint32 inputSize, bool encrypt /*= true*/)
104{
105    CSSM_QUERY_SIZE_DATA data;
106    data.SizeInputBlock = inputSize;
107    getOutputSize(data, 1, encrypt);
108    return data.SizeOutputBlock;
109}
110
111void Context::getOutputSize(CSSM_QUERY_SIZE_DATA &sizes, uint32 count, bool encrypt /*= true*/)
112{
113    check(CSSM_QuerySize(handle(), encrypt, count, &sizes));
114}
115
116
117//
118// The override() method of Context is an expert feature. It replaces the entire
119// context with a context object provided. It is up to the caller to keep this context
120// consistent with the purpose of the Context subclass he is (mis)using.
121// This feature is currently used by the SecurityServer.
122//
123void Context::override(const Security::Context &ctx)
124{
125	if (!isActive()) {
126		// make a valid context object (it doesn't matter what kind - keep it cheap)
127		check(CSSM_CSP_CreateDigestContext(attachment()->handle(), CSSM_ALGID_NONE, &mHandle));
128	}
129	// now replace everything with the context data provided
130	check(CSSM_SetContext(mHandle, &ctx));
131	mActive = true;		// now active
132}
133
134
135//
136// RccContexts
137//
138const ResourceControlContext &RccBearer::compositeRcc() const
139{
140	// explicitly specified RCC wins
141	if (mRcc)
142		return *mRcc;
143
144	// cobble one up from the pieces
145	if (mOwner)
146		mWorkRcc.input() = *mOwner;
147	else
148		mWorkRcc.clearPod();
149	mWorkRcc.credentials(mOpCred);
150	return mWorkRcc;
151}
152
153
154void RccBearer::owner(const CSSM_ACL_ENTRY_PROTOTYPE *owner)
155{
156	if (owner) {
157		mWorkInput = *owner;
158		this->owner(mWorkInput);
159	} else
160		this->owner((AclEntryInput*)NULL);
161}
162
163
164//
165// Manage PassThrough contexts
166//
167
168//
169// Invoke passThrough
170//
171void
172PassThrough::operator() (uint32 passThroughId, const void *inData, void **outData)
173{
174    check(CSSM_CSP_PassThrough(handle(), passThroughId, inData, outData));
175}
176
177void PassThrough::activate()
178{
179    StLock<Mutex> _(mActivateMutex);
180	if (!mActive) {
181		check(CSSM_CSP_CreatePassThroughContext(attachment()->handle(), mKey, &mHandle));
182		mActive = true;
183	}
184}
185
186
187//
188// Manage Digest contexts
189//
190void Digest::activate()
191{
192    StLock<Mutex> _(mActivateMutex);
193	if (!mActive) {
194		check(CSSM_CSP_CreateDigestContext(attachment()->handle(), mAlgorithm, &mHandle));
195		mActive = true;
196	}
197}
198
199
200void Digest::digest(const CssmData *data, uint32 count, CssmData &digest)
201{
202	activate();
203	if (mStaged)
204		Error::throwMe(CSSMERR_CSP_STAGED_OPERATION_IN_PROGRESS);
205	check(CSSM_DigestData(handle(), data, count, &digest));
206}
207
208void Digest::digest(const CssmData *data, uint32 count)
209{
210	activate();
211	if (!mStaged) {
212		check(CSSM_DigestDataInit(handle()));
213		mStaged = true;
214	}
215	check(CSSM_DigestDataUpdate(handle(), data, count));
216}
217
218void Digest::operator () (CssmData &digest)
219{
220	if (!mStaged)
221		Error::throwMe(CSSMERR_CSP_STAGED_OPERATION_NOT_STARTED);
222	check(CSSM_DigestDataFinal(handle(), &digest));
223	mStaged = false;
224}
225
226
227//
228// Random number generation
229//
230void Random::seed(const CssmCryptoData &seedData)
231{
232	mSeed = &seedData;
233	set(CSSM_ATTRIBUTE_SEED, seedData);
234}
235
236void Random::size(uint32 sz)
237{
238	mSize = sz;
239	set(CSSM_ATTRIBUTE_OUTPUT_SIZE, sz);
240}
241
242
243void Random::activate()
244{
245    StLock<Mutex> _(mActivateMutex);
246	if (!mActive) {
247		check(CSSM_CSP_CreateRandomGenContext(attachment()->handle(), mAlgorithm,
248			mSeed, mSize, &mHandle));
249		mActive = true;
250	}
251}
252
253
254void Random::generate(CssmData &data, uint32 newSize)
255{
256	if (newSize)
257		size(newSize);
258	activate();
259	assert(!mStaged);	// not a stage-able operation
260	check(CSSM_GenerateRandom(handle(), &data));
261}
262
263} // end namespace CssmClient
264} // end namespace Security
265