]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/bsafeContext.cpp
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / bsafeContext.cpp
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
35 A_SURRENDER_CTX * const BSafe::BSafeContext::bsSurrender = NULL;
36
37
38 //
39 // Construct an algorithm object
40 //
41 BSafe::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
59 BSafe::BSafeContext::~BSafeContext()
60 {
61 reset();
62 }
63
64 void 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 */
75 void 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
87 void 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
126 void 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 */
136 void 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 */
144 void 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 //
162 void 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 //
184 void 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
230 void 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
316 void 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 //
332 void 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
338 void 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
345 void 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
359 void 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)
382 void 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
412 size_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
418 void BSafe::BSafeContext::trackUpdate(size_t, size_t)
419 { /* do nothing */ }
420
421 //
422 // Common features of CipherContexts.
423 //
424 void 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