1/* 2 * Copyright (c) 2000-2001 Apple Computer, 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// SSContext - cryptographic contexts for the security server 21// 22#include "SSContext.h" 23 24#include "SSCSPSession.h" 25#include "SSKey.h" 26#include <security_utilities/debugging.h> 27 28#define ssCryptDebug(args...) secdebug("ssCrypt", ## args) 29 30using namespace SecurityServer; 31 32// 33// SSContext 34// 35SSContext::SSContext(SSCSPSession &session) 36: mSession(session), mContext(NULL) 37{ 38} 39 40void SSContext::clearOutBuf() 41{ 42 if(mOutBuf.Data) { 43 mSession.free(mOutBuf.Data); 44 mOutBuf.clear(); 45 } 46} 47 48void SSContext::copyOutBuf(CssmData &out) 49{ 50 if(out.length() < mOutBuf.length()) { 51 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 52 } 53 memmove(out.Data, mOutBuf.Data, mOutBuf.Length); 54 out.Length = mOutBuf.Length; 55 clearOutBuf(); 56} 57 58void 59SSContext::init(const Context &context, 60 bool /* encoding */) // @@@ should be removed from API since it's already in mDirection 61{ 62 mContext = &context; 63 clearOutBuf(); 64} 65 66SecurityServer::ClientSession & 67SSContext::clientSession() 68{ 69 return mSession.clientSession(); 70} 71 72 73// 74// SSRandomContext -- Context for GenerateRandom operations 75// 76SSRandomContext::SSRandomContext(SSCSPSession &session) : SSContext(session) {} 77 78void 79SSRandomContext::init(const Context &context, bool encoding) 80{ 81 SSContext::init(context, encoding); 82 83 // set/freeze output size 84 mOutSize = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE); 85 86#if 0 87 // seed the PRNG (if specified) 88 if (const CssmCryptoData *seed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED)) { 89 const CssmData &seedValue = (*seed)(); 90 clientSession().seedRandom(seedValue); 91 } 92#endif 93} 94 95size_t 96SSRandomContext::outputSize(bool final, size_t inSize) 97{ 98 return mOutSize; 99} 100 101void 102SSRandomContext::final(CssmData &out) 103{ 104 clientSession().generateRandom(*mContext, out); 105} 106 107 108// signature contexts 109SSSignatureContext::SSSignatureContext(SSCSPSession &session) 110 : SSContext(session), 111 mKeyHandle(noKey), 112 mNullDigest(NULL), 113 mDigest(NULL) 114{ 115 /* nothing else for now */ 116} 117 118SSSignatureContext::~SSSignatureContext() 119{ 120 delete mNullDigest; 121 delete mDigest; 122} 123 124void SSSignatureContext::init(const Context &context, bool signing) 125{ 126 SSContext::init(context, signing); 127 128 /* reusable: skip everything except resetting digest state */ 129 if((mNullDigest != NULL) || (mDigest != NULL)) { 130 if(mNullDigest != NULL) { 131 mNullDigest->digestInit(); 132 } 133 return; 134 } 135 136 /* snag key from context */ 137 const CssmKey &keyInContext = 138 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, 139 CSSMERR_CSP_MISSING_ATTR_KEY); 140 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle(); 141 142 /* get digest alg and sig alg from Context.algorithm */ 143 switch(context.algorithm()) { 144 /*** DSA ***/ 145 case CSSM_ALGID_SHA1WithDSA: 146 mDigestAlg = CSSM_ALGID_SHA1; 147 mSigAlg = CSSM_ALGID_DSA; 148 break; 149 case CSSM_ALGID_DSA: // Raw 150 mDigestAlg = CSSM_ALGID_NONE; 151 mSigAlg = CSSM_ALGID_DSA; 152 break; 153 /*** RSA ***/ 154 case CSSM_ALGID_SHA1WithRSA: 155 mDigestAlg = CSSM_ALGID_SHA1; 156 mSigAlg = CSSM_ALGID_RSA; 157 break; 158 case CSSM_ALGID_MD5WithRSA: 159 mDigestAlg = CSSM_ALGID_MD5; 160 mSigAlg = CSSM_ALGID_RSA; 161 break; 162 case CSSM_ALGID_MD2WithRSA: 163 mDigestAlg = CSSM_ALGID_MD2; 164 mSigAlg = CSSM_ALGID_RSA; 165 break; 166 case CSSM_ALGID_SHA256WithRSA: 167 mDigestAlg = CSSM_ALGID_SHA256; 168 mSigAlg = CSSM_ALGID_RSA; 169 break; 170 case CSSM_ALGID_SHA224WithRSA: 171 mDigestAlg = CSSM_ALGID_SHA224; 172 mSigAlg = CSSM_ALGID_RSA; 173 break; 174 case CSSM_ALGID_SHA384WithRSA: 175 mDigestAlg = CSSM_ALGID_SHA384; 176 mSigAlg = CSSM_ALGID_RSA; 177 break; 178 case CSSM_ALGID_SHA512WithRSA: 179 mDigestAlg = CSSM_ALGID_SHA512; 180 mSigAlg = CSSM_ALGID_RSA; 181 break; 182 case CSSM_ALGID_RSA: // Raw 183 mDigestAlg = CSSM_ALGID_NONE; 184 mSigAlg = CSSM_ALGID_RSA; 185 break; 186 /*** FEE ***/ 187 case CSSM_ALGID_FEE_SHA1: 188 mDigestAlg = CSSM_ALGID_SHA1; 189 mSigAlg = CSSM_ALGID_FEE; 190 break; 191 case CSSM_ALGID_FEE_MD5: 192 mDigestAlg = CSSM_ALGID_MD5; 193 mSigAlg = CSSM_ALGID_FEE; 194 break; 195 case CSSM_ALGID_FEE: // Raw 196 mDigestAlg = CSSM_ALGID_NONE; 197 mSigAlg = CSSM_ALGID_FEE; 198 break; 199 /*** ECDSA ***/ 200 case CSSM_ALGID_SHA1WithECDSA: 201 mDigestAlg = CSSM_ALGID_SHA1; 202 mSigAlg = CSSM_ALGID_ECDSA; 203 break; 204 case CSSM_ALGID_SHA224WithECDSA: 205 mDigestAlg = CSSM_ALGID_SHA224; 206 mSigAlg = CSSM_ALGID_ECDSA; 207 break; 208 case CSSM_ALGID_SHA256WithECDSA: 209 mDigestAlg = CSSM_ALGID_SHA256; 210 mSigAlg = CSSM_ALGID_ECDSA; 211 break; 212 case CSSM_ALGID_SHA384WithECDSA: 213 mDigestAlg = CSSM_ALGID_SHA384; 214 mSigAlg = CSSM_ALGID_ECDSA; 215 break; 216 case CSSM_ALGID_SHA512WithECDSA: 217 mDigestAlg = CSSM_ALGID_SHA512; 218 mSigAlg = CSSM_ALGID_ECDSA; 219 break; 220 case CSSM_ALGID_ECDSA: // Raw 221 mDigestAlg = CSSM_ALGID_NONE; 222 mSigAlg = CSSM_ALGID_ECDSA; 223 break; 224 default: 225 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); 226 } 227 228 /* set up mNullDigest or mDigest */ 229 if(mDigestAlg == CSSM_ALGID_NONE) { 230 mNullDigest = new NullDigest(); 231 } 232 else { 233 mDigest = new CssmClient::Digest(mSession.mRawCsp, mDigestAlg); 234 } 235} 236 237/* 238 * for raw sign/verify - optionally called after init. 239 * Note that in init (in this case), we set mDigestAlg to ALGID_NONE and set up 240 * a NullDigest. We now overwrite mDigestAlg, and we'll use�this 241 * new value when we do the actual sign/vfy. 242 */ 243void SSSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg) 244{ 245 mDigestAlg = digestAlg; 246} 247 248void SSSignatureContext::update(const CssmData &data) 249{ 250 /* Note that for this context, we really can not deal with an out-of-sequence 251 * update --> final(true, 0) --> update since we lose the pending digest state 252 * when we perform the implied final() during outputSize(true, 0). */ 253 assert(mOutBuf.Data == NULL); 254 255 /* add incoming data to digest or accumulator */ 256 if(mNullDigest) { 257 mNullDigest->digestUpdate(data.data(), data.length()); 258 } 259 else { 260 mDigest->digest(data); 261 } 262} 263 264size_t SSSignatureContext::outputSize(bool final, size_t inSize) 265{ 266 if(!final) { 267 ssCryptDebug("===sig outputSize !final\n"); 268 return 0; 269 } 270 if(!encoding()) { 271 ssCryptDebug("===sig outputSize final, !encoding\n"); 272 /* don't see why this is even called... */ 273 return 0; 274 } 275 if(inSize == 0) { 276 /* 277 * This is the implied signal to go for it. Note that in this case, 278 * we can not go back and re-do the op in case of an unexpected 279 * sequence of update/outputSize(final, 0)/final - we lose the digest 280 * state. Perhaps we should save the digest...? But still it would 281 * be impossible to do another update. 282 */ 283 clearOutBuf(); 284 sign(mOutBuf); 285 ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf.Length); 286 return (size_t)mOutBuf.Length; 287 } 288 else { 289 /* out-of-band case, ask CSP via SS */ 290 uint32 outSize = clientSession().getOutputSize(*mContext, 291 mKeyHandle, 292 /* FIXME - what to use for inSize here - we don't want to 293 * interrogate mDigest, as that would result in another RPC... 294 * and signature size is not related to input size...right? */ 295 (uint32)inSize, 296 true); 297 ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize); 298 return (size_t)outSize; 299 } 300} 301 302/* sign */ 303 304/* first the common routine shared by final and outputSize */ 305void SSSignatureContext::sign(CssmData &sig) 306{ 307 /* we have to pass down a modified Context, thus.... */ 308 Context tempContext = *mContext; 309 tempContext.AlgorithmType = mSigAlg; 310 311 if(mNullDigest) { 312 CssmData dData(const_cast<void *>(mNullDigest->digestPtr()), 313 mNullDigest->digestSizeInBytes()); 314 clientSession().generateSignature(tempContext, 315 mKeyHandle, 316 dData, 317 sig, 318 mDigestAlg); 319 } 320 else { 321 CssmAutoData d (mDigest->allocator ()); 322 d.set((*mDigest) ()); 323 324 clientSession().generateSignature(tempContext, 325 mKeyHandle, 326 d, 327 sig, 328 mDigestAlg); 329 } 330} 331 332/* this is the one called by CSPFullPluginSession */ 333void SSSignatureContext::final(CssmData &sig) 334{ 335 if(mOutBuf.Data) { 336 /* normal final case in which the actual RPC via SS was done in the 337 * previous outputSize() call. */ 338 ssCryptDebug("===final via pre-op and copy"); 339 copyOutBuf(sig); 340 return; 341 } 342 343 ssCryptDebug("===final via RPC"); 344 sign(sig); 345} 346 347/* verify */ 348void 349SSSignatureContext::final(const CssmData &sig) 350{ 351 /* we have to pass down a modified Context, thus.... */ 352 Context tempContext = *mContext; 353 tempContext.AlgorithmType = mSigAlg; 354 355 if(mNullDigest) { 356 CssmData dData(const_cast<void *>(mNullDigest->digestPtr()), 357 mNullDigest->digestSizeInBytes()); 358 clientSession().verifySignature(tempContext, 359 mKeyHandle, 360 dData, 361 sig, 362 mDigestAlg); 363 } 364 else { 365 CssmData digst = (*mDigest)(); 366 try { 367 clientSession().verifySignature(tempContext, 368 mKeyHandle, 369 digst, 370 sig, 371 mDigestAlg); 372 } 373 catch (...) { 374 mDigest->allocator().free(digst.Data); 375 throw; 376 } 377 mDigest->allocator().free(digst.Data); 378 } 379} 380 381 382// 383// SSCryptContext -- Context for Encrypt and Decrypt operations 384// 385SSCryptContext::SSCryptContext(SSCSPSession &session) 386 : SSContext(session), mKeyHandle(noKey) 387{ 388 /* nothing for now */ 389} 390 391 392SSCryptContext::~SSCryptContext() 393{ 394 /* nothing for now */ 395} 396 397void 398SSCryptContext::init(const Context &context, bool encoding) 399{ 400 ssCryptDebug("===init"); 401 SSContext::init(context, encoding); 402 403 /* reusable; reset accumulator */ 404 mNullDigest.digestInit(); 405 406 const CssmKey &keyInContext = 407 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, 408 CSSMERR_CSP_MISSING_ATTR_KEY); 409 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle(); 410} 411 412size_t 413SSCryptContext::inputSize(size_t outSize) 414{ 415 ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize); 416 return UINT_MAX; 417} 418 419size_t 420SSCryptContext::outputSize(bool final, size_t inSize) 421{ 422 ssCryptDebug("===outputSize final %d inSize=%u", final, (unsigned)inSize); 423 if(!final) { 424 /* we buffer until final; no intermediate output */ 425 return 0; 426 } 427 size_t inBufSize = mNullDigest.digestSizeInBytes(); 428 if(inSize == 0) { 429 /* This is the implied signal to go for it */ 430 clearOutBuf(); 431 if(inBufSize == 0) { 432 return 0; 433 } 434 const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inBufSize); 435 if (encoding()) { 436 clientSession().encrypt(*mContext, mKeyHandle, in, mOutBuf); 437 } 438 else { 439 clientSession().decrypt(*mContext, mKeyHandle, in, mOutBuf); 440 } 441 /* leave the accumulator as is in case of unexpected sequence */ 442 ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf.Length); 443 return mOutBuf.Length; 444 } 445 else { 446 /* out-of-band case, ask CSP via SS */ 447 uint32 outSize = clientSession().getOutputSize(*mContext, 448 mKeyHandle, 449 (uint32)(inBufSize + inSize), 450 encoding()); 451 ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize); 452 return (size_t)outSize; 453 } 454} 455 456void 457SSCryptContext::minimumProgress(size_t &in, size_t &out) 458{ 459 in = 1; 460 out = 0; 461} 462 463void 464SSCryptContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize) 465{ 466 ssCryptDebug("===update inSize=%u", (unsigned)inSize); 467 /* add incoming data to accumulator */ 468 mNullDigest.digestUpdate(inp, inSize); 469 outSize = 0; 470 clearOutBuf(); 471} 472 473void 474SSCryptContext::final(CssmData &out) 475{ 476 if(mOutBuf.Data != NULL) { 477 /* normal final case in which the actual RPC via SS was done in the 478 * previous outputSize() call. A memcpy is needed here because 479 * CSPFullPluginSession has just allocated the buf size we need. */ 480 ssCryptDebug("===final via pre-op and copy"); 481 copyOutBuf(out); 482 return; 483 } 484 485 /* when is this path taken...? */ 486 ssCryptDebug("===final via RPC"); 487 size_t inSize = mNullDigest.digestSizeInBytes(); 488 if(!inSize) return; 489 490 const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inSize); 491 IFDEBUG(size_t origOutSize = out.length()); 492 if (encoding()) { 493 clientSession().encrypt(*mContext, mKeyHandle, in, out); 494 } 495 else { 496 clientSession().decrypt(*mContext, mKeyHandle, in, out); 497 } 498 assert(out.length() <= origOutSize); 499 mNullDigest.digestInit(); 500} 501 502// Digest, using raw CSP 503SSDigestContext::SSDigestContext(SSCSPSession &session) 504 : SSContext(session), mDigest(NULL) 505{ 506 507} 508 509SSDigestContext::~SSDigestContext() 510{ 511 delete mDigest; 512} 513 514void SSDigestContext::init(const Context &context, bool encoding) 515{ 516 CSSM_ALGORITHMS alg; 517 518 SSContext::init(context, encoding); 519 alg = context.algorithm(); 520 mDigest = new CssmClient::Digest(mSession.mRawCsp, alg); 521} 522 523void SSDigestContext::update(const CssmData &data) 524{ 525 mDigest->digest(data); 526} 527 528void SSDigestContext::final(CssmData &out) 529{ 530 (*mDigest)(out); 531} 532 533size_t SSDigestContext::outputSize(bool final, size_t inSize) 534{ 535 if(!final) { 536 return 0; 537 } 538 else { 539 return (size_t)mDigest->getOutputSize((uint32)inSize); 540 } 541} 542 543// MACContext - common class for MAC generate, verify 544SSMACContext::SSMACContext(SSCSPSession &session) 545 : SSContext(session), mKeyHandle(noKey) 546{ 547 548} 549 550void SSMACContext::init(const Context &context, bool encoding) 551{ 552 SSContext::init(context, encoding); 553 554 /* reusable; reset accumulator */ 555 mNullDigest.digestInit(); 556 557 /* snag key from context */ 558 const CssmKey &keyInContext = 559 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, 560 CSSMERR_CSP_MISSING_ATTR_KEY); 561 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle(); 562} 563 564void SSMACContext::update(const CssmData &data) 565{ 566 /* add incoming data to accumulator */ 567 mNullDigest.digestUpdate(data.data(), data.length()); 568} 569 570size_t SSMACContext::outputSize(bool final, size_t inSize) 571{ 572 if(!final) { 573 ssCryptDebug("===mac outputSize !final\n"); 574 return 0; 575 } 576 if(!encoding()) { 577 ssCryptDebug("===mac outputSize final, !encoding\n"); 578 /* don't see why this is even called... */ 579 return 0; 580 } 581 if(inSize == 0) { 582 /* 583 * This is the implied signal to go for it. 584 */ 585 clearOutBuf(); 586 genMac(mOutBuf); 587 ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf.Length); 588 return (size_t)mOutBuf.Length; 589 } 590 else { 591 /* out-of-band case, ask CSP via SS */ 592 uint32 outSize = clientSession().getOutputSize(*mContext, 593 mKeyHandle, 594 (uint32)(inSize + mNullDigest.digestSizeInBytes()), 595 true); 596 ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize); 597 return (size_t)outSize; 598 } 599} 600 601/* generate */ 602 603/* first the common routine used by final() and outputSize() */ 604void SSMACContext::genMac(CssmData &mac) 605{ 606 CssmData allData(const_cast<void *>(mNullDigest.digestPtr()), 607 mNullDigest.digestSizeInBytes()); 608 clientSession().generateMac(*mContext, mKeyHandle, allData, mac); 609} 610 611void SSMACContext::final(CssmData &mac) 612{ 613 genMac(mac); 614} 615 616/* verify */ 617void SSMACContext::final(const CssmData &mac) 618{ 619 CssmData allData(const_cast<void *>(mNullDigest.digestPtr()), 620 mNullDigest.digestSizeInBytes()); 621 clientSession().verifyMac(*mContext, mKeyHandle, allData, mac); 622} 623