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