+++ /dev/null
-/*
- * 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 ¶mBlock() { 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;
-}
-