1/* 2 * Copyright (c) 2000-2001,2005-2008,2010-2012 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * appleCdsa.c - CDSA based implementation of sslCrypto.h interfaces. 26 */ 27 28#include "ssl.h" 29#if USE_CDSA_CRYPTO 30 31#include "appleCdsa.h" 32#include "sslCrypto.h" 33 34#include "CipherSuite.h" 35#include "sslContext.h" 36#include "sslMemory.h" 37#include "sslUtils.h" 38#include "sslDebug.h" 39#include "sslBER.h" 40#include "ModuleAttacher.h" 41 42#ifndef _SSL_KEYCHAIN_H_ 43#include "sslKeychain.h" 44#endif 45 46#include <string.h> 47#include <stdlib.h> 48#include <assert.h> 49 50#include <Security/cssm.h> 51#include <Security/cssmapple.h> 52#include <Security/Security.h> 53#include <Security/SecTrustPriv.h> 54#include <Security/SecPolicyPriv.h> 55#include <Security/SecKeyPriv.h> 56 57/* X.509 includes, from cssmapi */ 58#include <Security/x509defs.h> /* x.509 function and type defs */ 59#include <Security/oidsalg.h> 60#include <Security/oidscert.h> 61 62// MARK: - 63// MARK: Utilities 64 65/* 66 * Set up a Raw symmetric key with specified algorithm and key bits. 67 */ 68OSStatus sslSetUpSymmKey( 69 CSSM_KEY_PTR symKey, 70 CSSM_ALGORITHMS alg, 71 CSSM_KEYUSE keyUse, // CSSM_KEYUSE_ENCRYPT, etc. 72 CSSM_BOOL copyKey, // true: copy keyData false: set by reference 73 uint8 *keyData, 74 size_t keyDataLen) // in bytes 75{ 76 OSStatus serr; 77 CSSM_KEYHEADER *hdr; 78 79 memset(symKey, 0, sizeof(CSSM_KEY)); 80 if(copyKey) { 81 serr = stSetUpCssmData(&symKey->KeyData, keyDataLen); 82 if(serr) { 83 return serr; 84 } 85 memmove(symKey->KeyData.Data, keyData, keyDataLen); 86 } 87 else { 88 symKey->KeyData.Data = keyData; 89 symKey->KeyData.Length = keyDataLen; 90 } 91 92 /* set up the header */ 93 hdr = &symKey->KeyHeader; 94 hdr->BlobType = CSSM_KEYBLOB_RAW; 95 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; 96 hdr->AlgorithmId = alg; 97 hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY; 98 hdr->LogicalKeySizeInBits = keyDataLen * 8; 99 hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE; 100 hdr->KeyUsage = keyUse; 101 hdr->WrapAlgorithmId = CSSM_ALGID_NONE; 102 return errSecSuccess; 103} 104 105/* 106 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself. 107 */ 108OSStatus sslFreeKey( 109 CSSM_CSP_HANDLE cspHand, 110 CSSM_KEY_PTR *key, /* so we can null it out */ 111 #if ST_KC_KEYS_NEED_REF 112 SecKeychainRef *kcItem) 113 #else 114 void *kcItem) 115 #endif 116{ 117 assert(key != NULL); 118 119 if(*key != NULL) { 120 if(cspHand != 0) { 121 CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE); 122 } 123 stAppFree(*key, NULL); // key mallocd by CL using our callback 124 *key = NULL; 125 } 126 #if ST_KC_KEYS_NEED_REF 127 if((kcItem != NULL) && (*kcItem != NULL)) { 128 KCReleaseItem(kcItem); /* does this NULL the referent? */ 129 *kcItem = NULL; 130 } 131 #endif 132 return errSecSuccess; 133} 134 135/* 136 * Standard app-level memory functions required by CDSA. 137 */ 138void * stAppMalloc (size_t size, void *allocRef) { 139 return( malloc(size) ); 140} 141void stAppFree (void *mem_ptr, void *allocRef) { 142 free(mem_ptr); 143 return; 144} 145void * stAppRealloc (void *ptr, size_t size, void *allocRef) { 146 return( realloc( ptr, size ) ); 147} 148void * stAppCalloc (uint32_t num, size_t size, void *allocRef) { 149 return( calloc( num, size ) ); 150} 151 152/* 153 * Ensure there's a connection to ctx->cspHand. If there 154 * already is one, fine. 155 * Note that as of 12/18/00, we assume we're connected to 156 * all modules all the time (since we do an attachToAll() in 157 * SSLNewContext()). 158 */ 159OSStatus attachToCsp(SSLContext *ctx) 160{ 161 assert(ctx != NULL); 162 if(ctx->cspHand != 0) { 163 return errSecSuccess; 164 } 165 else { 166 return errSSLModuleAttach; 167 } 168} 169 170/* 171 * Connect to TP, CL; reusable. 172 */ 173OSStatus attachToCl(SSLContext *ctx) 174{ 175 assert(ctx != NULL); 176 if(ctx->clHand != 0) { 177 return errSecSuccess; 178 } 179 else { 180 return errSSLModuleAttach; 181 } 182} 183 184OSStatus attachToTp(SSLContext *ctx) 185{ 186 assert(ctx != NULL); 187 if(ctx->tpHand != 0) { 188 return errSecSuccess; 189 } 190 else { 191 return errSSLModuleAttach; 192 } 193} 194 195/* 196 * Convenience function - attach to CSP, CL, TP. Reusable. 197 */ 198OSStatus attachToAll(SSLContext *ctx) 199{ 200 CSSM_RETURN crtn; 201 202 assert(ctx != NULL); 203 crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand); 204 if(crtn) { 205 return errSSLModuleAttach; 206 } 207 else { 208 return errSecSuccess; 209 } 210} 211 212OSStatus detachFromAll(SSLContext *ctx) 213{ 214 #if 0 215 /* No more, attachments are kept on a global basis */ 216 assert(ctx != NULL); 217 if(ctx->cspHand != 0) { 218 CSSM_ModuleDetach(ctx->cspHand); 219 ctx->cspHand = 0; 220 } 221 if(ctx->tpHand != 0) { 222 CSSM_ModuleDetach(ctx->tpHand); 223 ctx->tpHand = 0; 224 } 225 if(ctx->clHand != 0) { 226 CSSM_ModuleDetach(ctx->clHand); 227 ctx->clHand = 0; 228 } 229 #endif /* 0 */ 230 return errSecSuccess; 231} 232 233/* 234 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to 235 * specified crypto context. 236 */ 237static CSSM_RETURN sslAddBlindingAttr( 238 CSSM_CC_HANDLE ccHand) 239{ 240 CSSM_CONTEXT_ATTRIBUTE newAttr; 241 CSSM_RETURN crtn; 242 243 newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; 244 newAttr.AttributeLength = sizeof(uint32_t); 245 newAttr.Attribute.Uint32 = 1; 246 crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr); 247 if(crtn) { 248 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn); 249 } 250 return crtn; 251} 252 253/* Get CSP, key in CSSM format from a SecKeyRef */ 254static OSStatus sslGetKeyParts( 255 SecKeyRef keyRef, 256 const CSSM_KEY **cssmKey, 257 CSSM_CSP_HANDLE *cspHand) 258{ 259 OSStatus ortn = SecKeyGetCSSMKey(keyRef, cssmKey); 260 if(ortn) { 261 sslErrorLog("sslGetKeyParts: SecKeyGetCSSMKey err %d\n", 262 (int)ortn); 263 return ortn; 264 } 265 ortn = SecKeyGetCSPHandle(keyRef, cspHand); 266 if(ortn) { 267 sslErrorLog("sslGetKeyParts: SecKeyGetCSPHandle err %d\n", 268 (int)ortn); 269 } 270 return ortn; 271} 272 273/* Return the first certificate reference from the supplied array 274 * whose data matches the given certificate, or NULL if none match. 275 */ 276 static SecCertificateRef sslGetMatchingCertInArray( 277 SecCertificateRef certRef, 278 CFArrayRef certArray) 279{ 280 CSSM_DATA certData; 281 OSStatus ortn; 282 int idx, count; 283 284 if(certRef == NULL || certArray == NULL) { 285 return NULL; 286 } 287 ortn = SecCertificateGetData(certRef, &certData); 288 if(!ortn) { 289 count = CFArrayGetCount(certArray); 290 for(idx=0; idx<count; idx++) { 291 CSSM_DATA aData = { 0, NULL }; 292 SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(certArray, idx); 293 ortn = SecCertificateGetData(aCert, &aData); 294 if (!ortn && aData.Length == certData.Length && 295 !memcmp(aData.Data, certData.Data, certData.Length)) { 296 return aCert; 297 } 298 } 299 } 300 return NULL; 301} 302 303// MARK: - 304// MARK: CSSM_DATA routines 305 306CSSM_DATA_PTR stMallocCssmData( 307 size_t size) 308{ 309 CSSM_DATA_PTR rtn = (CSSM_DATA_PTR)stAppMalloc(sizeof(CSSM_DATA), NULL); 310 311 if(rtn == NULL) { 312 return NULL; 313 } 314 rtn->Length = size; 315 if(size == 0) { 316 rtn->Data = NULL; 317 } 318 else { 319 rtn->Data = (uint8 *)stAppMalloc(size, NULL); 320 } 321 return rtn; 322} 323 324void stFreeCssmData( 325 CSSM_DATA_PTR data, 326 CSSM_BOOL freeStruct) 327{ 328 if(data == NULL) { 329 return; 330 } 331 if(data->Data != NULL) { 332 stAppFree(data->Data, NULL); 333 data->Data = NULL; 334 } 335 data->Length = 0; 336 if(freeStruct) { 337 stAppFree(data, NULL); 338 } 339} 340 341/* 342 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data. 343 * Malloc the Data ptr if necessary. 344 */ 345OSStatus stSetUpCssmData( 346 CSSM_DATA_PTR data, 347 size_t length) 348{ 349 assert(data != NULL); 350 if(data->Length == 0) { 351 data->Data = (uint8 *)stAppMalloc(length, NULL); 352 if(data->Data == NULL) { 353 return errSecAllocate; 354 } 355 } 356 else if(data->Length < length) { 357 sslErrorLog("stSetUpCssmData: length too small\n"); 358 return errSecAllocate; 359 } 360 data->Length = length; 361 return errSecSuccess; 362} 363 364/* All signature ops are "raw", with digest step done by us */ 365static OSStatus sslKeyToSigAlg( 366 const CSSM_KEY *cssmKey, 367 CSSM_ALGORITHMS *sigAlg) /* RETURNED */ 368 369{ 370 OSStatus ortn = errSecSuccess; 371 switch(cssmKey->KeyHeader.AlgorithmId) { 372 case CSSM_ALGID_RSA: 373 *sigAlg = CSSM_ALGID_RSA; 374 break; 375 case CSSM_ALGID_DSA: 376 *sigAlg = CSSM_ALGID_DSA; 377 break; 378 case CSSM_ALGID_ECDSA: 379 *sigAlg = CSSM_ALGID_ECDSA; 380 break; 381 default: 382 ortn = errSSLBadConfiguration; 383 break; 384 } 385 return ortn; 386} 387 388// MARK: - 389// MARK: Public CSP Functions 390 391/* 392 * Raw RSA/DSA sign/verify. 393 */ 394OSStatus sslRawSign( 395 SSLContext *ctx, 396 SecKeyRef privKeyRef, 397 const UInt8 *plainText, 398 size_t plainTextLen, 399 UInt8 *sig, // mallocd by caller; RETURNED 400 size_t sigLen, // available 401 size_t *actualBytes) // RETURNED 402{ 403 CSSM_CC_HANDLE sigHand = 0; 404 CSSM_RETURN crtn; 405 OSStatus serr; 406 CSSM_DATA sigData; 407 CSSM_DATA ptextData; 408 CSSM_CSP_HANDLE cspHand; 409 const CSSM_KEY *privKey; 410 const CSSM_ACCESS_CREDENTIALS *creds; 411 412 assert(ctx != NULL); 413 if((privKeyRef == NULL) || 414 (plainText == NULL) || 415 (sig == NULL) || 416 (actualBytes == NULL)) { 417 sslErrorLog("sslRsaRawSign: bad arguments\n"); 418 return errSSLInternal; 419 } 420 *actualBytes = 0; 421 422 /* Get CSP, signing key in CSSM format */ 423 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand); 424 if(serr) { 425 return serr; 426 } 427 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY); 428 429 CSSM_ALGORITHMS sigAlg; 430 serr = sslKeyToSigAlg(privKey, &sigAlg); 431 if(serr) { 432 return serr; 433 } 434 435 /* 436 * Get default creds 437 * FIXME: per 3420180, this needs to allow app-specified creds via 438 * an new API 439 */ 440 serr = SecKeyGetCredentials(privKeyRef, 441 CSSM_ACL_AUTHORIZATION_SIGN, 442 kSecCredentialTypeDefault, 443 &creds); 444 if(serr) { 445 sslErrorLog("sslRawSign: SecKeyGetCredentials err %lu\n", (unsigned long)serr); 446 return serr; 447 } 448 449 crtn = CSSM_CSP_CreateSignatureContext(cspHand, 450 sigAlg, 451 creds, 452 privKey, 453 &sigHand); 454 if(crtn) { 455 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn); 456 return errSSLCrypto; 457 } 458 459 if((ctx->rsaBlindingEnable) && 460 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) { 461 /* 462 * Turn on RSA blinding to defeat timing attacks 463 */ 464 crtn = sslAddBlindingAttr(sigHand); 465 if(crtn) { 466 return crtn; 467 } 468 } 469 470 ptextData.Data = (uint8 *)plainText; 471 ptextData.Length = plainTextLen; 472 473 /* caller better get this right, or the SignData will fail */ 474 sigData.Data = sig; 475 sigData.Length = sigLen; 476 477 crtn = CSSM_SignData(sigHand, 478 &ptextData, 479 1, 480 CSSM_ALGID_NONE, // digestAlg for raw sign 481 &sigData); 482 if(crtn) { 483 stPrintCdsaError("CSSM_SignData", crtn); 484 serr = errSSLCrypto; 485 } 486 else { 487 *actualBytes = sigData.Length; 488 serr = errSecSuccess; 489 } 490 if(sigHand != 0) { 491 CSSM_DeleteContext(sigHand); 492 } 493 return serr; 494} 495 496OSStatus sslRawVerify( 497 SSLContext *ctx, 498 const SSLPubKey *sslPubKey, 499 const UInt8 *plainText, 500 size_t plainTextLen, 501 const UInt8 *sig, 502 size_t sigLen) 503{ 504 CSSM_CC_HANDLE sigHand = 0; 505 CSSM_RETURN crtn; 506 OSStatus serr; 507 CSSM_DATA sigData; 508 CSSM_DATA ptextData; 509 const CSSM_KEY *pubKey; 510 CSSM_CSP_HANDLE cspHand; 511 512 assert(ctx != NULL); 513 if((sslPubKey == NULL) || 514 (sslPubKey->key == NULL) || 515 (sslPubKey->csp == 0) || 516 (plainText == NULL) || 517 (sig == NULL)) { 518 sslErrorLog("sslRawVerify: bad arguments\n"); 519 return errSSLInternal; 520 } 521 522 pubKey = &sslPubKey->key; 523 cspHand = sslPubKey->csp; 524 525 CSSM_ALGORITHMS sigAlg; 526 serr = sslKeyToSigAlg(pubKey, &sigAlg); 527 if(serr) { 528 return serr; 529 } 530 crtn = CSSM_CSP_CreateSignatureContext(cspHand, 531 sigAlg, 532 NULL, // passPhrase 533 pubKey, 534 &sigHand); 535 if(sigHand == 0) { 536 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn); 537 return errSSLCrypto; 538 } 539 540 ptextData.Data = (uint8 *)plainText; 541 ptextData.Length = plainTextLen; 542 sigData.Data = (uint8 *)sig; 543 sigData.Length = sigLen; 544 545 crtn = CSSM_VerifyData(sigHand, 546 &ptextData, 547 1, 548 CSSM_ALGID_NONE, // digestAlg 549 &sigData); 550 if(crtn) { 551 stPrintCdsaError("CSSM_VerifyData", crtn); 552 serr = errSSLCrypto; 553 } 554 else { 555 serr = errSecSuccess; 556 } 557 if(sigHand != 0) { 558 CSSM_DeleteContext(sigHand); 559 } 560 return serr; 561} 562 563/* 564 * Encrypt/Decrypt 565 */ 566OSStatus sslRsaEncrypt( 567 SSLContext *ctx, 568 const CSSM_KEY *pubKey, 569 CSSM_CSP_HANDLE cspHand, 570 CSSM_PADDING padding, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2 571 const UInt8 *plainText, 572 size_t plainTextLen, 573 UInt8 *cipherText, // mallocd by caller; RETURNED 574 size_t cipherTextLen, // available 575 size_t *actualBytes) // RETURNED 576{ 577 CSSM_DATA ctextData = {0, NULL}; 578 CSSM_DATA ptextData; 579 CSSM_DATA remData = {0, NULL}; 580 CSSM_CC_HANDLE cryptHand = 0; 581 OSStatus serr = errSSLInternal; 582 CSSM_RETURN crtn; 583 size_t bytesMoved = 0; 584 CSSM_ACCESS_CREDENTIALS creds; 585 586 assert(ctx != NULL); 587 assert(actualBytes != NULL); 588 *actualBytes = 0; 589 590 if((pubKey == NULL) || (cspHand == 0)) { 591 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n"); 592 return errSSLInternal; 593 } 594 assert(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY); 595 596 #if RSA_PUB_KEY_USAGE_HACK 597 ((CSSM_KEY_PTR)pubKey)->KeyHeader.KeyUsage |= CSSM_KEYUSE_ENCRYPT; 598 #endif 599 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 600 601 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, 602 CSSM_ALGID_RSA, 603 &creds, 604 pubKey, 605 padding, 606 &cryptHand); 607 if(crtn) { 608 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn); 609 return errSSLCrypto; 610 } 611 ptextData.Data = (uint8 *)plainText; 612 ptextData.Length = plainTextLen; 613 614 /* 615 * Have CSP malloc ciphertext 616 */ 617 crtn = CSSM_EncryptData(cryptHand, 618 &ptextData, 619 1, 620 &ctextData, 621 1, 622 &bytesMoved, 623 &remData); 624 if(crtn == CSSM_OK) { 625 /* 626 * ciphertext in both ctextData and remData; ensure it'll fit 627 * in caller's buf & copy 628 */ 629 if(bytesMoved > cipherTextLen) { 630 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %lu bytesMoved %lu\n", 631 cipherTextLen, bytesMoved); 632 serr = errSSLCrypto; 633 } 634 else { 635 size_t toMoveCtext; 636 size_t toMoveRem; 637 638 *actualBytes = bytesMoved; 639 /* 640 * Snag valid data from ctextData - its length or bytesMoved, 641 * whichever is less 642 */ 643 if(ctextData.Length > bytesMoved) { 644 /* everything's in ctext */ 645 toMoveCtext = bytesMoved; 646 toMoveRem = 0; 647 } 648 else { 649 /* must be some in remData too */ 650 toMoveCtext = ctextData.Length; 651 toMoveRem = bytesMoved - toMoveCtext; // remainder 652 } 653 if(toMoveCtext) { 654 memmove(cipherText, ctextData.Data, toMoveCtext); 655 } 656 if(toMoveRem) { 657 memmove(cipherText + toMoveCtext, remData.Data, 658 toMoveRem); 659 } 660 serr = errSecSuccess; 661 } 662 } 663 else { 664 stPrintCdsaError("CSSM_EncryptData", crtn); 665 serr = errSSLCrypto; 666 } 667 if(cryptHand != 0) { 668 CSSM_DeleteContext(cryptHand); 669 } 670 671 /* free data mallocd by CSP */ 672 stFreeCssmData(&ctextData, CSSM_FALSE); 673 stFreeCssmData(&remData, CSSM_FALSE); 674 return serr; 675} 676 677OSStatus sslRsaDecrypt( 678 SSLContext *ctx, 679 SecKeyRef privKeyRef, 680 CSSM_PADDING padding, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2 681 const UInt8 *cipherText, 682 size_t cipherTextLen, 683 UInt8 *plainText, // mallocd by caller; RETURNED 684 size_t plainTextLen, // available 685 size_t *actualBytes) // RETURNED 686{ 687 CSSM_DATA ptextData = {0, NULL}; 688 CSSM_DATA ctextData; 689 CSSM_DATA remData = {0, NULL}; 690 CSSM_CC_HANDLE cryptHand = 0; 691 OSStatus serr = errSSLInternal; 692 CSSM_RETURN crtn; 693 size_t bytesMoved = 0; 694 CSSM_CSP_HANDLE cspHand; 695 const CSSM_KEY *privKey; 696 const CSSM_ACCESS_CREDENTIALS *creds; 697 698 assert(ctx != NULL); 699 assert(actualBytes != NULL); 700 *actualBytes = 0; 701 702 if(privKeyRef == NULL) { 703 sslErrorLog("sslRsaDecrypt: bad privKey\n"); 704 return errSSLInternal; 705 } 706 707 /* Get CSP, signing key in CSSM format */ 708 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand); 709 if(serr) { 710 return serr; 711 } 712 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY); 713 714 /* 715 * Get default creds 716 * FIXME: per 3420180, this needs to allow app-specified creds via 717 * an new API 718 */ 719 serr = SecKeyGetCredentials(privKeyRef, 720 CSSM_ACL_AUTHORIZATION_DECRYPT, 721 kSecCredentialTypeDefault, 722 &creds); 723 if(serr) { 724 sslErrorLog("sslRsaDecrypt: SecKeyGetCredentials err %lu\n", (unsigned long)serr); 725 return serr; 726 } 727 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, 728 CSSM_ALGID_RSA, 729 creds, 730 privKey, 731 padding, 732 &cryptHand); 733 if(crtn) { 734 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn); 735 return errSSLCrypto; 736 } 737 ctextData.Data = (uint8 *)cipherText; 738 ctextData.Length = cipherTextLen; 739 740 if((ctx->rsaBlindingEnable) && 741 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) { 742 /* 743 * Turn on RSA blinding to defeat timing attacks 744 */ 745 crtn = sslAddBlindingAttr(cryptHand); 746 if(crtn) { 747 return crtn; 748 } 749 } 750 751 /* 752 * Have CSP malloc plaintext 753 */ 754 crtn = CSSM_DecryptData(cryptHand, 755 &ctextData, 756 1, 757 &ptextData, 758 1, 759 &bytesMoved, 760 &remData); 761 if(crtn == CSSM_OK) { 762 /* 763 * plaintext in both ptextData and remData; ensure it'll fit 764 * in caller's buf & copy 765 */ 766 if(bytesMoved > plainTextLen) { 767 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %lu bytesMoved %lu\n", 768 plainTextLen, bytesMoved); 769 serr = errSSLCrypto; 770 } 771 else { 772 size_t toMovePtext; 773 size_t toMoveRem; 774 775 *actualBytes = bytesMoved; 776 /* 777 * Snag valid data from ptextData - its length or bytesMoved, 778 * whichever is less 779 */ 780 if(ptextData.Length > bytesMoved) { 781 /* everything's in ptext */ 782 toMovePtext = bytesMoved; 783 toMoveRem = 0; 784 } 785 else { 786 /* must be some in remData too */ 787 toMovePtext = ptextData.Length; 788 toMoveRem = bytesMoved - toMovePtext; // remainder 789 } 790 if(toMovePtext) { 791 memmove(plainText, ptextData.Data, toMovePtext); 792 } 793 if(toMoveRem) { 794 memmove(plainText + toMovePtext, remData.Data, 795 toMoveRem); 796 } 797 serr = errSecSuccess; 798 } 799 } 800 else { 801 stPrintCdsaError("CSSM_DecryptData", crtn); 802 serr = errSSLCrypto; 803 } 804 if(cryptHand != 0) { 805 CSSM_DeleteContext(cryptHand); 806 } 807 808 /* free data mallocd by CSP */ 809 stFreeCssmData(&ptextData, CSSM_FALSE); 810 stFreeCssmData(&remData, CSSM_FALSE); 811 return serr; 812} 813 814/* 815 * Obtain size of key in bytes. 816 */ 817uint32_t sslPrivKeyLengthInBytes(const SSLPrivKey *sslKey) 818{ 819 const CSSM_KEY *cssmKey; 820 821 assert(sslKey != NULL); 822 assert(sslKey->key != NULL); 823 err = SecKeyGetCSSMKey(sslKey->key, &cssmKey); 824 if(err) { 825 sslErrorLog("sslKeyLengthInBytes: SecKeyGetCSSMKey err %d\n", (int)err); 826 return 0; 827 } 828 829 return (((cssmKey->KeyHeader.LogicalKeySizeInBits) + 7) / 8); 830} 831 832/* 833 * Obtain size of key in bytes. 834 */ 835uint32_t sslPubKeyLengthInBytes(const SSLPubKey *sslKey) 836{ 837 const CSSM_KEY *cssmKey; 838 839 assert(sslKey != NULL); 840 assert(sslKey->key != NULL); 841 842 return (((sslKey->key.KeyHeader.LogicalKeySizeInBits) + 7) / 8); 843} 844 845 846/* 847 * Obtain maximum size of signature in bytes. A bit of a kludge; we could 848 * ask the CSP to do this but that would be kind of expensive. 849 */ 850OSStatus sslGetMaxSigSize( 851 const CSSM_KEY *privKey, 852 uint32_t *maxSigSize) 853{ 854 OSStatus ortn = errSecSuccess; 855 assert(privKey != NULL); 856 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY); 857 switch(privKey->KeyHeader.AlgorithmId) { 858 case CSSM_ALGID_RSA: 859 *maxSigSize = sslPrivKeyLengthInBytes(privKey); 860 break; 861 case CSSM_ALGID_DSA: 862 { 863 /* DSA sig is DER sequence of two 160-bit integers */ 864 uint32_t sizeOfOneInt; 865 sizeOfOneInt = (160 / 8) + // the raw contents 866 1 + // possible leading zero 867 2; // tag + length (assume DER, not BER) 868 *maxSigSize = (2 * sizeOfOneInt) + 5; 869 break; 870 } 871 default: 872 ortn = errSSLBadConfiguration; 873 break; 874 } 875 return ortn; 876} 877/* 878 * Get raw key bits from an RSA public key. 879 */ 880OSStatus sslGetPubKeyBits( 881 SSLContext *ctx, 882 const CSSM_KEY *pubKey, 883 CSSM_CSP_HANDLE cspHand, 884 SSLBuffer *modulus, // data mallocd and RETURNED 885 SSLBuffer *exponent) // data mallocd and RETURNED 886{ 887 CSSM_KEY wrappedKey; 888 CSSM_BOOL didWrap = CSSM_FALSE; 889 const CSSM_KEYHEADER *hdr; 890 SSLBuffer pubKeyBlob; 891 OSStatus srtn; 892 893 assert(ctx != NULL); 894 assert(modulus != NULL); 895 assert(exponent != NULL); 896 assert(pubKey != NULL); 897 898 hdr = &pubKey->KeyHeader; 899 if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) { 900 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", (long)hdr->KeyClass); 901 return errSSLInternal; 902 } 903 if(hdr->AlgorithmId != CSSM_ALGID_RSA) { 904 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", (long)hdr->AlgorithmId); 905 return errSSLInternal; 906 } 907 908 /* Note currently ALL public keys are raw, obtained from the CL... */ 909 assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 910 911 /* 912 * Handle possible reference format - I think it should be in 913 * blob form since it came from the DL, but conversion is 914 * simple. 915 */ 916 switch(hdr->BlobType) { 917 case CSSM_KEYBLOB_RAW: 918 /* easy case */ 919 CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob); 920 break; 921 922 case CSSM_KEYBLOB_REFERENCE: 923 924 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n", 925 (long)hdr->BlobType); 926 return errSSLInternal; 927 928 #if 0 929 /* 930 * Convert to a blob via "NULL wrap"; no wrapping key, 931 * ALGID_NONE 932 */ 933 srtn = attachToCsp(ctx); 934 if(srtn) { 935 return srtn; 936 } 937 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 938 crtn = CSSM_CSP_CreateSymmetricContext(ctx->cspHand, 939 CSSM_ALGID_NONE, 940 CSSM_ALGMODE_NONE, 941 &creds, // creds 942 pubKey, 943 NULL, // InitVector 944 CSSM_PADDING_NONE, 945 0, // reserved 946 &ccHand); 947 if(crtn) { 948 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn); 949 return errSSLCrypto; 950 } 951 memset(&wrappedKey, 0, sizeof(CSSM_KEY)); 952 crtn = CSSM_WrapKey(ccHand, 953 &creds, 954 pubKey, 955 NULL, // descriptiveData 956 &wrappedKey); 957 CSSM_DeleteContext(ccHand); 958 if(crtn) { 959 stPrintCdsaError("CSSM_WrapKey", crtn); 960 return errSSLCrypto; 961 } 962 hdr = &wrappedKey.KeyHeader; 963 if(hdr->BlobType != CSSM_KEYBLOB_RAW) { 964 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n", 965 hdr->BlobType); 966 return errSSLCrypto; 967 } 968 didWrap = CSSM_TRUE; 969 CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob); 970 break; 971 #endif /* 0 */ 972 973 default: 974 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n", 975 (long)hdr->BlobType); 976 return errSSLInternal; 977 978 } /* switch BlobType */ 979 980 assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 981 srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent); 982 if(didWrap) { 983 CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE); 984 } 985 return srtn; 986} 987 988/* 989 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in 990 * Server-initiated key exchange. 991 */ 992OSStatus sslGetPubKeyFromBits( 993 SSLContext *ctx, 994 const SSLBuffer *modulus, 995 const SSLBuffer *exponent, 996 CSSM_KEY_PTR *pubKey, // mallocd and RETURNED 997 CSSM_CSP_HANDLE *cspHand) // RETURNED 998{ 999 CSSM_KEY_PTR key = NULL; 1000 OSStatus serr; 1001 SSLBuffer blob; 1002 CSSM_KEYHEADER_PTR hdr; 1003 CSSM_KEY_SIZE keySize; 1004 CSSM_RETURN crtn; 1005 1006 assert((ctx != NULL) && (modulus != NULL) && (exponent != NULL)); 1007 assert((pubKey != NULL) && (cspHand != NULL)); 1008 1009 *pubKey = NULL; 1010 *cspHand = 0; 1011 1012 serr = attachToCsp(ctx); 1013 if(serr) { 1014 return serr; 1015 } 1016 serr = sslEncodeRsaBlob(modulus, exponent, &blob); 1017 if(serr) { 1018 return serr; 1019 } 1020 1021 /* the rest is boilerplate, cook up a good-looking public key */ 1022 key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY)); 1023 if(key == NULL) { 1024 return errSecAllocate; 1025 } 1026 memset(key, 0, sizeof(CSSM_KEY)); 1027 hdr = &key->KeyHeader; 1028 1029 hdr->HeaderVersion = CSSM_KEYHEADER_VERSION; 1030 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */ 1031 hdr->BlobType = CSSM_KEYBLOB_RAW; 1032 hdr->AlgorithmId = CSSM_ALGID_RSA; 1033 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; 1034 hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; 1035 /* comply with ASA requirements */ 1036 hdr->KeyUsage = CSSM_KEYUSE_VERIFY; 1037 hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE; 1038 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */ 1039 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */ 1040 hdr->WrapAlgorithmId = CSSM_ALGID_NONE; 1041 hdr->WrapMode = CSSM_ALGMODE_NONE; 1042 1043 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to 1044 * actual key */ 1045 SSLBUF_TO_CSSM(&blob, &key->KeyData); 1046 1047 /* 1048 * Get keySizeInBits. This also serves to validate the key blob 1049 * we just cooked up. 1050 */ 1051 crtn = CSSM_QueryKeySizeInBits(ctx->cspHand, CSSM_INVALID_HANDLE, key, &keySize); 1052 if(crtn) { 1053 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn); 1054 serr = errSSLCrypto; 1055 goto abort; 1056 } 1057 1058 /* success */ 1059 hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits; 1060 *pubKey = key; 1061 *cspHand = ctx->cspHand; 1062 return errSecSuccess; 1063 1064abort: 1065 /* note this frees the blob */ 1066 sslFreeKey(ctx->cspHand, &key, NULL); 1067 return serr; 1068} 1069 1070#ifdef UNUSED_FUNCTIONS 1071/* 1072 * NULL-unwrap a raw key to a ref key. Caller must free the returned key. 1073 */ 1074static OSStatus sslNullUnwrapKey( 1075 CSSM_CSP_HANDLE cspHand, 1076 CSSM_KEY_PTR rawKey, 1077 CSSM_KEY_PTR refKey) 1078{ 1079 CSSM_DATA descData = {0, 0}; 1080 CSSM_RETURN crtn; 1081 CSSM_CC_HANDLE ccHand; 1082 CSSM_ACCESS_CREDENTIALS creds; 1083 CSSM_DATA labelData = {4, (uint8 *)"none"}; 1084 uint32 keyAttr; 1085 OSStatus ortn = errSecSuccess; 1086 1087 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 1088 memset(refKey, 0, sizeof(CSSM_KEY)); 1089 1090 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 1091 CSSM_ALGID_NONE, 1092 CSSM_ALGMODE_NONE, 1093 &creds, 1094 NULL, // unwrappingKey 1095 NULL, // initVector 1096 CSSM_PADDING_NONE, 1097 0, // Params 1098 &ccHand); 1099 if(crtn) { 1100 stPrintCdsaError("sslNullUnwrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn); 1101 return errSSLCrypto; 1102 } 1103 1104 keyAttr = rawKey->KeyHeader.KeyAttr; 1105 keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE | 1106 CSSM_KEYATTR_MODIFIABLE); 1107 keyAttr |= CSSM_KEYATTR_RETURN_REF; 1108 if(rawKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) { 1109 /* CSP policy */ 1110 keyAttr |= CSSM_KEYATTR_EXTRACTABLE; 1111 } 1112 crtn = CSSM_UnwrapKey(ccHand, 1113 NULL, // PublicKey 1114 rawKey, 1115 rawKey->KeyHeader.KeyUsage, 1116 keyAttr, 1117 &labelData, 1118 NULL, // CredAndAclEntry 1119 refKey, 1120 &descData); // required 1121 if(crtn != CSSM_OK) { 1122 stPrintCdsaError("sslNullUnwrapKey: CSSM_UnwrapKey\n", crtn); 1123 ortn = errSSLCrypto; 1124 } 1125 if(CSSM_DeleteContext(ccHand)) { 1126 printf("CSSM_DeleteContext failure\n"); 1127 } 1128 return crtn; 1129} 1130#endif 1131 1132/* 1133 * NULL-wrap a ref key to a raw key. Caller must free the returned key. 1134 */ 1135static OSStatus sslNullWrapKey( 1136 CSSM_CSP_HANDLE cspHand, 1137 CSSM_KEY_PTR refKey, 1138 CSSM_KEY_PTR rawKey) 1139{ 1140 CSSM_DATA descData = {0, 0}; 1141 CSSM_RETURN crtn; 1142 CSSM_CC_HANDLE ccHand; 1143 CSSM_ACCESS_CREDENTIALS creds; 1144 uint32 keyAttr; 1145 OSStatus ortn = errSecSuccess; 1146 1147 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 1148 memset(rawKey, 0, sizeof(CSSM_KEY)); 1149 1150 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 1151 CSSM_ALGID_NONE, 1152 CSSM_ALGMODE_NONE, 1153 &creds, 1154 NULL, // unwrappingKey 1155 NULL, // initVector 1156 CSSM_PADDING_NONE, 1157 0, // Params 1158 &ccHand); 1159 if(crtn) { 1160 stPrintCdsaError("sslNullWrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn); 1161 return errSSLCrypto; 1162 } 1163 1164 keyAttr = rawKey->KeyHeader.KeyAttr; 1165 keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE | 1166 CSSM_KEYATTR_MODIFIABLE); 1167 keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE; 1168 crtn = CSSM_WrapKey(ccHand, 1169 &creds, 1170 refKey, 1171 &descData, 1172 rawKey); 1173 if(crtn != CSSM_OK) { 1174 stPrintCdsaError("sslNullWrapKey: CSSM_WrapKey\n", crtn); 1175 ortn = errSSLCrypto; 1176 } 1177 if(CSSM_DeleteContext(ccHand)) { 1178 printf("CSSM_DeleteContext failure\n"); 1179 } 1180 return crtn; 1181} 1182 1183// MARK: - 1184// MARK: Public Certificate Functions 1185 1186/* 1187 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR. 1188 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself. 1189 * 1190 * For now, the returned cspHand is a copy of ctx->cspHand, so it 1191 * doesn't have to be detached later - this may change. 1192 * 1193 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for 1194 * us to tell the CL what CSP to use, we really have no way of knowing 1195 * what is going on here...we return the process-wide (bare) cspHand, 1196 * which is currently always able to deal with this raw public key. 1197 */ 1198OSStatus sslPubKeyFromCert( 1199 SSLContext *ctx, 1200 const SSLBuffer *derCert, 1201 SSLPubKey *pubKey) // RETURNED 1202{ 1203 OSStatus serr; 1204 CSSM_DATA certData; 1205 CSSM_RETURN crtn; 1206 1207 assert(ctx != NULL); 1208 assert(pubKey != NULL); 1209 1210 pubKey->key = NULL; 1211 pubKey->cspHand = 0; 1212 1213 serr = attachToCl(ctx); 1214 if(serr) { 1215 return serr; 1216 } 1217 serr = attachToCsp(ctx); 1218 if(serr) { 1219 return serr; 1220 } 1221 SSLBUF_TO_CSSM(derCert, &certData); 1222 crtn = CSSM_CL_CertGetKeyInfo(ctx->clHand, &certData, &pubKey->key); 1223 if(crtn) { 1224 return errSSLBadCert; 1225 } 1226 else { 1227 pubKey->cspHand = ctx->cspHand; 1228 return errSecSuccess; 1229 } 1230} 1231 1232/* 1233 * Release each element in a CFArray. 1234 */ 1235static void sslReleaseArray( 1236 CFArrayRef a) 1237{ 1238 CFIndex num = CFArrayGetCount(a); 1239 CFIndex dex; 1240 for(dex=0; dex<num; dex++) { 1241 CFTypeRef elmt = (CFTypeRef)CFArrayGetValueAtIndex(a, dex); 1242 secdebug("sslcert", "Freeing cert %p", elmt); 1243 CFRelease(elmt); 1244 } 1245} 1246 1247/* 1248 * Verify a chain of DER-encoded certs. 1249 * Last cert in the chain is leaf. 1250 * 1251 * If arePeerCerts is true, host name verification is enabled and we 1252 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise 1253 * we're just validating our own certs; no host name checking and 1254 * peerSecTrust is transient. 1255 */ 1256 OSStatus sslVerifyCertChain( 1257 SSLContext *ctx, 1258 const SSLCertificate *certChain, 1259 bool arePeerCerts) 1260{ 1261 uint32_t numCerts; 1262 int i; 1263 OSStatus serr; 1264 SSLCertificate *c = (SSLCertificate *)certChain; 1265 CSSM_RETURN crtn; 1266 CSSM_APPLE_TP_SSL_OPTIONS sslOpts; 1267 CSSM_APPLE_TP_ACTION_DATA tpActionData; 1268 SecPolicyRef policy = NULL; 1269 SecPolicySearchRef policySearch = NULL; 1270 CFDataRef actionData = NULL; 1271 CSSM_DATA sslOptsData; 1272 CFMutableArrayRef anchors = NULL; 1273 SecCertificateRef cert; // only lives in CFArrayRefs 1274 SecTrustResultType secTrustResult; 1275 CFMutableArrayRef kcList = NULL; 1276 SecTrustRef theTrust = NULL; 1277 1278 if(ctx->peerSecTrust && arePeerCerts) { 1279 /* renegotiate - start with a new SecTrustRef */ 1280 CFRelease(ctx->peerSecTrust); 1281 ctx->peerSecTrust = NULL; 1282 } 1283 1284 numCerts = SSLGetCertificateChainLength(certChain); 1285 if(numCerts == 0) { 1286 /* nope */ 1287 return errSSLBadCert; 1288 } 1289 1290 /* 1291 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs. 1292 * TP Cert group has root at the end, opposite of 1293 * SSLCertificate chain. 1294 */ 1295 CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts, 1296 &kCFTypeArrayCallBacks); 1297 if(certGroup == NULL) { 1298 return errSecAllocate; 1299 } 1300 /* subsequent errors to errOut: */ 1301 1302 for(i=numCerts-1; i>=0; i--) { 1303 CSSM_DATA cdata; 1304 SSLBUF_TO_CSSM(&c->derCert, &cdata); 1305 serr = SecCertificateCreateFromData(&cdata, CSSM_CERT_X_509v3, 1306 CSSM_CERT_ENCODING_DER, &cert); 1307 if(serr) { 1308 goto errOut; 1309 } 1310 /* 1311 * Can't set a value at index i when there is an empty element 1312 * at i=1! 1313 */ 1314 secdebug("sslcert", "Adding cert %p", cert); 1315 CFArrayInsertValueAtIndex(certGroup, 0, cert); 1316 c = c->next; 1317 } 1318 1319 /* 1320 * Cook up an SSL-specific SecPolicyRef. This will persists as part 1321 * of the SecTrustRef object we'll be creating. 1322 */ 1323 serr = SecPolicySearchCreate(CSSM_CERT_X_509v3, 1324 &CSSMOID_APPLE_TP_SSL, 1325 NULL, 1326 &policySearch); 1327 if(serr) { 1328 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n", 1329 (int)serr); 1330 goto errOut; 1331 } 1332 serr = SecPolicySearchCopyNext(policySearch, &policy); 1333 if(serr) { 1334 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n", 1335 (int)serr); 1336 goto errOut; 1337 } 1338 sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; 1339 if(arePeerCerts) { 1340 sslOpts.ServerNameLen = ctx->peerDomainNameLen; 1341 sslOpts.ServerName = ctx->peerDomainName; 1342 } 1343 else { 1344 sslOpts.ServerNameLen = 0; 1345 sslOpts.ServerName = NULL; 1346 } 1347 sslOpts.Flags = 0; 1348 if(ctx->protocolSide == kSSLServerSide) { 1349 /* we're evaluating a client cert */ 1350 sslOpts.Flags |= CSSM_APPLE_TP_SSL_CLIENT; 1351 } 1352 sslOptsData.Data = (uint8 *)&sslOpts; 1353 sslOptsData.Length = sizeof(sslOpts); 1354 serr = SecPolicySetValue(policy, &sslOptsData); 1355 if(serr) { 1356 sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n", 1357 (int)serr); 1358 goto errOut; 1359 } 1360 1361 /* now a SecTrustRef */ 1362 serr = SecTrustCreateWithCertificates(certGroup, policy, &theTrust); 1363 if(serr) { 1364 sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates " 1365 "rtn %d\n", (int)serr); 1366 goto errOut; 1367 } 1368 1369 /* anchors - default, or ours? */ 1370 if(ctx->trustedCerts != NULL) { 1371 serr = SecTrustSetAnchorCertificates(theTrust, ctx->trustedCerts); 1372 if(serr) { 1373 sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates " 1374 "rtn %d\n", (int)serr); 1375 goto errOut; 1376 } 1377 } 1378 tpActionData.Version = CSSM_APPLE_TP_ACTION_VERSION; 1379 tpActionData.ActionFlags = 0; 1380 if(ctx->allowExpiredCerts) { 1381 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; 1382 } 1383 if(ctx->allowExpiredRoots) { 1384 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT; 1385 } 1386 actionData = CFDataCreate(NULL, (UInt8 *)&tpActionData, sizeof(tpActionData)); 1387 1388 serr = SecTrustSetParameters(theTrust, CSSM_TP_ACTION_DEFAULT, 1389 actionData); 1390 if(serr) { 1391 sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n", 1392 (int)serr); 1393 goto errOut; 1394 } 1395 1396 #if 0 1397 /* Disabled for Radar 3421314 */ 1398 /* 1399 * Avoid searching user keychains for intermediate certs by specifying 1400 * an empty array of keychains 1401 */ 1402 kcList = CFArrayCreateMutable(NULL, 0, NULL); 1403 if(kcList == NULL) { 1404 sslErrorLog("***sslVerifyCertChain: error creating null kcList\n"); 1405 serr = errSecAllocate; 1406 goto errOut; 1407 } 1408 serr = SecTrustSetKeychains(theTrust, kcList); 1409 if(serr) { 1410 sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n", 1411 (int)serr); 1412 goto errOut; 1413 } 1414 #endif 1415 1416 /* 1417 * Save this no matter what if we're evaluating peer certs. 1418 * We do a retain here so we can unconditionally release theTrust 1419 * at the end of this routine in case of previous error or 1420 * !arePeerCerts. 1421 */ 1422 if(arePeerCerts) { 1423 ctx->peerSecTrust = theTrust; 1424 CFRetain(theTrust); 1425 } 1426 1427 if(!ctx->enableCertVerify) { 1428 /* trivial case, this is caller's responsibility */ 1429 serr = errSecSuccess; 1430 goto errOut; 1431 } 1432 1433 /* 1434 * If the caller provided a list of trusted leaf certs, check them here 1435 */ 1436 if(ctx->trustedLeafCerts) { 1437 if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certGroup, 0), 1438 ctx->trustedLeafCerts)) { 1439 serr = errSecSuccess; 1440 goto errOut; 1441 } 1442 } 1443 1444 /* 1445 * Here we go; hand it over to SecTrust/TP. 1446 */ 1447 serr = SecTrustEvaluate(theTrust, &secTrustResult); 1448 if(serr) { 1449 sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n", 1450 (int)serr); 1451 goto errOut; 1452 } 1453 switch(secTrustResult) { 1454 case kSecTrustResultUnspecified: 1455 /* cert chain valid, no special UserTrust assignments */ 1456 case kSecTrustResultProceed: 1457 /* cert chain valid AND user explicitly trusts this */ 1458 crtn = CSSM_OK; 1459 break; 1460 case kSecTrustResultDeny: 1461 case kSecTrustResultConfirm: 1462 /* 1463 * Cert chain may well have verified OK, but user has flagged 1464 * one of these certs as untrustable. 1465 */ 1466 crtn = CSSMERR_TP_NOT_TRUSTED; 1467 break; 1468 default: 1469 { 1470 OSStatus osCrtn; 1471 serr = SecTrustGetCssmResultCode(theTrust, &osCrtn); 1472 if(serr) { 1473 sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode" 1474 " rtn %d\n", (int)serr); 1475 goto errOut; 1476 } 1477 crtn = osCrtn; 1478 } 1479 } 1480 if(crtn) { 1481 /* get some detailed error info */ 1482 switch(crtn) { 1483 case CSSMERR_TP_INVALID_ANCHOR_CERT: 1484 /* root found but we don't trust it */ 1485 if(ctx->allowAnyRoot) { 1486 serr = errSecSuccess; 1487 sslErrorLog("***Warning: accepting unknown root cert\n"); 1488 } 1489 else { 1490 serr = errSSLUnknownRootCert; 1491 } 1492 break; 1493 case CSSMERR_TP_NOT_TRUSTED: 1494 /* no root, not even in implicit SSL roots */ 1495 if(ctx->allowAnyRoot) { 1496 sslErrorLog("***Warning: accepting unverified cert chain\n"); 1497 serr = errSecSuccess; 1498 } 1499 else { 1500 serr = errSSLNoRootCert; 1501 } 1502 break; 1503 case CSSMERR_TP_CERT_EXPIRED: 1504 assert(!ctx->allowExpiredCerts); 1505 serr = errSSLCertExpired; 1506 break; 1507 case CSSMERR_TP_CERT_NOT_VALID_YET: 1508 serr = errSSLCertNotYetValid; 1509 break; 1510 case CSSMERR_APPLETP_HOSTNAME_MISMATCH: 1511 serr = errSSLHostNameMismatch; 1512 break; 1513 case errSecInvalidTrustSettings: 1514 /* these get passed along unmodified */ 1515 serr = crtn; 1516 break; 1517 default: 1518 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned", 1519 crtn); 1520 serr = errSSLXCertChainInvalid; 1521 break; 1522 } 1523 } /* SecTrustEvaluate error */ 1524 1525errOut: 1526 /* 1527 * Free up resources - certGroup, policy, etc. Note that most of these 1528 * will actually persist as long as the current SSLContext does since 1529 * peerSecTrust holds references to these. 1530 */ 1531 if(policy) { 1532 CFRelease(policy); 1533 } 1534 if(policySearch) { 1535 CFRelease(policySearch); 1536 } 1537 if(actionData) { 1538 CFRelease(actionData); 1539 } 1540 if(anchors) { 1541 sslReleaseArray(anchors); 1542 CFRelease(anchors); 1543 } 1544 if(certGroup) { 1545 sslReleaseArray(certGroup); 1546 CFRelease(certGroup); 1547 } 1548 if(kcList) { 1549 /* empty, no contents to release */ 1550 CFRelease(kcList); 1551 } 1552 if(theTrust) { 1553 CFRelease(theTrust); 1554 } 1555 return serr; 1556} 1557 1558#ifndef NDEBUG 1559void stPrintCdsaError(const char *op, CSSM_RETURN crtn) 1560{ 1561 cssmPerror(op, crtn); 1562} 1563#endif 1564 1565// MARK: - 1566// MARK: Diffie-Hellman Support 1567 1568/* 1569 * Generate a Diffie-Hellman key pair. Algorithm parameters always 1570 * come from the server, so on client side we have the parameters 1571 * as two SSLBuffers. On server side we have the pre-encoded block 1572 * which comes from ServerDhParams. 1573 */ 1574OSStatus sslDhGenKeyPairClient( 1575 SSLContext *ctx, 1576 const SSLBuffer *prime, 1577 const SSLBuffer *generator, 1578 CSSM_KEY_PTR publicKey, // RETURNED 1579 CSSM_KEY_PTR privateKey) // RETURNED 1580{ 1581 assert((prime->data != NULL) && (generator->data != NULL)); 1582 if(prime->data && !generator->data) { 1583 return errSSLProtocol; 1584 } 1585 if(!prime->data && generator->data) { 1586 return errSSLProtocol; 1587 } 1588 1589 SSLBuffer sParam; 1590 OSStatus ortn = sslEncodeDhParams(prime, generator, &sParam); 1591 if(ortn) { 1592 sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n"); 1593 return ortn; 1594 } 1595 ortn = sslDhGenerateKeyPair(ctx, &sParam, prime->length * 8, publicKey, privateKey); 1596 SSLFreeBuffer(&sParam); 1597 return ortn; 1598} 1599 1600OSStatus sslDhGenerateKeyPair( 1601 SSLContext *ctx, 1602 const SSLBuffer *paramBlob, 1603 uint32_t keySizeInBits, 1604 CSSM_KEY_PTR publicKey, // RETURNED 1605 CSSM_KEY_PTR privateKey) // RETURNED 1606{ 1607 CSSM_RETURN crtn; 1608 CSSM_CC_HANDLE ccHandle; 1609 CSSM_DATA labelData = {8, (uint8 *)"tempKey"}; 1610 OSStatus ortn = errSecSuccess; 1611 CSSM_DATA cParamBlob; 1612 1613 assert(ctx != NULL); 1614 assert(ctx->cspHand != 0); 1615 1616 memset(publicKey, 0, sizeof(CSSM_KEY)); 1617 memset(privateKey, 0, sizeof(CSSM_KEY)); 1618 SSLBUF_TO_CSSM(paramBlob, &cParamBlob); 1619 1620 crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand, 1621 CSSM_ALGID_DH, 1622 keySizeInBits, 1623 NULL, // Seed 1624 NULL, // Salt 1625 NULL, // StartDate 1626 NULL, // EndDate 1627 &cParamBlob, 1628 &ccHandle); 1629 if(crtn) { 1630 stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn); 1631 return errSSLCrypto; 1632 } 1633 1634 crtn = CSSM_GenerateKeyPair(ccHandle, 1635 CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key 1636 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, 1637 &labelData, 1638 publicKey, 1639 /* private key specification */ 1640 CSSM_KEYUSE_DERIVE, 1641 CSSM_KEYATTR_RETURN_REF, 1642 &labelData, // same labels 1643 NULL, // CredAndAclEntry 1644 privateKey); 1645 if(crtn) { 1646 stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn); 1647 ortn = errSSLCrypto; 1648 } 1649 CSSM_DeleteContext(ccHandle); 1650 return ortn; 1651} 1652 1653/* 1654 * Perform Diffie-Hellman key exchange. 1655 * Valid on entry: 1656 * ctx->dhPrivate 1657 * ctx->dhPeerPublic 1658 * 1659 * This generates deriveSizeInBits of key-exchanged data. 1660 */ 1661 1662/* the alg isn't important; we just want to be able to cook up lots of bits */ 1663#define DERIVE_KEY_ALG CSSM_ALGID_RC5 1664 1665OSStatus sslDhKeyExchange( 1666 SSLContext *ctx, 1667 uint32_t deriveSizeInBits, 1668 SSLBuffer *exchanged) 1669{ 1670 CSSM_RETURN crtn; 1671 CSSM_ACCESS_CREDENTIALS creds; 1672 CSSM_CC_HANDLE ccHandle; 1673 CSSM_DATA labelData = {8, (uint8 *)"tempKey"}; 1674 CSSM_KEY derivedKey; 1675 OSStatus ortn = errSecSuccess; 1676 1677 assert(ctx != NULL); 1678 assert(ctx->cspHand != 0); 1679 assert(ctx->dhPrivate != NULL); 1680 if(ctx->dhPeerPublic.length == 0) { 1681 /* comes from peer, don't panic */ 1682 sslErrorLog("cdsaDhKeyExchange: null peer public key\n"); 1683 return errSSLProtocol; 1684 } 1685 1686 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 1687 memset(&derivedKey, 0, sizeof(CSSM_KEY)); 1688 1689 crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->cspHand, 1690 CSSM_ALGID_DH, 1691 DERIVE_KEY_ALG, 1692 deriveSizeInBits, 1693 &creds, 1694 ctx->dhPrivate, // BaseKey 1695 0, // IterationCount 1696 0, // Salt 1697 0, // Seed 1698 &ccHandle); 1699 if(crtn) { 1700 stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn); 1701 return errSSLCrypto; 1702 } 1703 1704 /* public key passed in as CSSM_DATA *Param */ 1705 CSSM_DATA theirPubKeyData; 1706 SSLBUF_TO_CSSM(&ctx->dhPeerPublic, &theirPubKeyData); 1707 1708 crtn = CSSM_DeriveKey(ccHandle, 1709 &theirPubKeyData, 1710 CSSM_KEYUSE_ANY, 1711 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, 1712 &labelData, 1713 NULL, // cread/acl 1714 &derivedKey); 1715 if(crtn) { 1716 stPrintCdsaError("DH CSSM_DeriveKey", crtn); 1717 ortn = errSSLCrypto; 1718 } 1719 else { 1720 CSSM_TO_SSLBUF(&derivedKey.KeyData, exchanged); 1721 } 1722 CSSM_DeleteContext(ccHandle); 1723 return ortn; 1724} 1725 1726// MARK: - 1727// MARK: *** ECDSA support *** 1728 1729/* specify either 32-bit integer or a pointer as an added attribute value */ 1730typedef enum { 1731 CAT_Uint32, 1732 CAT_Ptr 1733} ContextAttrType; 1734 1735/* 1736 * Given a context specified via a CSSM_CC_HANDLE, add a new 1737 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, 1738 * AttributeLength, and an untyped pointer. 1739 */ 1740static CSSM_RETURN sslAddContextAttribute(CSSM_CC_HANDLE CCHandle, 1741 uint32 AttributeType, 1742 uint32 AttributeLength, 1743 ContextAttrType attrType, 1744 /* specify exactly one of these */ 1745 const void *AttributePtr, 1746 uint32 attributeInt) 1747{ 1748 CSSM_CONTEXT_ATTRIBUTE newAttr; 1749 CSSM_RETURN crtn; 1750 1751 newAttr.AttributeType = AttributeType; 1752 newAttr.AttributeLength = AttributeLength; 1753 if(attrType == CAT_Uint32) { 1754 newAttr.Attribute.Uint32 = attributeInt; 1755 } 1756 else { 1757 newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; 1758 } 1759 crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); 1760 if(crtn) { 1761 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn); 1762 } 1763 return crtn; 1764} 1765 1766/* 1767 * Generate ECDH key pair with the given SSL_ECDSA_NamedCurve. 1768 * Private key, in ref form, is placed in ctx->ecdhPrivate. 1769 * Public key, in ECPoint form - which can NOT be used as 1770 * a key in any CSP ops - is placed in ecdhExchangePublic. 1771 */ 1772OSStatus sslEcdhGenerateKeyPair( 1773 SSLContext *ctx, 1774 SSL_ECDSA_NamedCurve namedCurve) 1775{ 1776 CSSM_RETURN crtn; 1777 CSSM_CC_HANDLE ccHandle = 0; 1778 CSSM_DATA labelData = {8, (uint8 *)"ecdsaKey"}; 1779 OSStatus ortn = errSecSuccess; 1780 CSSM_KEY pubKey; 1781 uint32 keySizeInBits; 1782 1783 assert(ctx != NULL); 1784 assert(ctx->cspHand != 0); 1785 sslFreeKey(ctx->ecdhPrivCspHand, &ctx->ecdhPrivate, NULL); 1786 SSLFreeBuffer(&ctx->ecdhExchangePublic); 1787 1788 switch(namedCurve) { 1789 case SSL_Curve_secp256r1: 1790 keySizeInBits = 256; 1791 break; 1792 case SSL_Curve_secp384r1: 1793 keySizeInBits = 384; 1794 break; 1795 case SSL_Curve_secp521r1: 1796 keySizeInBits = 521; 1797 break; 1798 default: 1799 /* should not have gotten this far */ 1800 sslErrorLog("sslEcdhGenerateKeyPair: bad namedCurve (%u)\n", 1801 (unsigned)namedCurve); 1802 return errSSLInternal; 1803 } 1804 1805 ctx->ecdhPrivate = (CSSM_KEY *)sslMalloc(sizeof(CSSM_KEY)); 1806 1807 memset(ctx->ecdhPrivate, 0, sizeof(CSSM_KEY)); 1808 memset(&pubKey, 0, sizeof(CSSM_KEY)); 1809 1810 crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand, 1811 CSSM_ALGID_ECDSA, 1812 keySizeInBits, 1813 NULL, // Seed 1814 NULL, // Salt 1815 NULL, // StartDate 1816 NULL, // EndDate 1817 NULL, // Params 1818 &ccHandle); 1819 if(crtn) { 1820 stPrintCdsaError("ECDH CSSM_CSP_CreateKeyGenContext", crtn); 1821 return errSSLCrypto; 1822 } 1823 /* subsequent errors to errOut: */ 1824 1825 /* 1826 * Here's how we get the raw ECPoint form of a public key 1827 */ 1828 crtn = sslAddContextAttribute(ccHandle, 1829 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT, 1830 sizeof(uint32), 1831 CAT_Uint32, 1832 NULL, 1833 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING); 1834 if(crtn) { 1835 ortn = errSSLCrypto; 1836 goto errOut; 1837 } 1838 1839 crtn = CSSM_GenerateKeyPair(ccHandle, 1840 /* public key specification */ 1841 CSSM_KEYUSE_DERIVE, // only legal use - right? 1842 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, 1843 &labelData, 1844 &pubKey, 1845 /* private key specification */ 1846 CSSM_KEYUSE_DERIVE, 1847 CSSM_KEYATTR_RETURN_REF, 1848 &labelData, // same labels 1849 NULL, // CredAndAclEntry 1850 ctx->ecdhPrivate); 1851 if(crtn) { 1852 stPrintCdsaError("ECDH CSSM_GenerateKeyPair", crtn); 1853 ortn = errSSLCrypto; 1854 goto errOut; 1855 } 1856 ctx->ecdhPrivCspHand = ctx->cspHand; 1857 1858 /* 1859 * Take that public key data, drop it into ecdhExchangePublic, 1860 * and free the key. 1861 */ 1862 ortn = SSLCopyBufferFromData(pubKey.KeyData.Data, pubKey.KeyData.Length, 1863 &ctx->ecdhExchangePublic); 1864 CSSM_FreeKey(ctx->cspHand, NULL, &pubKey, CSSM_FALSE); 1865 1866errOut: 1867 if(ccHandle != 0) { 1868 CSSM_DeleteContext(ccHandle); 1869 } 1870 return ortn; 1871 1872} 1873 1874/* 1875 * Perform ECDH key exchange. Obtained key material is the same 1876 * size as our private key. 1877 * 1878 * On entry, ecdhPrivate is our private key. The peer's public key 1879 * is either ctx->ecdhPeerPublic for ECDHE exchange, or 1880 * ctx->peerPubKey for ECDH exchange. 1881 */ 1882OSStatus sslEcdhKeyExchange( 1883 SSLContext *ctx, 1884 SSLBuffer *exchanged) 1885{ 1886 CSSM_RETURN crtn; 1887 CSSM_ACCESS_CREDENTIALS creds; 1888 const CSSM_ACCESS_CREDENTIALS *secCreds; 1889 const CSSM_ACCESS_CREDENTIALS *useCreds = &creds; 1890 CSSM_CC_HANDLE ccHandle; 1891 CSSM_DATA labelData = {8, (uint8 *)"tempKey"}; 1892 CSSM_KEY derivedKey; 1893 OSStatus ortn = errSecSuccess; 1894 CSSM_KEY rawKey; 1895 bool useRefKeys = false; 1896 uint32 keyAttr; 1897 SSLBuffer pubKeyBits = {0, NULL}; 1898 1899 assert(ctx != NULL); 1900 assert(ctx->ecdhPrivCspHand != 0); 1901 assert(ctx->ecdhPrivate != NULL); 1902 1903 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 1904 memset(&derivedKey, 0, sizeof(CSSM_KEY)); 1905 memset(&rawKey, 0, sizeof(CSSM_KEY)); 1906 1907 /* 1908 * If we're using an actual CSSM_KEY for the peer public key, and its 1909 * cspHand differs from our private key, we do things a bit different - 1910 * our key is in the CSPDL space, and it has a Sec-style ACL for which 1911 * we need creds. Also, the peer public key and the derived key have 1912 * to be in reference form. 1913 */ 1914 switch(ctx->selectedCipherSpec.keyExchangeMethod) { 1915 case SSL_ECDH_ECDSA: 1916 case SSL_ECDH_RSA: 1917 if(ctx->cspHand != ctx->ecdhPrivCspHand) { 1918 useRefKeys = true; 1919 } 1920 break; 1921 default: 1922 break; 1923 } 1924 if(useRefKeys) { 1925 assert(ctx->signingPrivKeyRef != NULL); 1926 ortn = SecKeyGetCredentials(ctx->signingPrivKeyRef, 1927 CSSM_ACL_AUTHORIZATION_DERIVE, 1928 kSecCredentialTypeDefault, 1929 &secCreds); 1930 if(ortn) { 1931 stPrintCdsaError("ECDH SecKeyGetCredentials", ortn); 1932 return ortn; 1933 } 1934 useCreds = secCreds; 1935 } 1936 crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->ecdhPrivCspHand, 1937 CSSM_ALGID_ECDH, 1938 DERIVE_KEY_ALG, 1939 ctx->ecdhPrivate->KeyHeader.LogicalKeySizeInBits, 1940 useCreds, 1941 ctx->ecdhPrivate, // BaseKey 1942 0, // IterationCount 1943 0, // Salt 1944 0, // Seed 1945 &ccHandle); 1946 if(crtn) { 1947 stPrintCdsaError("ECDH CSSM_CSP_CreateDeriveKeyContext", crtn); 1948 return errSSLCrypto; 1949 } 1950 /* subsequent errors to errOut: */ 1951 1952 CSSM_DATA theirPubKeyData = {0, NULL}; 1953 1954 switch(ctx->selectedCipherSpec.keyExchangeMethod) { 1955 case SSL_ECDHE_ECDSA: 1956 case SSL_ECDHE_RSA: 1957 /* public key passed in as CSSM_DATA *Param */ 1958 if(ctx->ecdhPeerPublic.length == 0) { 1959 /* comes from peer, don't panic */ 1960 sslErrorLog("sslEcdhKeyExchange: null peer public key\n"); 1961 ortn = errSSLProtocol; 1962 goto errOut; 1963 } 1964 SSLBUF_TO_CSSM(&ctx->ecdhPeerPublic, &theirPubKeyData); 1965 break; 1966 case SSL_ECDH_ECDSA: 1967 case SSL_ECDH_RSA: 1968 /* add pub key as a context attr */ 1969 if(ctx->peerPubKey == NULL) { 1970 sslErrorLog("sslEcdhKeyExchange: no peer key\n"); 1971 ortn = errSSLInternal; 1972 goto errOut; 1973 } 1974 1975 /* 1976 * If we're using CSPDL, extract the raw public key bits in ECPoint 1977 * form and transmit as CSSM_DATA *Param. 1978 * The securityd can't transmit a public key in a DeriveKey context 1979 * in any form. 1980 */ 1981 if(useRefKeys) { 1982 ortn = sslEcdsaPubKeyBits(ctx->peerPubKey, &pubKeyBits); 1983 if(ortn) { 1984 goto errOut; 1985 } 1986 SSLBUF_TO_CSSM(&pubKeyBits, &theirPubKeyData); 1987 } 1988 else { 1989 crtn = sslAddContextAttribute(ccHandle, 1990 CSSM_ATTRIBUTE_PUBLIC_KEY, 1991 sizeof(CSSM_KEY), 1992 CAT_Ptr, 1993 (void *)ctx->peerPubKey, 1994 0); 1995 if(crtn) { 1996 stPrintCdsaError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)", 1997 crtn); 1998 ortn = errSSLInternal; 1999 goto errOut; 2000 } 2001 } 2002 break; 2003 default: 2004 /* shouldn't be here */ 2005 assert(0); 2006 ortn = errSSLInternal; 2007 goto errOut; 2008 } 2009 2010 if(useRefKeys) { 2011 keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE; 2012 } 2013 else { 2014 keyAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE; 2015 } 2016 crtn = CSSM_DeriveKey(ccHandle, 2017 &theirPubKeyData, 2018 CSSM_KEYUSE_ANY, 2019 keyAttr, 2020 &labelData, 2021 NULL, // cred/acl 2022 &derivedKey); 2023 if(crtn) { 2024 stPrintCdsaError("ECDH CSSM_DeriveKey", crtn); 2025 ortn = errSSLCrypto; 2026 goto errOut; 2027 } 2028 2029 if(useRefKeys) { 2030 /* 2031 * one more step: NULL-wrap the generated ref key to something we 2032 * can use 2033 */ 2034 ortn = sslNullWrapKey(ctx->ecdhPrivCspHand, &derivedKey, &rawKey); 2035 if(ortn) { 2036 goto errOut; 2037 } 2038 ortn = SSLCopyBufferFromData(rawKey.KeyData.Data, rawKey.KeyData.Length, 2039 exchanged); 2040 } 2041 else { 2042 ortn = SSLCopyBufferFromData(derivedKey.KeyData.Data, 2043 derivedKey.KeyData.Length, exchanged); 2044 } 2045errOut: 2046 CSSM_DeleteContext(ccHandle); 2047 if(useRefKeys) { 2048 if(pubKeyBits.length) { 2049 SSLFreeBuffer(&pubKeyBits); 2050 } 2051 if(rawKey.KeyData.Length) { 2052 CSSM_FreeKey(ctx->ecdhPrivCspHand, NULL, &rawKey, CSSM_FALSE); 2053 } 2054 } 2055 return ortn; 2056} 2057 2058 2059/* 2060 * After ciphersuite negotiation is complete, verify that we have 2061 * the capability of actually performing the selected cipher. 2062 * Currently we just verify that we have a cert and private signing 2063 * key, if needed, and that the signing key's algorithm matches the 2064 * expected key exchange method. 2065 * 2066 * This is currently called from FindCipherSpec(), after it sets 2067 * ctx->selectedCipherSuite to a (supposedly) valid value, and from 2068 * sslBuildCipherSuiteArray(), in server mode (pre-negotiation) only. 2069 */ 2070OSStatus sslVerifySelectedCipher( 2071 SSLContext *ctx, 2072 const SSLCipherSpec *selectedCipherSpec) 2073{ 2074 if(ctx->protocolSide == kSSLClientSide) { 2075 return errSecSuccess; 2076 } 2077 #if SSL_PAC_SERVER_ENABLE 2078 if((ctx->masterSecretCallback != NULL) && 2079 (ctx->sessionTicket.data != NULL)) { 2080 /* EAP via PAC resumption; we can do it */ 2081 return errSecSuccess; 2082 } 2083 #endif /* SSL_PAC_SERVER_ENABLE */ 2084 2085 CSSM_ALGORITHMS requireAlg = CSSM_ALGID_NONE; 2086 if(selectedCipherSpec == NULL) { 2087 return errSSLInternal; 2088 } 2089 switch (selectedCipherSpec->keyExchangeMethod) { 2090 case SSL_RSA: 2091 case SSL_RSA_EXPORT: 2092 case SSL_DH_RSA: 2093 case SSL_DH_RSA_EXPORT: 2094 case SSL_DHE_RSA: 2095 case SSL_DHE_RSA_EXPORT: 2096 requireAlg = CSSM_ALGID_RSA; 2097 break; 2098 case SSL_DHE_DSS: 2099 case SSL_DHE_DSS_EXPORT: 2100 case SSL_DH_DSS: 2101 case SSL_DH_DSS_EXPORT: 2102 requireAlg = CSSM_ALGID_DSA; 2103 break; 2104 case SSL_DH_anon: 2105 case SSL_DH_anon_EXPORT: 2106 /* CSSM_ALGID_NONE, no signing key */ 2107 break; 2108 /* 2109 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side, 2110 * we'll need to add some logic here... 2111 */ 2112 #if SSL_ECDSA_SERVER 2113 #error Work needed in sslVerifySelectedCipher 2114 #endif 2115 2116 default: 2117 /* needs update per cipherSpecs.c */ 2118 assert(0); 2119 return errSSLInternal; 2120 } 2121 if(requireAlg == CSSM_ALGID_NONE) { 2122 return errSecSuccess; 2123 } 2124 2125 /* private signing key required */ 2126 if(ctx->signingPrivKeyRef == NULL) { 2127 sslErrorLog("sslVerifySelectedCipher: no signing key\n"); 2128 return errSSLBadConfiguration; 2129 } 2130 { 2131 const CSSM_KEY *cssmKey; 2132 OSStatus ortn = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey); 2133 if(ortn) { 2134 sslErrorLog("sslVerifySelectedCipher: SecKeyGetCSSMKey err %d\n", 2135 (int)ortn); 2136 return ortn; 2137 } 2138 if(cssmKey->KeyHeader.AlgorithmId != requireAlg) { 2139 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n"); 2140 return errSSLBadConfiguration; 2141 } 2142 } 2143 return errSecSuccess; 2144} 2145 2146#endif /* USE_CDSA_CRYPTO */ 2147 2148