1/*
2 * Copyright (c) 2000-2001,2011,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#ifdef	BSAFE_CSP_ENABLE
19
20
21//
22// bsafeContext.cpp - implementation of class BSafe::BSafeContext
23//					  and some of its subclasses
24//
25
26#include "bsafecspi.h"
27#include "bsafePKCS1.h"
28#include <bkey.h>
29#include <balg.h>
30#include <algobj.h>
31#include "cspdebugging.h"
32
33#define DATA(cData)		POINTER(cData.data()), cData.length()
34
35A_SURRENDER_CTX * const BSafe::BSafeContext::bsSurrender = NULL;
36
37
38//
39// Construct an algorithm object
40//
41BSafe::BSafeContext::BSafeContext(AppleCSPSession &session)
42	: AppleCSPContext(session)
43{
44    bsAlgorithm = NULL;
45    bsKey = NULL;
46	bsBinKey = NULL;
47    bsRandom = NULL;
48    initialized = false;
49	opStarted = false;
50#ifdef SAFER
51    inUpdate = NULL;
52    inOutUpdate = NULL;
53    inFinal = NULL;
54    outFinal = NULL;
55    outFinalR = NULL;
56#endif //SAFER
57}
58
59BSafe::BSafeContext::~BSafeContext()
60{
61    reset();
62}
63
64void BSafe::BSafeContext::reset()
65{
66    B_DestroyAlgorithmObject(&bsAlgorithm);
67    B_DestroyAlgorithmObject(&bsRandom);
68	destroyBsKey();
69}
70
71/*
72 * Clear key state. We only destroy bsKey if we don't have a
73 * BinaryKey.
74 */
75void BSafe::BSafeContext::destroyBsKey()
76{
77	if(bsBinKey == NULL) {
78		B_DestroyKeyObject(&bsKey);
79	}
80	else {
81		// bsKey gets destroyed when bsBinKey gets deleted
82		bsBinKey = NULL;
83		bsKey = NULL;
84	}
85}
86
87void BSafe::check(int status, bool isKeyOp)
88{
89	if(status == 0) {
90		return;
91	}
92	dprintf1("BSAFE Error %d\n", status);
93    switch (status) {
94		case BE_ALLOC:
95			throw std::bad_alloc();
96		case BE_SIGNATURE:
97			CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
98		case BE_OUTPUT_LEN:
99			CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
100		case BE_INPUT_LEN:
101			CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
102		case BE_EXPONENT_EVEN:
103		case BE_EXPONENT_LEN:
104		case BE_EXPONENT_ONE:
105			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
106		case BE_DATA:
107		case BE_INPUT_DATA:
108			if(isKeyOp) {
109				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
110			}
111			else {
112				CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
113			}
114		case BE_MODULUS_LEN:
115		case BE_OVER_32K:
116		case BE_INPUT_COUNT:
117		case BE_CANCEL:
118			//@@@ later...
119        default:
120			//@@@ translate BSafe errors intelligently
121            CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
122    }
123}
124
125
126void BSafe::BSafeContext::setAlgorithm(
127	B_INFO_TYPE bAlgType,
128	const void *info)
129{
130    B_DestroyAlgorithmObject(&bsAlgorithm);	// clear any old BSafe algorithm
131    check(B_CreateAlgorithmObject(&bsAlgorithm));
132    check(B_SetAlgorithmInfo(bsAlgorithm, bAlgType, POINTER(info)));
133}
134
135/* safely create bsKey */
136void BSafe::BSafeContext::createBsKey()
137{
138	/* reset to initial key state - some keys can't be reused */
139    destroyBsKey();
140    check(B_CreateKeyObject(&bsKey));
141}
142
143/* form of *info varies per bKeyInfo */
144void BSafe::BSafeContext::setKeyAtom(
145	B_INFO_TYPE bKeyInfo,
146	const void *info)
147{
148	/* debug only */
149	if((bKeyInfo == KI_RSAPublicBER) || (bKeyInfo == KI_RSAPublic)) {
150			printf("Aargh! Unhandled KI_RSAPublic!\n");
151			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
152	}
153	assert(bKeyInfo != KI_RSAPublicBER);		// handled elsewhere for now
154	assert(bKeyInfo != KI_RSAPublic);			// handled elsewhere for now
155	createBsKey();
156    check(B_SetKeyInfo(bsKey, bKeyInfo, POINTER(info)), true);
157}
158
159//
160// Set outSize for RSA keys.
161//
162void BSafe::BSafeContext::setRsaOutSize(
163	bool isPubKey)
164{
165	assert(bsKey != NULL);
166
167	A_RSA_KEY *keyInfo;
168	if(isPubKey) {
169		keyInfo = getKey<A_RSA_KEY>(bsKey, KI_RSAPublic);
170	}
171	else {
172		keyInfo = getKey<A_RSA_KEY>(bsKey, KI_RSAPrivate);
173	}
174	mOutSize = (B_IntegerBits(keyInfo->modulus.data,
175		keyInfo->modulus.len) + 7) / 8;
176}
177
178//
179// Handle various forms of reference key. Symmetric
180// keys are stored as SymmetricBinaryKey, with raw key bytes
181// in keyData. Our asymmetric keys are stored as BSafeBinaryKeys,
182// with an embedded ready-to-use B_KEY_OBJ.
183//
184void BSafe::BSafeContext::setRefKey(CssmKey &key)
185{
186	bool isPubKey = false;
187
188	switch(key.keyClass()) {
189		case CSSM_KEYCLASS_SESSION_KEY:
190		{
191			assert(key.blobFormat() ==
192				CSSM_KEYBLOB_REF_FORMAT_INTEGER);
193
194			BinaryKey &binKey = session().lookupRefKey(key);
195			// fails if this is not a SymmetricBinaryKey
196			SymmetricBinaryKey *symBinKey =
197				dynamic_cast<SymmetricBinaryKey *>(&binKey);
198			if(symBinKey == NULL) {
199				errorLog0("BSafe::setRefKey(1): wrong BinaryKey subclass\n");
200				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
201			}
202			setKeyFromCssmData(KI_Item, symBinKey->mKeyData);
203			return;
204		}
205		case CSSM_KEYCLASS_PUBLIC_KEY:
206			isPubKey = true;		// and fall thru
207		case CSSM_KEYCLASS_PRIVATE_KEY:
208		{
209			BinaryKey &binKey = session().lookupRefKey(key);
210			destroyBsKey();
211			bsBinKey = dynamic_cast<BSafeBinaryKey *>(&binKey);
212			/* this cast failing means that this is some other
213			 * kind of binary key */
214			if(bsBinKey == NULL) {
215				errorLog0("BSafe::setRefKey(2): wrong BinaryKey subclass\n");
216				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
217			}
218			assert(bsBinKey->bsKey() != NULL);
219			bsKey = bsBinKey->bsKey();
220			if(key.algorithm() == CSSM_ALGID_RSA) {
221				setRsaOutSize(isPubKey);
222			}
223			return;
224		}
225		default:
226		    CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
227	}
228}
229
230void BSafe::BSafeContext::setKeyFromContext(
231	const Context &context,
232	bool required)
233{
234    CssmKey &key =
235		context.get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
236
237	switch(key.blobType()) {
238		case CSSM_KEYBLOB_REFERENCE:
239			setRefKey(key);
240			return;
241		case CSSM_KEYBLOB_RAW:
242			break;		// to main routine
243		default:
244			CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
245	}
246
247	bool isPubKey;
248	switch (key.keyClass()) {
249		case CSSM_KEYCLASS_SESSION_KEY:
250			/* symmetric, one format supported for all algs */
251			switch (key.blobFormat()) {
252				case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
253					setKeyFromCssmKey(KI_Item, key);
254					return;
255				default:
256					CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
257			}
258		case CSSM_KEYCLASS_PUBLIC_KEY:
259			isPubKey = true;
260			break;
261		case CSSM_KEYCLASS_PRIVATE_KEY:
262			isPubKey = false;
263			break;
264		default:
265			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
266	}
267
268	/* We know it's an asymmetric key; get some info */
269	B_INFO_TYPE infoType;
270	CSSM_KEYBLOB_FORMAT expectedFormat;
271
272	if(!bsafeAlgToInfoType(key.algorithm(),
273		isPubKey,
274		infoType,
275		expectedFormat)) {
276		/* unknown alg! */
277		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
278	}
279
280	/*
281	 * Correct format?
282	 * NOTE: if we end up supporting multiple incoming key formats, they'll
283	 * have to be handled here.
284	 */
285	if(expectedFormat != key.blobFormat()) {
286		errorLog1("setKeyFromContext: invalid blob format (%d)\n",
287			(int)key.blobFormat());
288		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
289	}
290
291	/*
292	 * Most formats can be handled directly by BSAFE. Handle the special cases
293	 * requiring additional processing here.
294	 */
295	switch(expectedFormat)  {
296		case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
297			/* RSA public keys */
298			createBsKey();
299			BS_setKeyPkcs1(CssmData::overlay(key.KeyData), bsKey);
300			break;
301		default:
302			setKeyFromCssmKey(infoType, key);
303			break;
304	}
305
306	/*
307	 * One more thing - set mOutSize for RSA keys
308	 */
309	if(key.algorithm() == CSSM_ALGID_RSA) {
310		setRsaOutSize(isPubKey);
311	}
312}
313
314#define BSAFE_RANDSIZE	32
315
316void BSafe::BSafeContext::setRandom()
317{
318    if (bsRandom == NULL) {
319        check(B_CreateAlgorithmObject(&bsRandom));
320        check(B_SetAlgorithmInfo(bsRandom, AI_X962Random_V0, NULL_PTR));
321        check(B_RandomInit(bsRandom, chooser(), bsSurrender));
322        uint8 seed[BSAFE_RANDSIZE];
323		session().getRandomBytes(BSAFE_RANDSIZE, seed);
324        check(B_RandomUpdate(bsRandom, seed, sizeof(seed), bsSurrender));
325    }
326}
327
328
329//
330// Operational methods of BSafeContext
331//
332void BSafe::BSafeContext::init(const Context &, bool)
333{
334    // some algorithms don't need init(), because all is done in the context constructor
335}
336
337// update for input-only block/stream algorithms
338void BSafe::BSafeContext::update(const CssmData &data)
339{
340	opStarted = true;
341    check(inUpdate(bsAlgorithm, POINTER(data.data()), data.length(), bsSurrender));
342}
343
344// update for input/output block/stream algorithms
345void BSafe::BSafeContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
346{
347    unsigned int length;
348	opStarted = true;
349    check(inOutUpdate(bsAlgorithm, POINTER(outp), &length, outSize,
350                               POINTER(inp), inSize, bsRandom, bsSurrender));
351    // always eat all input (inSize unchanged)
352    outSize = length;
353
354    // let the algorithm manager track I/O sizes, if needed
355    trackUpdate(inSize, outSize);
356}
357
358// output-generating final call
359void BSafe::BSafeContext::final(CssmData &out)
360{
361    unsigned int length;
362    if (outFinal) {
363        check(outFinal(bsAlgorithm,
364			POINTER(out.data()),
365			&length,
366			out.length(),
367			bsSurrender));
368	}
369    else {
370        check(outFinalR(bsAlgorithm,
371			POINTER(out.data()),
372			&length,
373			out.length(),
374			bsRandom,
375			bsSurrender));
376	}
377    out.length(length);
378	initialized = false;
379}
380
381// verifying final call (takes additional input)
382void BSafe::BSafeContext::final(const CssmData &in)
383{
384 	int status;
385
386	/* note sig verify errors can show up as lots of BSAFE statuses;
387	 * munge them all into the appropriate error */
388   if (inFinal) {
389        status = inFinal(bsAlgorithm,
390			POINTER(in.data()),
391			in.length(),
392			bsSurrender);
393	}
394    else {
395        status = inFinalR(bsAlgorithm,
396			POINTER(in.data()),
397			in.length(),
398			bsRandom,
399			bsSurrender);
400	}
401	if(status != 0) {
402		if((mType == CSSM_ALGCLASS_SIGNATURE) && (mDirection == false)) {
403			/* yep, sig verify error */
404			CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
405		}
406		/* other error, use standard trap */
407		check(status);
408	}
409	initialized = false;
410}
411
412size_t BSafe::BSafeContext::outputSize(bool final, size_t inSize)
413{
414    // this default implementation only makes sense for single-output end-loaded algorithms
415    return final ? mOutSize : 0;
416}
417
418void BSafe::BSafeContext::trackUpdate(size_t, size_t)
419{ /* do nothing */ }
420
421//
422// Common features of CipherContexts.
423//
424void BSafe::CipherContext::cipherInit()
425{
426    // set handlers
427    if (encoding) {
428        inOutUpdate = B_EncryptUpdate;
429        outFinalR = B_EncryptFinal;
430    } else {
431        inOutUpdate = B_DecryptUpdate;
432        outFinalR = B_DecryptFinal;
433    }
434    outFinal = NULL;
435
436    // init the algorithm
437    check((encoding ? B_EncryptInit : B_DecryptInit)
438          (bsAlgorithm, bsKey, chooser(), bsSurrender));
439
440    // buffers start empty
441    pending = 0;
442
443    // state is now valid
444    initialized = true;
445	opStarted = false;
446}
447#endif	/* BSAFE_CSP_ENABLE */
448
449