]> git.saurik.com Git - apple/security.git/blobdiff - SecureTransport/sslKeyExchange.cpp
Security-222.tar.gz
[apple/security.git] / SecureTransport / sslKeyExchange.cpp
diff --git a/SecureTransport/sslKeyExchange.cpp b/SecureTransport/sslKeyExchange.cpp
deleted file mode 100644 (file)
index cf7c77b..0000000
+++ /dev/null
@@ -1,1376 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
- * 
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-/*
-       File:           sslKeyExchange.c
-
-       Contains:       Support for key exchange and server key exchange
-
-       Written by:     Doug Mitchell
-
-       Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
-
-*/
-
-#include "sslContext.h"
-#include "sslHandshake.h"
-#include "sslMemory.h"
-#include "sslDebug.h"
-#include "sslUtils.h"
-#include "appleCdsa.h"
-#include "sslDigests.h"
-#include "ModuleAttacher.h"
-#include "sslBER.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include <Security/globalizer.h>
-#include <Security/threading.h>
-
-#pragma mark -
-#pragma mark *** forward static declarations ***
-static OSStatus SSLGenServerDHParamsAndKey(SSLContext *ctx);
-static OSStatus SSLEncodeDHKeyParams(SSLContext *ctx, UInt8 *charPtr);
-static OSStatus SSLDecodeDHKeyParams(SSLContext *ctx, UInt8 *&charPtr,
-       UInt32 length);
-
-#define DH_PARAM_DUMP          0
-#if    DH_PARAM_DUMP
-
-static void dumpBuf(const char *name, SSLBuffer &buf)
-{
-       printf("%s:\n", name);
-       UInt8 *cp = buf.data;
-       UInt8 *endCp = cp + buf.length;
-       
-       do {
-               for(unsigned i=0; i<16; i++) {
-                       printf("%02x ", *cp++);
-                       if(cp == endCp) {
-                               break;
-                       }
-               }
-               if(cp == endCp) {
-                       break;
-               }
-               printf("\n");
-       } while(cp < endCp);
-       printf("\n");
-}
-#else
-#define dumpBuf(n, b)
-#endif /* DH_PARAM_DUMP */
-
-#if    APPLE_DH
-
-#pragma mark -
-#pragma mark *** local D-H parameter generator ***
-/*
- * Process-wide server-supplied Diffie-Hellman parameters. 
- * This might be overridden by some API_supplied parameters
- * in the future.
- */
-class ServerDhParams
-{
-public:
-       ServerDhParams();
-       ~ServerDhParams();
-       const SSLBuffer &prime()                { return mPrime; }
-       const SSLBuffer &generator()    { return mGenerator; }
-       const SSLBuffer &paramBlock()   { return mParamBlock; }
-       
-private:
-       /* these two for sending over the wire */
-       SSLBuffer               mPrime;         
-       SSLBuffer               mGenerator;
-       /* this one for sending to the CSP at key gen time */
-       SSLBuffer               mParamBlock;
-};
-
-ServerDhParams::ServerDhParams()
-{
-       mPrime.data = NULL;
-       mPrime.length = 0;
-       mGenerator.data = NULL;
-       mGenerator.length = 0;
-       mParamBlock.data = NULL;
-       mParamBlock.length = 0;
-       
-       CSSM_CSP_HANDLE cspHand;
-       CSSM_CL_HANDLE clHand;                  // not used here, just for 
-                                                                       //   attachToModules()
-       CSSM_TP_HANDLE tpHand;                  // ditto
-       CSSM_RETURN crtn;
-       
-       crtn = attachToModules(&cspHand, &clHand, &tpHand);
-       if(crtn) {
-               MacOSError::throwMe(errSSLModuleAttach);
-       }
-       
-       CSSM_CC_HANDLE  ccHandle;
-       CSSM_DATA cParams = {0, NULL};
-       
-       crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
-               CSSM_ALGID_DH,
-               SSL_DH_DEFAULT_PRIME_SIZE,
-               NULL,                                   // Seed
-               NULL,                                   // Salt
-               NULL,                                   // StartDate
-               NULL,                                   // EndDate
-               &cParams,                       // Params, may be NULL
-               &ccHandle);
-       if(crtn) {
-               stPrintCdsaError("ServerDhParams CSSM_CSP_CreateKeyGenContext", crtn);
-               MacOSError::throwMe(errSSLCrypto);
-       }
-       
-       /* explicitly generate params and save them */
-       sslDhDebug("^^^generating Diffie-Hellman parameters...");
-       crtn = CSSM_GenerateAlgorithmParams(ccHandle, 
-               SSL_DH_DEFAULT_PRIME_SIZE, &cParams);
-       if(crtn) {
-               stPrintCdsaError("ServerDhParams CSSM_GenerateAlgorithmParams", crtn);
-               CSSM_DeleteContext(ccHandle);
-               MacOSError::throwMe(errSSLCrypto);
-       }
-       CSSM_TO_SSLBUF(&cParams, &mParamBlock);
-       OSStatus ortn = sslDecodeDhParams(&mParamBlock, &mPrime, &mGenerator);
-       if(ortn) {
-               sslErrorLog("ServerDhParams: param decode error\n");
-               MacOSError::throwMe(ortn);
-       }
-       CSSM_DeleteContext(ccHandle);
-}
-
-ServerDhParams::~ServerDhParams()
-{
-       sslFree(mPrime.data);
-       sslFree(mGenerator.data);
-       sslFree(mParamBlock.data);
-}
-
-/* the single global thing */
-static ModuleNexus<ServerDhParams> serverDhParams;
-
-#endif /* APPLE_DH */
-
-#pragma mark -
-#pragma mark *** RSA key exchange ***
-
-/*
- * Client RSA Key Exchange msgs actually start with a two-byte
- * length field, contrary to the first version of RFC 2246, dated
- * January 1999. See RFC 2246, March 2002, section 7.4.7.1 for 
- * updated requirements. 
- */
-#define RSA_CLIENT_KEY_ADD_LENGTH              1
-
-typedef        CSSM_KEY_PTR    SSLRSAPrivateKey;
-
-static OSStatus
-SSLEncodeRSAKeyParams(SSLBuffer *keyParams, SSLRSAPrivateKey *key, SSLContext *ctx)
-{   OSStatus    err;
-    SSLBuffer   modulus, exponent;
-    UInt8       *charPtr;
-
-       if(err = attachToCsp(ctx)) {
-               return err;
-       }
-       
-       /* Note currently ALL public keys are raw, obtained from the CL... */
-       assert((*key)->KeyHeader.BlobType == CSSM_KEYBLOB_RAW);
-       err = sslGetPubKeyBits(ctx,
-               *key,
-               ctx->cspHand,
-               &modulus,
-               &exponent);
-       if(err) {
-               SSLFreeBuffer(modulus, ctx);
-               SSLFreeBuffer(exponent, ctx);
-               return err;
-       }
-    
-    if ((err = SSLAllocBuffer(*keyParams, 
-                       modulus.length + exponent.length + 4, ctx)) != 0) {
-        return err;
-       }
-    charPtr = keyParams->data;
-    charPtr = SSLEncodeInt(charPtr, modulus.length, 2);
-    memcpy(charPtr, modulus.data, modulus.length);
-    charPtr += modulus.length;
-    charPtr = SSLEncodeInt(charPtr, exponent.length, 2);
-    memcpy(charPtr, exponent.data, exponent.length);
-
-       /* these were mallocd by sslGetPubKeyBits() */
-       SSLFreeBuffer(modulus, ctx);
-       SSLFreeBuffer(exponent, ctx);
-    return noErr;
-}
-
-static OSStatus
-SSLEncodeRSAPremasterSecret(SSLContext *ctx)
-{   SSLBuffer           randData;
-    OSStatus            err;
-    SSLProtocolVersion maxVersion;
-       
-    if ((err = SSLAllocBuffer(ctx->preMasterSecret, 
-                       SSL_RSA_PREMASTER_SECRET_SIZE, ctx)) != 0)
-        return err;
-    
-       assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
-                  (ctx->negProtocolVersion == TLS_Version_1_0));
-       sslGetMaxProtVersion(ctx, &maxVersion);
-    SSLEncodeInt(ctx->preMasterSecret.data, maxVersion, 2);
-    randData.data = ctx->preMasterSecret.data+2;
-    randData.length = SSL_RSA_PREMASTER_SECRET_SIZE - 2;
-    if ((err = sslRand(ctx, &randData)) != 0)
-        return err;
-    return noErr;
-}
-
-/*
- * Generate a server key exchange message signed by our RSA or DSA private key. 
- */
-static OSStatus
-SSLEncodeSignedServerKeyExchange(SSLRecord &keyExch, SSLContext *ctx)
-{   OSStatus        err;
-    UInt8           *charPtr;
-    int             outputLen;
-    UInt8           hashes[SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN];
-    SSLBuffer       exchangeParams,clientRandom,serverRandom,hashCtx, hash;
-       UInt8                   *dataToSign;
-       UInt32                  dataToSignLen;
-       bool                    isRsa = true;
-    UInt32                     maxSigLen;
-    UInt32             actSigLen;
-       SSLBuffer               signature;
-       const CSSM_KEY  *cssmKey;
-       
-    assert(ctx->protocolSide == SSL_ServerSide);
-       assert(ctx->signingPubKey != NULL);
-       assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
-                  (ctx->negProtocolVersion == TLS_Version_1_0));
-    exchangeParams.data = 0;
-    hashCtx.data = 0;
-       signature.data = 0;
-       
-       /* Set up parameter block to hash ==> exchangeParams */
-       switch(ctx->selectedCipherSpec->keyExchangeMethod) {
-               case SSL_RSA:
-        case SSL_RSA_EXPORT:
-                       /* 
-                        * Parameter block = encryption public key.
-                        * If app hasn't supplied a separate encryption cert, abort.
-                        */
-                       if(ctx->encryptPubKey == NULL) {
-                               sslErrorLog("RSAServerKeyExchange: no encrypt cert\n");
-                               return errSSLBadConfiguration;
-                       }
-                       err = SSLEncodeRSAKeyParams(&exchangeParams, 
-                               &ctx->encryptPubKey, ctx);
-                       break;
-                       
-               #if     APPLE_DH
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-                       isRsa = false;
-                       /* and fall through */
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-               {
-                       /* 
-                        * Parameter block = {prime, generator, public key}
-                        * Obtain D-H parameters (if we don't have them) and a key pair. 
-                        */
-                       err = SSLGenServerDHParamsAndKey(ctx);
-                       if(err) {
-                               return err;
-                       }
-                       UInt32 len = ctx->dhParamsPrime.length + 
-                               ctx->dhParamsGenerator.length + 
-                               ctx->dhExchangePublic.length + 6 /* 3 length fields */;
-                       err = SSLAllocBuffer(exchangeParams, len, ctx);
-                       if(err) {
-                               goto fail;
-                       }
-                       err = SSLEncodeDHKeyParams(ctx, exchangeParams.data);
-                       break;
-               }
-               #endif  /* APPLE_DH */
-               default:
-                       /* shouldn't be here */
-                       assert(0);
-                       return errSSLInternal;
-       }
-       if(err) {
-               goto fail;
-       }
-                           
-       /* cook up hash(es) for raw sign */
-    clientRandom.data   = ctx->clientRandom;
-    clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
-    serverRandom.data   = ctx->serverRandom;
-    serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
-    
-       if(isRsa) {
-               /* skip this if signing with DSA */
-               dataToSign = hashes;
-               dataToSignLen = SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN;
-               hash.data = &hashes[0];
-               hash.length = SSL_MD5_DIGEST_LEN;
-               
-               if ((err = ReadyHash(SSLHashMD5, hashCtx, ctx)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.update(hashCtx, clientRandom)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.update(hashCtx, serverRandom)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.update(hashCtx, exchangeParams)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.final(hashCtx, hash)) != 0)
-                       goto fail;
-               if ((err = SSLFreeBuffer(hashCtx, ctx)) != 0)
-                       goto fail;
-    }
-       else {
-               /* DSA - just use the SHA1 hash */
-               dataToSign = &hashes[SSL_MD5_DIGEST_LEN];
-               dataToSignLen = SSL_SHA1_DIGEST_LEN;
-       }
-    hash.data = &hashes[SSL_MD5_DIGEST_LEN];
-    hash.length = SSL_SHA1_DIGEST_LEN;
-    if ((err = ReadyHash(SSLHashSHA1, hashCtx, ctx)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.update(hashCtx, clientRandom)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.update(hashCtx, serverRandom)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.update(hashCtx, exchangeParams)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.final(hashCtx, hash)) != 0)
-        goto fail;
-    if ((err = SSLFreeBuffer(hashCtx, ctx)) != 0)
-        goto fail;
-    
-       /* preallocate a buffer for signing */
-       err = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey);
-       if(err) {
-               sslErrorLog("SSLEncodeSignedServerKeyExchange: SecKeyGetCSSMKey err %d\n",
-                       (int)err);
-        goto fail;
-       }
-       err = sslGetMaxSigSize(cssmKey, maxSigLen);
-       if(err) {
-        goto fail;
-       }
-       err = SSLAllocBuffer(signature, maxSigLen, ctx);
-       if(err) {
-               goto fail;
-       }
-       
-       err = sslRawSign(ctx,
-               ctx->signingPrivKeyRef,
-               dataToSign,                     // one or two hashes
-               dataToSignLen,
-               signature.data,
-               maxSigLen,
-               &actSigLen);
-       if(err) {
-               goto fail;
-       }
-       assert(actSigLen <= maxSigLen);
-       
-       /* package it all up */
-    outputLen = exchangeParams.length + 2 + actSigLen;
-    keyExch.protocolVersion = ctx->negProtocolVersion;
-    keyExch.contentType = SSL_RecordTypeHandshake;
-    if ((err = SSLAllocBuffer(keyExch.contents, outputLen+4, ctx)) != 0)
-        goto fail;
-    
-    charPtr = keyExch.contents.data;
-    *charPtr++ = SSL_HdskServerKeyExchange;
-    charPtr = SSLEncodeInt(charPtr, outputLen, 3);
-    
-    memcpy(charPtr, exchangeParams.data, exchangeParams.length);
-    charPtr += exchangeParams.length;
-    charPtr = SSLEncodeInt(charPtr, actSigLen, 2);
-       memcpy(charPtr, signature.data, actSigLen);
-    assert((charPtr + actSigLen) == 
-                  (keyExch.contents.data + keyExch.contents.length));
-    
-    err = noErr;
-    
-fail:
-    SSLFreeBuffer(hashCtx, ctx);
-    SSLFreeBuffer(exchangeParams, ctx);
-    SSLFreeBuffer(signature, ctx);
-    return err;
-}
-
-/*
- * Decode and verify a server key exchange message signed by server's 
- * public key. 
- */
-static OSStatus
-SSLDecodeSignedServerKeyExchange(SSLBuffer message, SSLContext *ctx)
-{   
-       OSStatus        err;
-    SSLBuffer       hashOut, hashCtx, clientRandom, serverRandom;
-    UInt16          modulusLen, exponentLen, signatureLen;
-    UInt8           *modulus, *exponent, *signature;
-    UInt8           hashes[SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN];
-    SSLBuffer       signedHashes;
-       UInt8                   *dataToSign;
-       UInt32                  dataToSignLen;
-       bool                    isRsa = true;
-       
-       assert(ctx->protocolSide == SSL_ClientSide);
-       signedHashes.data = 0;
-    hashCtx.data = 0;
-    
-    if (message.length < 2) {
-       sslErrorLog("SSLDecodeSignedServerKeyExchange: msg len error 1\n");
-        return errSSLProtocol;
-    }
-       
-       /* first extract the key-exchange-method-specific parameters */
-    UInt8 *charPtr = message.data;
-       UInt8 *endCp = charPtr + message.length;
-       switch(ctx->selectedCipherSpec->keyExchangeMethod) {
-               case SSL_RSA:
-        case SSL_RSA_EXPORT:
-                       modulusLen = SSLDecodeInt(charPtr, 2);
-                       charPtr += 2;
-                       if((charPtr + modulusLen) > endCp) {
-                               sslErrorLog("signedServerKeyExchange: msg len error 2\n");
-                               return errSSLProtocol;
-                       }
-                       modulus = charPtr;
-                       charPtr += modulusLen;
-
-                       exponentLen = SSLDecodeInt(charPtr, 2);
-                       charPtr += 2;
-                       if((charPtr + exponentLen) > endCp) {
-                               sslErrorLog("signedServerKeyExchange: msg len error 3\n");
-                               return errSSLProtocol;
-                       }
-                       exponent = charPtr;
-                       charPtr += exponentLen;
-                       break;
-               #if             APPLE_DH
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-                       isRsa = false;
-                       /* and fall through */
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-                       err = SSLDecodeDHKeyParams(ctx, charPtr, message.length);
-                       if(err) {
-                               return err;
-                       }
-                       break;
-               #endif  /* APPLE_DH */
-               default:
-                       assert(0);
-                       return errSSLInternal;
-       }
-       
-       /* this is what's hashed */
-       SSLBuffer signedParams;
-       signedParams.data = message.data;
-       signedParams.length = charPtr - message.data;
-       
-       signatureLen = SSLDecodeInt(charPtr, 2);
-       charPtr += 2;
-       if((charPtr + signatureLen) != endCp) {
-               sslErrorLog("signedServerKeyExchange: msg len error 4\n");
-               return errSSLProtocol;
-       }
-       signature = charPtr;
-       
-    clientRandom.data = ctx->clientRandom;
-    clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
-    serverRandom.data = ctx->serverRandom;
-    serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
-       
-       if(isRsa) {
-               /* skip this if signing with DSA */
-               dataToSign = hashes;
-               dataToSignLen = SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN;
-               hashOut.data = hashes;
-               hashOut.length = SSL_MD5_DIGEST_LEN;
-               
-               if ((err = ReadyHash(SSLHashMD5, hashCtx, ctx)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.update(hashCtx, clientRandom)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.update(hashCtx, serverRandom)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.update(hashCtx, signedParams)) != 0)
-                       goto fail;
-               if ((err = SSLHashMD5.final(hashCtx, hashOut)) != 0)
-                       goto fail;
-       }
-       else {
-               /* DSA - just use the SHA1 hash */
-               dataToSign = &hashes[SSL_MD5_DIGEST_LEN];
-               dataToSignLen = SSL_SHA1_DIGEST_LEN;
-       }
-       hashOut.data = hashes + SSL_MD5_DIGEST_LEN; 
-    hashOut.length = SSL_SHA1_DIGEST_LEN;
-    if ((err = SSLFreeBuffer(hashCtx, ctx)) != 0)
-        goto fail;
-    
-    if ((err = ReadyHash(SSLHashSHA1, hashCtx, ctx)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.update(hashCtx, clientRandom)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.update(hashCtx, serverRandom)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.update(hashCtx, signedParams)) != 0)
-        goto fail;
-    if ((err = SSLHashSHA1.final(hashCtx, hashOut)) != 0)
-        goto fail;
-
-       err = sslRawVerify(ctx,
-               ctx->peerPubKey,
-               ctx->peerPubKeyCsp,
-               dataToSign,                             /* plaintext */
-               dataToSignLen,                  /* plaintext length */
-               signature,
-               signatureLen);
-       if(err) {
-               sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
-                       "returned %d\n", (int)err);
-               goto fail;
-       }
-    
-       /* Signature matches; now replace server key with new key */
-       switch(ctx->selectedCipherSpec->keyExchangeMethod) {
-               case SSL_RSA:
-        case SSL_RSA_EXPORT:
-               {
-                       SSLBuffer modBuf;
-                       SSLBuffer expBuf;
-                       
-                       /* first free existing peerKey */
-                       sslFreeKey(ctx->peerPubKeyCsp, 
-                               &ctx->peerPubKey,
-                               NULL);                                  /* no KCItem */
-                               
-                       /* and cook up a new one from raw bits */
-                       modBuf.data = modulus;
-                       modBuf.length = modulusLen;
-                       expBuf.data = exponent;
-                       expBuf.length = exponentLen;
-                       err = sslGetPubKeyFromBits(ctx,
-                               &modBuf,
-                               &expBuf,
-                               &ctx->peerPubKey,
-                               &ctx->peerPubKeyCsp);
-                       break;
-               }
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-                       break;                                  /* handled above */
-               default:
-                       assert(0);                              /* handled above */
-       }
-fail:
-    SSLFreeBuffer(signedHashes, ctx);
-    SSLFreeBuffer(hashCtx, ctx);
-    return err;
-}
-
-static OSStatus
-SSLDecodeRSAKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
-{   OSStatus            err;
-    UInt32                     outputLen, localKeyModulusLen;
-    SSLProtocolVersion  version;
-    Boolean                            useEncryptKey = false;
-       UInt8                           *src = NULL;
-       SecKeyRef                       keyRef = NULL;
-    const CSSM_KEY             *cssmKey;
-               
-       assert(ctx->protocolSide == SSL_ServerSide);
-       
-       #if             SSL_SERVER_KEYEXCH_HACK
-               /* 
-                * the way we work with Netscape.
-                * FIXME - maybe we should *require* an encryptPrivKey in this
-                * situation?
-                */
-               if((ctx->selectedCipherSpec->keyExchangeMethod == SSL_RSA_EXPORT) &&
-                       (ctx->encryptPrivKey != NULL)) {
-                       useEncryptKey = true;
-               }
-               
-       #else   /* !SSL_SERVER_KEYEXCH_HACK */
-               /* The "correct" way, I think, which doesn't work with Netscape */
-               if (ctx->encryptPrivKeyRef) {
-                       useEncryptKey = true;
-               }
-       #endif  /* SSL_SERVER_KEYEXCH_HACK */
-       if (useEncryptKey) {
-               keyRef  = ctx->encryptPrivKeyRef;
-               /* FIXME: when 3420180 is implemented, pick appropriate creds here */
-       } 
-       else {
-               keyRef  = ctx->signingPrivKeyRef;
-               /* FIXME: when 3420180 is implemented, pick appropriate creds here */
-       }
-       err = SecKeyGetCSSMKey(keyRef, &cssmKey);
-       if(err) {
-               sslErrorLog("SSLDecodeRSAKeyExchange: SecKeyGetCSSMKey err %d\n",
-                       (int)err);
-               return err;
-       }
-    
-       localKeyModulusLen = sslKeyLengthInBytes(cssmKey);
-
-       /* 
-        * We have to tolerate incoming key exchange msgs with and without the 
-        * two-byte "encrypted length" field.
-        */
-    if (keyExchange.length == localKeyModulusLen) {
-               /* no length encoded */
-               src = keyExchange.data;
-       }
-       else if((keyExchange.length == (localKeyModulusLen + 2)) &&
-               (ctx->negProtocolVersion >= TLS_Version_1_0)) {
-               /* TLS only - skip the length bytes */
-               src = keyExchange.data + 2;
-       }
-       else {
-       sslErrorLog("SSLDecodeRSAKeyExchange: length error (exp %u got %u)\n",
-                       (unsigned)localKeyModulusLen, (unsigned)keyExchange.length);
-        return errSSLProtocol;
-       }
-    err = SSLAllocBuffer(ctx->preMasterSecret, SSL_RSA_PREMASTER_SECRET_SIZE, ctx);
-       if(err != 0) {
-        return err;
-       }
-
-       /*
-        * From this point on, to defend against the Bleichenbacher attack
-        * and its Klima-Pokorny-Rosa variant, any errors we detect are *not* 
-        * reported to the caller or the peer. If we detect any error during 
-        * decryption (e.g., bad PKCS1 padding) or in the testing of the version
-        * number in the premaster secret, we proceed by generating a random
-        * premaster secret, with the correct version number, and tell our caller
-        * that everything is fine. This session will fail as soon as the 
-        * finished messages are sent, since we will be using a bogus premaster 
-        * secret (and hence bogus session and MAC keys). Meanwhile we have 
-        * not provided any side channel information relating to the cause of 
-        * the failure.
-        *
-        * See http://eprint.iacr.org/2003/052/ for more info.
-        */
-       err = sslRsaDecrypt(ctx,
-               keyRef,
-               src, 
-               localKeyModulusLen,                             // ciphertext len
-               ctx->preMasterSecret.data,
-               SSL_RSA_PREMASTER_SECRET_SIZE,  // plaintext buf available
-               &outputLen);
-    
-       if(err != noErr) {                                                                      
-               /* possible Bleichenbacher attack */
-               sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: RSA decrypt fail");
-       }
-       else if(outputLen != SSL_RSA_PREMASTER_SECRET_SIZE) {   
-               sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: premaster secret size error");
-       err = errSSLProtocol;                                                   // not passed back to caller
-    }
-    
-       if(err == noErr) {
-               /*
-                * Two legal values here - the one we actually negotiated (which is 
-                * technically incorrect but not uncommon), and the one the client
-                * sent as its preferred version in the client hello msg.
-                */
-               version = (SSLProtocolVersion)SSLDecodeInt(ctx->preMasterSecret.data, 2);
-               if((version != ctx->negProtocolVersion) &&
-                  (version != ctx->clientReqProtocol)) {
-                       /* possible Klima-Pokorny-Rosa attack */
-                       sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: version error");
-                       err = errSSLProtocol;
-               }
-    }
-       if(err != noErr) {
-               /* 
-                * Obfuscate failures for defense against Bleichenbacher and
-                * Klima-Pokorny-Rosa attacks.
-                */
-               SSLEncodeInt(ctx->preMasterSecret.data, ctx->negProtocolVersion, 2);
-               SSLBuffer tmpBuf;
-               tmpBuf.data   = ctx->preMasterSecret.data + 2;
-               tmpBuf.length = SSL_RSA_PREMASTER_SECRET_SIZE - 2;
-               /* must ignore failures here */
-               sslRand(ctx, &tmpBuf);
-       }
-       
-       /* in any case, save premaster secret (good or bogus) and proceed */
-    return noErr;
-}
-
-static OSStatus
-SSLEncodeRSAKeyExchange(SSLRecord &keyExchange, SSLContext *ctx)
-{   OSStatus            err;
-    UInt32                     outputLen, peerKeyModulusLen;
-    UInt32                             bufLen;
-       UInt8                           *dst;
-       bool                            encodeLen = false;
-       
-       assert(ctx->protocolSide == SSL_ClientSide);
-    if ((err = SSLEncodeRSAPremasterSecret(ctx)) != 0)
-        return err;
-    
-    keyExchange.contentType = SSL_RecordTypeHandshake;
-       assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
-                       (ctx->negProtocolVersion == TLS_Version_1_0));
-    keyExchange.protocolVersion = ctx->negProtocolVersion;
-        
-       peerKeyModulusLen = sslKeyLengthInBytes(ctx->peerPubKey);
-       bufLen = peerKeyModulusLen + 4;
-       #if     RSA_CLIENT_KEY_ADD_LENGTH
-       if(ctx->negProtocolVersion >= TLS_Version_1_0) {
-               bufLen += 2;
-               encodeLen = true;
-       }
-       #endif
-    if ((err = SSLAllocBuffer(keyExchange.contents, 
-               bufLen,ctx)) != 0)
-    {   
-        return err;
-    }
-       dst = keyExchange.contents.data + 4;
-       if(encodeLen) {
-               dst += 2;
-       }
-    keyExchange.contents.data[0] = SSL_HdskClientKeyExchange;
-       
-       /* this is the record payload length */
-    SSLEncodeInt(keyExchange.contents.data + 1, bufLen - 4, 3);
-       if(encodeLen) {
-               /* the length of the encrypted pre_master_secret */
-               SSLEncodeInt(keyExchange.contents.data + 4,                     
-                       peerKeyModulusLen, 2);
-       }
-       err = sslRsaEncrypt(ctx,
-               ctx->peerPubKey,
-               /* FIXME - maybe this should be ctx->cspHand */
-               ctx->peerPubKeyCsp,
-               ctx->preMasterSecret.data, 
-               SSL_RSA_PREMASTER_SECRET_SIZE,
-               dst,
-               peerKeyModulusLen,
-               &outputLen);
-       if(err) {
-               return err;
-       }
-    
-    assert(outputLen == encodeLen ? 
-               keyExchange.contents.length - 6 :
-               keyExchange.contents.length - 4 );
-    
-    return noErr;
-}
-
-
-#if APPLE_DH
-
-#pragma mark -
-#pragma mark *** Diffie-Hellman key exchange ***
-
-/*
- * Diffie-Hellman setup, server side. On successful return, the 
- * following SSLContext members are valid:
- *
- *             dhParamsPrime
- *             dhParamsGenerator
- *             dhPrivate
- *             dhExchangePublic
- */
-static OSStatus
-SSLGenServerDHParamsAndKey(
-       SSLContext *ctx)
-{
-       OSStatus ortn;
-    assert(ctx->protocolSide == SSL_ServerSide);
-       
-       /* 
-        * Obtain D-H parameters if we don't have them.
-        */
-       if(ctx->dhParamsPrime.data == NULL) {
-               assert(ctx->dhParamsGenerator.data == NULL);
-               const SSLBuffer &pr = serverDhParams().prime();
-               ortn = SSLCopyBuffer(pr, ctx->dhParamsPrime);
-               if(ortn) {
-                       return ortn;
-               }
-               const SSLBuffer &gen = serverDhParams().generator();
-               ortn = SSLCopyBuffer(gen, ctx->dhParamsGenerator);
-               if(ortn) {
-                       return ortn;
-               }
-               const SSLBuffer &block = serverDhParams().paramBlock();
-               ortn = SSLCopyBuffer(block, ctx->dhParamsEncoded);
-               if(ortn) {
-                       return ortn;
-               }
-       }
-       
-       /* generate per-session D-H key pair */
-       sslFreeKey(ctx->cspHand, &ctx->dhPrivate, NULL);
-       SSLFreeBuffer(ctx->dhExchangePublic, ctx);
-       ctx->dhPrivate = (CSSM_KEY *)sslMalloc(sizeof(CSSM_KEY));
-       CSSM_KEY pubKey;
-       ortn = sslDhGenerateKeyPair(ctx, 
-               ctx->dhParamsEncoded,
-               ctx->dhParamsPrime.length * 8,
-               &pubKey, ctx->dhPrivate);
-       if(ortn) {
-               return ortn;
-       }
-       CSSM_TO_SSLBUF(&pubKey.KeyData, &ctx->dhExchangePublic);
-       return noErr;
-} 
-
-/*
- * Encode DH params and public key in caller-supplied buffer. 
- */
-static OSStatus 
-SSLEncodeDHKeyParams(
-       SSLContext *ctx,
-       UInt8 *charPtr)
-{
-    assert(ctx->protocolSide == SSL_ServerSide);
-       assert(ctx->dhParamsPrime.data != NULL);
-       assert(ctx->dhParamsGenerator.data != NULL);
-       assert(ctx->dhExchangePublic.data != NULL);
-       
-       charPtr = SSLEncodeInt(charPtr, ctx->dhParamsPrime.length, 2);
-       memcpy(charPtr, ctx->dhParamsPrime.data, ctx->dhParamsPrime.length);
-       charPtr += ctx->dhParamsPrime.length;
-       
-       charPtr = SSLEncodeInt(charPtr, ctx->dhParamsGenerator.length, 2);
-       memcpy(charPtr, ctx->dhParamsGenerator.data, 
-               ctx->dhParamsGenerator.length);
-       charPtr += ctx->dhParamsGenerator.length;
-       
-       charPtr = SSLEncodeInt(charPtr, ctx->dhExchangePublic.length, 2);
-       memcpy(charPtr, ctx->dhExchangePublic.data, 
-               ctx->dhExchangePublic.length);
-
-       dumpBuf("server prime", ctx->dhParamsPrime);
-       dumpBuf("server generator", ctx->dhParamsGenerator);
-       dumpBuf("server pub key", ctx->dhExchangePublic);
-       return noErr;
-}
-
-/*
- * Decode DH params and server public key.
- */
-static OSStatus
-SSLDecodeDHKeyParams(
-       SSLContext *ctx,
-       UInt8 *&charPtr,                // IN/OUT
-       UInt32 length)
-{   
-       OSStatus        err = noErr;
-       
-       assert(ctx->protocolSide == SSL_ClientSide);
-    UInt8 *endCp = charPtr + length;
-
-       /* Allow reuse via renegotiation */
-    SSLFreeBuffer(ctx->dhParamsPrime, ctx);
-    SSLFreeBuffer(ctx->dhParamsGenerator, ctx);
-       SSLFreeBuffer(ctx->dhPeerPublic, ctx);
-       
-       /* Prime, with a two-byte length */
-       UInt32 len = SSLDecodeInt(charPtr, 2);
-       charPtr += 2;
-       if((charPtr + len) > endCp) {
-               return errSSLProtocol;
-       }
-       err = SSLAllocBuffer(ctx->dhParamsPrime, len, ctx);
-       if(err) {
-               return err;
-       }
-       memmove(ctx->dhParamsPrime.data, charPtr, len);
-       charPtr += len;
-       
-       /* Generator, with a two-byte length */
-       len = SSLDecodeInt(charPtr, 2);
-       charPtr += 2;
-       if((charPtr + len) > endCp) {
-               return errSSLProtocol;
-       }
-       err = SSLAllocBuffer(ctx->dhParamsGenerator, len, ctx);
-       if(err) {
-               return err;
-       }
-       memmove(ctx->dhParamsGenerator.data, charPtr, len);
-       charPtr += len;
-       
-       /* peer public key, with a two-byte length */
-       len = SSLDecodeInt(charPtr, 2);
-       charPtr += 2;
-       err = SSLAllocBuffer(ctx->dhPeerPublic, len, ctx);
-       if(err) {
-               return err;
-       }
-       memmove(ctx->dhPeerPublic.data, charPtr, len);
-       charPtr += len;
-       
-       dumpBuf("client peer pub", ctx->dhPeerPublic);
-       dumpBuf("client prime", ctx->dhParamsPrime);
-       dumpBuf("client generator", ctx->dhParamsGenerator);
-               
-       return err;     
-}
-
-/* 
- * Given the server's Diffie-Hellman parameters, generate our
- * own DH key pair, and perform key exchange using the server's 
- * public key and our private key. The result is the premaster 
- * secret.
- *
- * SSLContext members valid on entry:
- *             dhParamsPrime
- *             dhParamsGenerator
- *             dhPeerPublic
- *  
- * SSLContext members valid on successful return:
- *             dhPrivate
- *             dhExchangePublic
- *             preMasterSecret
- */
-static OSStatus
-SSLGenClientDHKeyAndExchange(SSLContext *ctx)
-{   
-       OSStatus            ortn;
-
-    assert(ctx->protocolSide == SSL_ClientSide);
-       if((ctx->dhParamsPrime.data == NULL) ||
-          (ctx->dhParamsGenerator.data == NULL) ||
-          (ctx->dhPeerPublic.data == NULL)) {
-          sslErrorLog("SSLGenClientDHKeyAndExchange: incomplete server params\n");
-          return errSSLProtocol;
-       }
-       
-    /* generate two keys */
-       CSSM_KEY pubKey;
-       ctx->dhPrivate = (CSSM_KEY *)sslMalloc(sizeof(CSSM_KEY));
-       ortn = sslDhGenKeyPairClient(ctx, 
-               ctx->dhParamsPrime,     ctx->dhParamsGenerator,
-               &pubKey, ctx->dhPrivate);
-       if(ortn) {
-               sslFree(ctx->dhPrivate);
-               ctx->dhPrivate = NULL;
-               return ortn;
-       }
-       
-       /* do the exchange, size of prime */
-       ortn = sslDhKeyExchange(ctx, ctx->dhParamsPrime.length * 8, 
-               &ctx->preMasterSecret);
-       if(ortn) {
-               return ortn;
-       }
-       CSSM_TO_SSLBUF(&pubKey.KeyData, &ctx->dhExchangePublic);
-       return noErr;
-}
-
-static OSStatus
-SSLEncodeDHanonServerKeyExchange(SSLRecord &keyExch, SSLContext *ctx)
-{   
-       OSStatus            ortn = noErr;
-       
-       assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
-                       (ctx->negProtocolVersion == TLS_Version_1_0));
-       assert(ctx->protocolSide == SSL_ServerSide);
-
-       /* 
-        * Obtain D-H parameters (if we don't have them) and a key pair. 
-        */
-       ortn = SSLGenServerDHParamsAndKey(ctx);
-       if(ortn) {
-               return ortn;
-       }
-       
-       UInt32 length = 6 + 
-               ctx->dhParamsPrime.length + 
-               ctx->dhParamsGenerator.length + ctx->dhExchangePublic.length;
-       
-       keyExch.protocolVersion = ctx->negProtocolVersion;
-       keyExch.contentType = SSL_RecordTypeHandshake;
-       if ((ortn = SSLAllocBuffer(keyExch.contents, length+4, ctx)) != 0)
-               return ortn;
-       
-       UInt8 *charPtr = keyExch.contents.data;
-       *charPtr++ = SSL_HdskServerKeyExchange;
-       charPtr = SSLEncodeInt(charPtr, length, 3);
-       
-       /* encode prime, generator, our public key */
-       return SSLEncodeDHKeyParams(ctx, charPtr);
-}
-
-
-static OSStatus
-SSLDecodeDHanonServerKeyExchange(SSLBuffer message, SSLContext *ctx)
-{   
-       OSStatus        err = noErr;
-       
-       assert(ctx->protocolSide == SSL_ClientSide);
-    if (message.length < 6) {
-       sslErrorLog("SSLDecodeDHanonServerKeyExchange error: msg len %u\n",
-               (unsigned)message.length);
-        return errSSLProtocol;
-    }
-    UInt8 *charPtr = message.data;
-       err = SSLDecodeDHKeyParams(ctx, charPtr, message.length);
-       if(err == noErr) {
-               if((message.data + message.length) != charPtr) {
-                       err = errSSLProtocol;
-               }
-       }
-       return err;
-}
-
-static OSStatus
-SSLDecodeDHClientKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
-{   
-       OSStatus        ortn = noErr;
-    unsigned int    publicLen;
-
-       assert(ctx->protocolSide == SSL_ServerSide);
-       if(ctx->dhParamsPrime.data == NULL) {
-               /* should never happen */
-               assert(0);
-               return errSSLInternal;
-       }
-       
-       /* this message simply contains the client's public DH key */
-       UInt8 *charPtr = keyExchange.data;
-    publicLen = SSLDecodeInt(charPtr, 2);
-       charPtr += 2;
-       if((keyExchange.length != publicLen + 2) ||
-          (publicLen > ctx->dhParamsPrime.length)) {
-        return errSSLProtocol;
-    }
-       SSLFreeBuffer(ctx->dhPeerPublic, ctx);  // allow reuse via renegotiation
-       ortn = SSLAllocBuffer(ctx->dhPeerPublic, publicLen, ctx);
-       if(ortn) {
-               return ortn;
-       }
-       memmove(ctx->dhPeerPublic.data, charPtr, publicLen);
-       
-       /* DH Key exchange, result --> premaster secret */
-       SSLFreeBuffer(ctx->preMasterSecret, ctx);
-       ortn = sslDhKeyExchange(ctx, ctx->dhParamsPrime.length * 8, 
-               &ctx->preMasterSecret);
-
-       dumpBuf("server peer pub", ctx->dhPeerPublic);
-       dumpBuf("server premaster", ctx->preMasterSecret);
-       return ortn;
-}
-
-static OSStatus
-SSLEncodeDHClientKeyExchange(SSLRecord &keyExchange, SSLContext *ctx)
-{   OSStatus            err;
-    unsigned int        outputLen;
-    
-       assert(ctx->protocolSide == SSL_ClientSide);
-    if ((err = SSLGenClientDHKeyAndExchange(ctx)) != 0)
-        return err;
-    
-    outputLen = ctx->dhExchangePublic.length + 2;
-    
-    keyExchange.contentType = SSL_RecordTypeHandshake;
-       assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
-                       (ctx->negProtocolVersion == TLS_Version_1_0));
-    keyExchange.protocolVersion = ctx->negProtocolVersion;
-    
-    if ((err = SSLAllocBuffer(keyExchange.contents,outputLen + 4,ctx)) != 0)
-        return err;
-    
-    keyExchange.contents.data[0] = SSL_HdskClientKeyExchange;
-    SSLEncodeInt(keyExchange.contents.data+1, 
-               ctx->dhExchangePublic.length+2, 3);
-    
-    SSLEncodeInt(keyExchange.contents.data+4, 
-               ctx->dhExchangePublic.length, 2);
-    memcpy(keyExchange.contents.data+6, ctx->dhExchangePublic.data, 
-               ctx->dhExchangePublic.length);
-
-       dumpBuf("client pub key", ctx->dhExchangePublic);
-       dumpBuf("client premaster", ctx->preMasterSecret);
-    return noErr;
-}
-
-#endif /* APPLE_DH */
-
-#pragma mark -
-#pragma mark *** Public Functions ***
-OSStatus
-SSLEncodeServerKeyExchange(SSLRecord &keyExch, SSLContext *ctx)
-{   OSStatus      err;
-    
-    switch (ctx->selectedCipherSpec->keyExchangeMethod)
-    {   case SSL_RSA:
-        case SSL_RSA_EXPORT:
-        #if            APPLE_DH
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-               #endif  /* APPLE_DH */
-            if ((err = SSLEncodeSignedServerKeyExchange(keyExch, ctx)) != 0)
-                return err;
-            break;
-        #if            APPLE_DH
-        case SSL_DH_anon:
-               case SSL_DH_anon_EXPORT:
-            if ((err = SSLEncodeDHanonServerKeyExchange(keyExch, ctx)) != 0)
-                return err;
-            break;
-        #endif
-        default:
-            return unimpErr;
-    }
-    
-    return noErr;
-}
-
-OSStatus
-SSLProcessServerKeyExchange(SSLBuffer message, SSLContext *ctx)
-{   
-       OSStatus      err;
-    
-    switch (ctx->selectedCipherSpec->keyExchangeMethod) {   
-               case SSL_RSA:
-        case SSL_RSA_EXPORT:
-        #if            APPLE_DH
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-               #endif
-            err = SSLDecodeSignedServerKeyExchange(message, ctx);
-            break;
-        #if            APPLE_DH
-        case SSL_DH_anon:
-               case SSL_DH_anon_EXPORT:
-            err = SSLDecodeDHanonServerKeyExchange(message, ctx);
-            break;
-        #endif
-        default:
-            err = unimpErr;
-                       break;
-    }
-    
-    return err;
-}
-
-OSStatus
-SSLEncodeKeyExchange(SSLRecord &keyExchange, SSLContext *ctx)
-{   OSStatus      err;
-    
-    assert(ctx->protocolSide == SSL_ClientSide);
-    
-    switch (ctx->selectedCipherSpec->keyExchangeMethod) {
-               case SSL_RSA:
-        case SSL_RSA_EXPORT:
-            err = SSLEncodeRSAKeyExchange(keyExchange, ctx);
-            break;
-        #if            APPLE_DH
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-        case SSL_DH_anon:
-               case SSL_DH_anon_EXPORT:
-            err = SSLEncodeDHClientKeyExchange(keyExchange, ctx);
-            break;
-        #endif
-        default:
-            err = unimpErr;
-    }
-    
-    return err;
-}
-
-OSStatus
-SSLProcessKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
-{   OSStatus      err;
-    
-    switch (ctx->selectedCipherSpec->keyExchangeMethod)
-    {   case SSL_RSA:
-        case SSL_RSA_EXPORT:
-            if ((err = SSLDecodeRSAKeyExchange(keyExchange, ctx)) != 0)
-                return err;
-            break;
-               #if             APPLE_DH
-        case SSL_DH_anon:
-               case SSL_DHE_DSS:
-               case SSL_DHE_DSS_EXPORT:
-               case SSL_DHE_RSA:
-               case SSL_DHE_RSA_EXPORT:
-               case SSL_DH_anon_EXPORT:
-            if ((err = SSLDecodeDHClientKeyExchange(keyExchange, ctx)) != 0)
-                return err;
-            break;
-        #endif
-        default:
-            return unimpErr;
-    }
-    
-    return noErr;
-}
-
-OSStatus
-SSLInitPendingCiphers(SSLContext *ctx)
-{   OSStatus        err;
-    SSLBuffer       key;
-    UInt8           *keyDataProgress, *keyPtr, *ivPtr;
-    int             keyDataLen;
-    CipherContext   *serverPending, *clientPending;
-        
-    key.data = 0;
-    
-    ctx->readPending.macRef = ctx->selectedCipherSpec->macAlgorithm;
-    ctx->writePending.macRef = ctx->selectedCipherSpec->macAlgorithm;
-    ctx->readPending.symCipher = ctx->selectedCipherSpec->cipher;
-    ctx->writePending.symCipher = ctx->selectedCipherSpec->cipher;
-    ctx->readPending.sequenceNum.high = ctx->readPending.sequenceNum.low = 0;
-    ctx->writePending.sequenceNum.high = ctx->writePending.sequenceNum.low = 0;
-    
-    keyDataLen = ctx->selectedCipherSpec->macAlgorithm->hash->digestSize +
-                     ctx->selectedCipherSpec->cipher->secretKeySize;
-    if (ctx->selectedCipherSpec->isExportable == NotExportable)
-        keyDataLen += ctx->selectedCipherSpec->cipher->ivSize;
-    keyDataLen *= 2;        /* two of everything */
-    
-    if ((err = SSLAllocBuffer(key, keyDataLen, ctx)) != 0)
-        return err;
-       assert(ctx->sslTslCalls != NULL);
-    if ((err = ctx->sslTslCalls->generateKeyMaterial(key, ctx)) != 0)
-        goto fail;
-    
-    if (ctx->protocolSide == SSL_ServerSide)
-    {   serverPending = &ctx->writePending;
-        clientPending = &ctx->readPending;
-    }
-    else
-    {   serverPending = &ctx->readPending;
-        clientPending = &ctx->writePending;
-    }
-    
-    keyDataProgress = key.data;
-    memcpy(clientPending->macSecret, keyDataProgress, 
-               ctx->selectedCipherSpec->macAlgorithm->hash->digestSize);
-    keyDataProgress += ctx->selectedCipherSpec->macAlgorithm->hash->digestSize;
-    memcpy(serverPending->macSecret, keyDataProgress, 
-               ctx->selectedCipherSpec->macAlgorithm->hash->digestSize);
-    keyDataProgress += ctx->selectedCipherSpec->macAlgorithm->hash->digestSize;
-    
-       /* init the reusable-per-record MAC contexts */
-       err = ctx->sslTslCalls->initMac(clientPending, ctx);
-       if(err) {
-               goto fail;
-       }
-       err = ctx->sslTslCalls->initMac(serverPending, ctx);
-       if(err) {
-               goto fail;
-       }
-       
-    if (ctx->selectedCipherSpec->isExportable == NotExportable)
-    {   keyPtr = keyDataProgress;
-        keyDataProgress += ctx->selectedCipherSpec->cipher->secretKeySize;
-        /* Skip server write key to get to IV */
-        ivPtr = keyDataProgress + ctx->selectedCipherSpec->cipher->secretKeySize;
-        if ((err = ctx->selectedCipherSpec->cipher->initialize(keyPtr, ivPtr,
-                                    clientPending, ctx)) != 0)
-            goto fail;
-        keyPtr = keyDataProgress;
-        keyDataProgress += ctx->selectedCipherSpec->cipher->secretKeySize;
-        /* Skip client write IV to get to server write IV */
-        ivPtr = keyDataProgress + ctx->selectedCipherSpec->cipher->ivSize;
-        if ((err = ctx->selectedCipherSpec->cipher->initialize(keyPtr, ivPtr,
-                                    serverPending, ctx)) != 0)
-            goto fail;
-    }
-    else {
-        UInt8          clientExportKey[16], serverExportKey[16], 
-                                       clientExportIV[16],  serverExportIV[16];
-        SSLBuffer   clientWrite, serverWrite;
-        SSLBuffer      finalClientWrite, finalServerWrite;
-               SSLBuffer       finalClientIV, finalServerIV;
-               
-        assert(ctx->selectedCipherSpec->cipher->keySize <= 16);
-        assert(ctx->selectedCipherSpec->cipher->ivSize <= 16);
-        
-               /* Inputs to generateExportKeyAndIv are clientRandom, serverRandom,
-                *    clientWriteKey, serverWriteKey. The first two are already present
-                *    in ctx.
-                * Outputs are a key and IV for each of {server, client}.
-                */
-        clientWrite.data = keyDataProgress;
-        clientWrite.length = ctx->selectedCipherSpec->cipher->secretKeySize;
-        serverWrite.data = keyDataProgress + clientWrite.length;
-        serverWrite.length = ctx->selectedCipherSpec->cipher->secretKeySize;
-               finalClientWrite.data = clientExportKey;
-               finalServerWrite.data   = serverExportKey;
-               finalClientIV.data      = clientExportIV;
-               finalServerIV.data      = serverExportIV;
-               finalClientWrite.length = 16;
-               finalServerWrite.length = 16;
-               /* these can be zero */
-               finalClientIV.length    = ctx->selectedCipherSpec->cipher->ivSize;
-               finalServerIV.length    = ctx->selectedCipherSpec->cipher->ivSize;
-
-               assert(ctx->sslTslCalls != NULL);
-               err = ctx->sslTslCalls->generateExportKeyAndIv(ctx, clientWrite, serverWrite,
-                       finalClientWrite, finalServerWrite, finalClientIV, finalServerIV);
-               if(err) {
-                       goto fail;
-               }
-        if ((err = ctx->selectedCipherSpec->cipher->initialize(clientExportKey, 
-                               clientExportIV, clientPending, ctx)) != 0)
-            goto fail;
-        if ((err = ctx->selectedCipherSpec->cipher->initialize(serverExportKey, 
-                               serverExportIV, serverPending, ctx)) != 0)
-            goto fail;
-    }
-    
-       /* Ciphers are ready for use */
-    ctx->writePending.ready = 1;
-    ctx->readPending.ready = 1;
-    
-       /* Ciphers get swapped by sending or receiving a change cipher spec message */
-    
-    err = noErr;
-fail:
-    SSLFreeBuffer(key, ctx);
-    return err;
-}
-