sslKeyExchange.cpp [plain text]
#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
#if APPLE_DH
#pragma mark -
#pragma mark *** local D-H parameter generator ***
class ServerDhParams
{
public:
ServerDhParams();
~ServerDhParams();
const SSLBuffer &prime() { return mPrime; }
const SSLBuffer &generator() { return mGenerator; }
const SSLBuffer ¶mBlock() { return mParamBlock; }
private:
SSLBuffer mPrime;
SSLBuffer mGenerator;
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; CSSM_TP_HANDLE tpHand; 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, NULL, NULL, NULL, &cParams, &ccHandle);
if(crtn) {
stPrintCdsaError("ServerDhParams CSSM_CSP_CreateKeyGenContext", crtn);
MacOSError::throwMe(errSSLCrypto);
}
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);
}
static ModuleNexus<ServerDhParams> serverDhParams;
#endif
#pragma mark -
#pragma mark *** RSA key exchange ***
#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;
err = sslGetPubKeyBits(ctx,
*key,
ctx->encryptKeyCsp,
&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);
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;
}
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;
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;
switch(ctx->selectedCipherSpec->keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
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;
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
{
err = SSLGenServerDHParamsAndKey(ctx);
if(err) {
return err;
}
UInt32 len = ctx->dhParamsPrime.length +
ctx->dhParamsGenerator.length +
ctx->dhExchangePublic.length + 6 ;
err = SSLAllocBuffer(exchangeParams, len, ctx);
if(err) {
goto fail;
}
err = SSLEncodeDHKeyParams(ctx, exchangeParams.data);
break;
}
#endif
default:
assert(0);
return errSSLInternal;
}
if(err) {
goto fail;
}
clientRandom.data = ctx->clientRandom;
clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
serverRandom.data = ctx->serverRandom;
serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
if(isRsa) {
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 {
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;
err = sslGetMaxSigSize(ctx->signingPrivKey, maxSigLen);
if(err) {
goto fail;
}
err = SSLAllocBuffer(signature, maxSigLen, ctx);
if(err) {
goto fail;
}
err = sslRawSign(ctx,
ctx->signingPrivKey,
ctx->signingKeyCsp,
dataToSign, dataToSignLen,
signature.data,
maxSigLen,
&actSigLen);
if(err) {
goto fail;
}
assert(actSigLen <= maxSigLen);
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;
}
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;
}
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;
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
err = SSLDecodeDHKeyParams(ctx, charPtr, message.length);
if(err) {
return err;
}
break;
#endif
default:
assert(0);
return errSSLInternal;
}
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) {
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 {
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,
dataToSignLen,
signature,
signatureLen);
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
"returned %d\n", (int)err);
goto fail;
}
switch(ctx->selectedCipherSpec->keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
{
SSLBuffer modBuf;
SSLBuffer expBuf;
sslFreeKey(ctx->peerPubKeyCsp,
&ctx->peerPubKey,
NULL);
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;
default:
assert(0);
}
fail:
SSLFreeBuffer(signedHashes, ctx);
SSLFreeBuffer(hashCtx, ctx);
return err;
}
static OSStatus
SSLDecodeRSAKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
{ OSStatus err;
UInt32 outputLen, localKeyModulusLen;
CSSM_KEY_PTR *key;
SSLProtocolVersion version;
Boolean useEncryptKey = false;
UInt8 *src = NULL;
CSSM_CSP_HANDLE cspHand;
assert(ctx->protocolSide == SSL_ServerSide);
#if SSL_SERVER_KEYEXCH_HACK
if((ctx->selectedCipherSpec->keyExchangeMethod == SSL_RSA_EXPORT) &&
(ctx->encryptPrivKey != NULL)) {
useEncryptKey = true;
}
#else
if (ctx->encryptPrivKey) {
useEncryptKey = true;
}
#endif
if (useEncryptKey) {
key = &ctx->encryptPrivKey;
cspHand = ctx->encryptKeyCsp;
}
else {
key = &ctx->signingPrivKey;
cspHand = ctx->signingKeyCsp;
}
localKeyModulusLen = sslKeyLengthInBytes(*key);
if (keyExchange.length == localKeyModulusLen) {
src = keyExchange.data;
}
else if((keyExchange.length == (localKeyModulusLen + 2)) &&
(ctx->negProtocolVersion >= TLS_Version_1_0)) {
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;
}
err = sslRsaDecrypt(ctx,
*key,
cspHand,
src,
localKeyModulusLen, ctx->preMasterSecret.data,
SSL_RSA_PREMASTER_SECRET_SIZE, &outputLen);
if(err != noErr) {
sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: RSA decrypt fail");
}
else if(outputLen != SSL_RSA_PREMASTER_SECRET_SIZE) {
sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: premaster secret size error");
err = errSSLProtocol; }
if(err == noErr) {
version = (SSLProtocolVersion)SSLDecodeInt(ctx->preMasterSecret.data, 2);
if((version != ctx->negProtocolVersion) &&
(version != ctx->clientReqProtocol)) {
sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: version error");
err = errSSLProtocol;
}
}
if(err != noErr) {
SSLEncodeInt(ctx->preMasterSecret.data, ctx->negProtocolVersion, 2);
SSLBuffer tmpBuf;
tmpBuf.data = ctx->preMasterSecret.data + 2;
tmpBuf.length = SSL_RSA_PREMASTER_SECRET_SIZE - 2;
sslRand(ctx, &tmpBuf);
}
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;
SSLEncodeInt(keyExchange.contents.data + 1, bufLen - 4, 3);
if(encodeLen) {
SSLEncodeInt(keyExchange.contents.data + 4,
peerKeyModulusLen, 2);
}
err = sslRsaEncrypt(ctx,
ctx->peerPubKey,
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 ***
static OSStatus
SSLGenServerDHParamsAndKey(
SSLContext *ctx)
{
OSStatus ortn;
assert(ctx->protocolSide == SSL_ServerSide);
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;
}
}
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;
}
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;
}
static OSStatus
SSLDecodeDHKeyParams(
SSLContext *ctx,
UInt8 *&charPtr, UInt32 length)
{
OSStatus err = noErr;
assert(ctx->protocolSide == SSL_ClientSide);
UInt8 *endCp = charPtr + length;
SSLFreeBuffer(ctx->dhParamsPrime, ctx);
SSLFreeBuffer(ctx->dhParamsGenerator, ctx);
SSLFreeBuffer(ctx->dhPeerPublic, ctx);
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;
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;
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;
}
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;
}
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;
}
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);
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);
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) {
assert(0);
return errSSLInternal;
}
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); ortn = SSLAllocBuffer(ctx->dhPeerPublic, publicLen, ctx);
if(ortn) {
return ortn;
}
memmove(ctx->dhPeerPublic.data, charPtr, publicLen);
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
#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
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;
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;
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;
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;
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);
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;
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;
}
ctx->writePending.ready = 1;
ctx->readPending.ready = 1;
err = noErr;
fail:
SSLFreeBuffer(key, ctx);
return err;
}