#include "ssl.h"
#include "sslContext.h"
#include "sslHandshake.h"
#include "sslMemory.h"
#include "sslDebug.h"
#include "sslUtils.h"
#include "sslCrypto.h"
#include "sslDigests.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <corecrypto/ccdh_gp.h>
#ifdef USE_CDSA_CRYPTO
#include <Security/cssmapi.h>
#include <Security/SecKeyPriv.h>
#include "ModuleAttacher.h"
#else
#include <Security/SecRSAKey.h>
#include <AssertMacros.h>
#include <Security/oidsalg.h>
#if APPLE_DH
static OSStatus SSLGenServerDHParamsAndKey(SSLContext *ctx);
static size_t SSLEncodedDHKeyParamsLen(SSLContext *ctx);
static OSStatus SSLEncodeDHKeyParams(SSLContext *ctx, uint8_t *charPtr);
#endif
#endif
#include <pthread.h>
#pragma mark -
#pragma mark Forward Static Declarations
#if APPLE_DH
#if USE_CDSA_CRYPTO
static OSStatus SSLGenServerDHParamsAndKey(SSLContext *ctx);
static OSStatus SSLEncodeDHKeyParams(SSLContext *ctx, uint8_t *charPtr);
#endif
static OSStatus SSLDecodeDHKeyParams(SSLContext *ctx, uint8_t **charPtr,
size_t length);
#endif
static OSStatus SSLDecodeECDHKeyParams(SSLContext *ctx, uint8_t **charPtr,
size_t length);
#define DH_PARAM_DUMP 0
#if DH_PARAM_DUMP
static void dumpBuf(const char *name, SSLBuffer *buf)
{
printf("%s:\n", name);
uint8_t *cp = buf->data;
uint8_t *endCp = cp + buf->length;
do {
unsigned i;
for(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 Diffie-Hellman Parameter Generator
struct ServerDhParams
{
SSLBuffer prime;
SSLBuffer generator;
SSLBuffer paramBlock;
};
#endif
#pragma mark -
#pragma mark RSA Key Exchange
#define RSA_CLIENT_KEY_ADD_LENGTH 1
static OSStatus
SSLEncodeRSAKeyParams(SSLBuffer *keyParams, SSLPubKey *key, SSLContext *ctx)
{
#if 0
SSLBuffer modulus, exponent;
uint8_t *charPtr;
#ifdef USE_CDSA_CRYPTO
if(err = attachToCsp(ctx)) {
return err;
}
assert((*key)->KeyHeader.BlobType == CSSM_KEYBLOB_RAW);
#endif
err = sslGetPubKeyBits(ctx,
key,
&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;
#else
CFDataRef modulus = SecKeyCopyModulus(SECKEYREF(key));
if (!modulus) {
sslErrorLog("SSLEncodeRSAKeyParams: SecKeyCopyModulus failed\n");
return errSSLCrypto;
}
CFDataRef exponent = SecKeyCopyExponent(SECKEYREF(key));
if (!exponent) {
sslErrorLog("SSLEncodeRSAKeyParams: SecKeyCopyExponent failed\n");
CFRelease(modulus);
return errSSLCrypto;
}
CFIndex modulusLength = CFDataGetLength(modulus);
CFIndex exponentLength = CFDataGetLength(exponent);
sslDebugLog("SSLEncodeRSAKeyParams: modulus len=%ld, exponent len=%ld\n",
modulusLength, exponentLength);
OSStatus err;
if ((err = SSLAllocBuffer(keyParams,
modulusLength + exponentLength + 4, ctx)) != 0) {
return err;
}
uint8_t *charPtr = keyParams->data;
charPtr = SSLEncodeSize(charPtr, modulusLength, 2);
memcpy(charPtr, CFDataGetBytePtr(modulus), modulusLength);
charPtr += modulusLength;
charPtr = SSLEncodeSize(charPtr, exponentLength, 2);
memcpy(charPtr, CFDataGetBytePtr(exponent), exponentLength);
CFRelease(modulus);
CFRelease(exponent);
return noErr;
#endif
}
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);
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
SSLSignServerKeyExchangeTls12(SSLContext *ctx, SSLSignatureAndHashAlgorithm sigAlg, SSLBuffer exchangeParams, SSLBuffer signature, size_t *actSigLen)
{
OSStatus err;
SSLBuffer hashOut, hashCtx, clientRandom, serverRandom;
uint8_t hashes[SSL_MAX_DIGEST_LEN];
SSLBuffer signedHashes;
uint8_t *dataToSign;
size_t dataToSignLen;
const HashReference *hashRef;
SecAsn1AlgId algId;
signedHashes.data = 0;
hashCtx.data = 0;
clientRandom.data = ctx->clientRandom;
clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
serverRandom.data = ctx->serverRandom;
serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
switch (sigAlg.hash) {
case SSL_HashAlgorithmSHA1:
hashRef = &SSLHashSHA1;
algId.algorithm = CSSMOID_SHA1WithRSA;
break;
case SSL_HashAlgorithmSHA256:
hashRef = &SSLHashSHA256;
algId.algorithm = CSSMOID_SHA256WithRSA;
break;
case SSL_HashAlgorithmSHA384:
hashRef = &SSLHashSHA384;
algId.algorithm = CSSMOID_SHA384WithRSA;
break;
default:
sslErrorLog("SSLVerifySignedServerKeyExchangeTls12: unsupported hash %d\n", sigAlg.hash);
return errSSLProtocol;
}
dataToSign = hashes;
dataToSignLen = hashRef->digestSize;
hashOut.data = hashes;
hashOut.length = hashRef->digestSize;
if ((err = ReadyHash(hashRef, &hashCtx, ctx)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &clientRandom)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &exchangeParams)) != 0)
goto fail;
if ((err = hashRef->final(&hashCtx, &hashOut)) != 0)
goto fail;
if(sigAlg.signature==SSL_SignatureAlgorithmRSA) {
err = sslRsaSign(ctx,
ctx->signingPrivKeyRef,
&algId,
dataToSign,
dataToSignLen,
signature.data,
signature.length,
actSigLen);
} else {
err = sslRawSign(ctx,
ctx->signingPrivKeyRef,
dataToSign, dataToSignLen,
signature.data,
signature.length,
actSigLen);
}
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchangeTls12: sslRawVerify "
"returned %d\n", (int)err);
goto fail;
}
fail:
SSLFreeBuffer(&signedHashes, ctx);
SSLFreeBuffer(&hashCtx, ctx);
return err;
}
static OSStatus
SSLSignServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer exchangeParams, SSLBuffer signature, size_t *actSigLen)
{
OSStatus err;
uint8_t hashes[SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN];
SSLBuffer clientRandom,serverRandom,hashCtx, hash;
uint8_t *dataToSign;
size_t dataToSignLen;
hashCtx.data = 0;
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 = sslRawSign(ctx,
ctx->signingPrivKeyRef,
dataToSign, dataToSignLen,
signature.data,
signature.length,
actSigLen);
if(err) {
goto fail;
}
fail:
SSLFreeBuffer(&hashCtx, ctx);
return err;
}
static
OSStatus FindSigAlg(SSLContext *ctx,
SSLSignatureAndHashAlgorithm *alg)
{
unsigned i;
assert(ctx->protocolSide == kSSLServerSide);
assert(ctx->negProtocolVersion >= TLS_Version_1_2);
assert(!ctx->isDTLS);
if((ctx->numClientSigAlgs==0) ||(ctx->clientSigAlgs==NULL))
return errSSLInternal;
for(i=0; i<ctx->numClientSigAlgs; i++) {
alg->hash = ctx->clientSigAlgs[i].hash;
alg->signature = ctx->clientSigAlgs[i].signature;
if(ctx->clientSigAlgs[i].signature != SSL_SignatureAlgorithmRSA)
continue;
if((alg->hash==SSL_HashAlgorithmSHA1) || (alg->hash==SSL_HashAlgorithmSHA256)) {
return noErr;
}
}
return errSSLProtocol;
}
static OSStatus
SSLEncodeSignedServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx)
{ OSStatus err;
uint8_t *charPtr;
size_t outputLen;
bool isRsa = true;
size_t maxSigLen;
size_t actSigLen;
SSLBuffer signature;
int head = 4;
SSLBuffer exchangeParams;
assert(ctx->protocolSide == kSSLServerSide);
assert(ctx->signingPubKey != NULL);
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
exchangeParams.data = 0;
signature.data = 0;
#if ENABLE_DTLS
if(ctx->negProtocolVersion == DTLS_Version_1_0) {
head+=8;
}
#endif
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;
}
size_t len = SSLEncodedDHKeyParamsLen(ctx);
err = SSLAllocBuffer(&exchangeParams, len, ctx);
if(err) {
goto fail;
}
err = SSLEncodeDHKeyParams(ctx, exchangeParams.data);
break;
}
#endif
default:
assert(0);
return errSSLInternal;
}
SSLSignatureAndHashAlgorithm sigAlg;
err = sslGetMaxSigSize(ctx->signingPrivKeyRef, &maxSigLen);
if(err) {
goto fail;
}
err = SSLAllocBuffer(&signature, maxSigLen, ctx);
if(err) {
goto fail;
}
outputLen = exchangeParams.length + 2;
if (sslVersionIsLikeTls12(ctx))
{
err=FindSigAlg(ctx, &sigAlg);
if(err)
goto fail;
outputLen += 2;
err = SSLSignServerKeyExchangeTls12(ctx, sigAlg, exchangeParams,
signature, &actSigLen);
} else {
err = SSLSignServerKeyExchange(ctx, isRsa, exchangeParams,
signature, &actSigLen);
}
if(err)
goto fail;
assert(actSigLen <= maxSigLen);
outputLen += actSigLen;
keyExch->protocolVersion = ctx->negProtocolVersion;
keyExch->contentType = SSL_RecordTypeHandshake;
if ((err = SSLAllocBuffer(&keyExch->contents, outputLen+head, ctx)) != 0)
goto fail;
charPtr = SSLEncodeHandshakeHeader(ctx, keyExch, SSL_HdskServerKeyExchange, outputLen);
memcpy(charPtr, exchangeParams.data, exchangeParams.length);
charPtr += exchangeParams.length;
if (sslVersionIsLikeTls12(ctx))
{
*charPtr++=sigAlg.hash;
*charPtr++=sigAlg.signature;
}
charPtr = SSLEncodeInt(charPtr, actSigLen, 2);
memcpy(charPtr, signature.data, actSigLen);
assert((charPtr + actSigLen) ==
(keyExch->contents.data + keyExch->contents.length));
err = noErr;
fail:
SSLFreeBuffer(&exchangeParams, ctx);
SSLFreeBuffer(&signature, ctx);
return err;
}
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
OSStatus err;
SSLBuffer hashOut, hashCtx, clientRandom, serverRandom;
uint8_t hashes[SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN];
SSLBuffer signedHashes;
uint8_t *dataToSign;
size_t dataToSignLen;
signedHashes.data = 0;
hashCtx.data = 0;
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,
dataToSign,
dataToSignLen,
signature,
signatureLen);
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
"returned %d\n", (int)err);
goto fail;
}
fail:
SSLFreeBuffer(&signedHashes, ctx);
SSLFreeBuffer(&hashCtx, ctx);
return err;
}
static OSStatus
SSLVerifySignedServerKeyExchangeTls12(SSLContext *ctx, SSLSignatureAndHashAlgorithm sigAlg, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
OSStatus err;
SSLBuffer hashOut, hashCtx, clientRandom, serverRandom;
uint8_t hashes[SSL_MAX_DIGEST_LEN];
SSLBuffer signedHashes;
uint8_t *dataToSign;
size_t dataToSignLen;
const HashReference *hashRef;
SecAsn1AlgId algId;
signedHashes.data = 0;
hashCtx.data = 0;
clientRandom.data = ctx->clientRandom;
clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
serverRandom.data = ctx->serverRandom;
serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
switch (sigAlg.hash) {
case SSL_HashAlgorithmSHA1:
hashRef = &SSLHashSHA1;
algId.algorithm = CSSMOID_SHA1WithRSA;
break;
case SSL_HashAlgorithmSHA256:
hashRef = &SSLHashSHA256;
algId.algorithm = CSSMOID_SHA256WithRSA;
break;
case SSL_HashAlgorithmSHA384:
hashRef = &SSLHashSHA384;
algId.algorithm = CSSMOID_SHA384WithRSA;
break;
default:
sslErrorLog("SSLVerifySignedServerKeyExchangeTls12: unsupported hash %d\n", sigAlg.hash);
return errSSLProtocol;
}
dataToSign = hashes;
dataToSignLen = hashRef->digestSize;
hashOut.data = hashes;
hashOut.length = hashRef->digestSize;
if ((err = ReadyHash(hashRef, &hashCtx, ctx)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &clientRandom)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &signedParams)) != 0)
goto fail;
if ((err = hashRef->final(&hashCtx, &hashOut)) != 0)
goto fail;
if(sigAlg.signature==SSL_SignatureAlgorithmRSA) {
err = sslRsaVerify(ctx,
ctx->peerPubKey,
&algId,
dataToSign,
dataToSignLen,
signature,
signatureLen);
} else {
err = sslRawVerify(ctx,
ctx->peerPubKey,
dataToSign,
dataToSignLen,
signature,
signatureLen);
}
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchangeTls12: sslRawVerify "
"returned %d\n", (int)err);
goto fail;
}
fail:
SSLFreeBuffer(&signedHashes, ctx);
SSLFreeBuffer(&hashCtx, ctx);
return err;
}
static OSStatus
SSLDecodeSignedServerKeyExchange(SSLBuffer message, SSLContext *ctx)
{
OSStatus err;
UInt16 modulusLen = 0, exponentLen = 0, signatureLen;
uint8_t *modulus = NULL, *exponent = NULL, *signature;
bool isRsa = true;
assert(ctx->protocolSide == kSSLClientSide);
if (message.length < 2) {
sslErrorLog("SSLDecodeSignedServerKeyExchange: msg len error 1\n");
return errSSLProtocol;
}
uint8_t *charPtr = message.data;
uint8_t *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
case SSL_ECDHE_ECDSA:
isRsa = false;
case SSL_ECDHE_RSA:
err = SSLDecodeECDHKeyParams(ctx, &charPtr, message.length);
if(err) {
return err;
}
break;
default:
assert(0);
return errSSLInternal;
}
SSLBuffer signedParams;
signedParams.data = message.data;
signedParams.length = charPtr - message.data;
SSLSignatureAndHashAlgorithm sigAlg;
if (sslVersionIsLikeTls12(ctx)) {
if((charPtr + 2) > endCp) {
sslErrorLog("signedServerKeyExchange: msg len error 499\n");
return errSSLProtocol;
}
sigAlg.hash = *charPtr++;
sigAlg.signature = *charPtr++;
}
signatureLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
if((charPtr + signatureLen) != endCp) {
sslErrorLog("signedServerKeyExchange: msg len error 4\n");
return errSSLProtocol;
}
signature = charPtr;
if (sslVersionIsLikeTls12(ctx))
{
err = SSLVerifySignedServerKeyExchangeTls12(ctx, sigAlg, signedParams,
signature, signatureLen);
} else {
err = SSLVerifySignedServerKeyExchange(ctx, isRsa, signedParams,
signature, signatureLen);
}
if(err)
goto fail;
switch(ctx->selectedCipherSpec.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
{
SSLBuffer modBuf;
SSLBuffer expBuf;
sslFreePubKey(&ctx->peerPubKey);
modBuf.data = modulus;
modBuf.length = modulusLen;
expBuf.data = exponent;
expBuf.length = exponentLen;
err = sslGetPubKeyFromBits(ctx,
&modBuf,
&expBuf,
&ctx->peerPubKey);
break;
}
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
case SSL_DHE_DSS:
case SSL_DHE_DSS_EXPORT:
case SSL_ECDHE_ECDSA:
case SSL_ECDHE_RSA:
break;
default:
assert(0);
}
fail:
return err;
}
static OSStatus
SSLDecodeRSAKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
{ OSStatus err;
size_t outputLen, localKeyModulusLen;
SSLProtocolVersion version;
Boolean useEncryptKey = false;
uint8_t *src = NULL;
SSLPrivKey *keyRef = NULL;
assert(ctx->protocolSide == kSSLServerSide);
#if SSL_SERVER_KEYEXCH_HACK
if((ctx->selectedCipherSpec.keyExchangeMethod == SSL_RSA_EXPORT) &&
(ctx->encryptPrivKey != NULL)) {
useEncryptKey = true;
}
#else
if (ctx->encryptPrivKeyRef) {
useEncryptKey = true;
}
#endif
if (useEncryptKey) {
keyRef = ctx->encryptPrivKeyRef;
}
else {
keyRef = ctx->signingPrivKeyRef;
}
localKeyModulusLen = sslPrivKeyLengthInBytes(keyRef);
if (localKeyModulusLen == 0) {
sslErrorLog("SSLDecodeRSAKeyExchange: private key modulus is 0\n");
return errSSLCrypto;
}
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,
keyRef,
#if USE_CDSA_CRYPTO
CSSM_PADDING_PKCS1,
#else
kSecPaddingPKCS1,
#endif
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;
size_t outputLen, peerKeyModulusLen;
size_t bufLen;
uint8_t *dst;
bool encodeLen = false;
uint8_t *p;
int head;
size_t msglen;
assert(ctx->protocolSide == kSSLClientSide);
if ((err = SSLEncodeRSAPremasterSecret(ctx)) != 0)
return err;
keyExchange->contentType = SSL_RecordTypeHandshake;
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
keyExchange->protocolVersion = ctx->negProtocolVersion;
peerKeyModulusLen = sslPubKeyLengthInBytes(ctx->peerPubKey);
if (peerKeyModulusLen == 0) {
sslErrorLog("SSLEncodeRSAKeyExchange: peer key modulus is 0\n");
}
#if SSL_DEBUG
sslDebugLog("SSLEncodeRSAKeyExchange: peer key modulus length = %lu\n", peerKeyModulusLen);
#endif
msglen = peerKeyModulusLen;
#if RSA_CLIENT_KEY_ADD_LENGTH
if(ctx->negProtocolVersion >= TLS_Version_1_0) {
msglen += 2;
encodeLen = true;
}
#endif
head = SSLHandshakeHeaderSize(keyExchange);
bufLen = msglen + head;
if ((err = SSLAllocBuffer(&keyExchange->contents,
bufLen,ctx)) != 0)
{
return err;
}
dst = keyExchange->contents.data + head;
if(encodeLen) {
dst += 2;
}
p = keyExchange->contents.data;
p = SSLEncodeHandshakeHeader(ctx, keyExchange, SSL_HdskClientKeyExchange, msglen);
if(encodeLen) {
SSLEncodeSize(keyExchange->contents.data + head,
peerKeyModulusLen, 2);
}
err = sslRsaEncrypt(ctx,
ctx->peerPubKey,
#if USE_CDSA_CRYPTO
CSSM_PADDING_PKCS1,
#else
kSecPaddingPKCS1,
#endif
ctx->preMasterSecret.data,
SSL_RSA_PREMASTER_SECRET_SIZE,
dst,
peerKeyModulusLen,
&outputLen);
if(err) {
sslErrorLog("SSLEncodeRSAKeyExchange: error %d\n", err);
return err;
}
assert(outputLen == (encodeLen ? msglen - 2 : msglen));
return noErr;
}
#if APPLE_DH
#pragma mark -
#pragma mark Diffie-Hellman Key Exchange
static OSStatus
SSLGenServerDHParamsAndKey(
SSLContext *ctx)
{
OSStatus ortn;
assert(ctx->protocolSide == kSSLServerSide);
if(ctx->dhParamsEncoded.data == NULL) {
ccdh_const_gp_t gp = ccdh_gp_rfc5114_MODP_2048_256();
cc_size n = ccdh_gp_n(gp);
size_t s = ccdh_gp_prime_size(gp);
uint8_t p[s];
uint8_t g[s];
ccn_write_uint(n, ccdh_gp_prime(gp), s, p);
ccn_write_uint(n, ccdh_gp_g(gp), s, g);
const SSLBuffer prime = {
.data = p,
.length = s,
};
const SSLBuffer generator = {
.data = g,
.length = s,
};
ortn=sslEncodeDhParams(&ctx->dhParamsEncoded,
&prime,
&generator);
if(ortn)
return ortn;
}
#if USE_CDSA_CRYPTO
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);
#else
if (!ctx->secDHContext) {
ortn = sslDhCreateKey(ctx);
if(ortn)
return ortn;
}
return sslDhGenerateKeyPair(ctx);
#endif
return noErr;
}
static size_t
SSLEncodedDHKeyParamsLen(SSLContext *ctx)
{
SSLBuffer prime;
SSLBuffer generator;
sslDecodeDhParams(&ctx->dhParamsEncoded, &prime, &generator);
return (2+prime.length+2+generator.length+2+ctx->dhExchangePublic.length);
}
static OSStatus
SSLEncodeDHKeyParams(
SSLContext *ctx,
uint8_t *charPtr)
{
assert(ctx->protocolSide == kSSLServerSide);
assert(ctx->dhParamsEncoded.data != NULL);
assert(ctx->dhExchangePublic.data != NULL);
SSLBuffer prime;
SSLBuffer generator;
sslDecodeDhParams(&ctx->dhParamsEncoded, &prime, &generator);
charPtr = SSLEncodeInt(charPtr, prime.length, 2);
memcpy(charPtr, prime.data, prime.length);
charPtr += prime.length;
charPtr = SSLEncodeInt(charPtr, generator.length, 2);
memcpy(charPtr, generator.data,
generator.length);
charPtr += generator.length;
charPtr = SSLEncodeInt(charPtr, ctx->dhExchangePublic.length, 2);
memcpy(charPtr, ctx->dhExchangePublic.data,
ctx->dhExchangePublic.length);
dumpBuf("server prime", &prime);
dumpBuf("server generator", &generator);
dumpBuf("server pub key", &ctx->dhExchangePublic);
return noErr;
}
static OSStatus
SSLDecodeDHKeyParams(
SSLContext *ctx,
uint8_t **charPtr, size_t length)
{
OSStatus err = noErr;
SSLBuffer prime;
SSLBuffer generator;
assert(ctx->protocolSide == kSSLClientSide);
uint8_t *endCp = *charPtr + length;
SSLFreeBuffer(&ctx->dhPeerPublic, ctx);
UInt32 len = SSLDecodeInt(*charPtr, 2);
(*charPtr) += 2;
if((*charPtr + len) > endCp) {
return errSSLProtocol;
}
prime.data = *charPtr;
prime.length = len;
(*charPtr) += len;
len = SSLDecodeInt(*charPtr, 2);
(*charPtr) += 2;
if((*charPtr + len) > endCp) {
return errSSLProtocol;
}
generator.data = *charPtr;
generator.length = len;
(*charPtr) += len;
sslEncodeDhParams(&ctx->dhParamsEncoded, &prime, &generator);
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;
#if USE_CDSA_CRYPTO
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);
#else
ortn=errSSLProtocol;
require(ctx->dhParamsEncoded.data, out);
require_noerr(ortn = sslDhCreateKey(ctx), out);
require_noerr(ortn = sslDhGenerateKeyPair(ctx), out);
require_noerr(ortn = sslDhKeyExchange(ctx), out);
out:
#endif
return ortn;
}
static OSStatus
SSLEncodeDHanonServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx)
{
OSStatus ortn = noErr;
int head;
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
assert(ctx->protocolSide == kSSLServerSide);
ortn = SSLGenServerDHParamsAndKey(ctx);
if(ortn) {
return ortn;
}
size_t length = SSLEncodedDHKeyParamsLen(ctx);
keyExch->protocolVersion = ctx->negProtocolVersion;
keyExch->contentType = SSL_RecordTypeHandshake;
head = SSLHandshakeHeaderSize(keyExch);
if ((ortn = SSLAllocBuffer(&keyExch->contents, length+head, ctx)) != 0)
return ortn;
uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExch, SSL_HdskServerKeyExchange, length);
return SSLEncodeDHKeyParams(ctx, charPtr);
}
static OSStatus
SSLDecodeDHanonServerKeyExchange(SSLBuffer message, SSLContext *ctx)
{
OSStatus err = noErr;
assert(ctx->protocolSide == kSSLClientSide);
if (message.length < 6) {
sslErrorLog("SSLDecodeDHanonServerKeyExchange error: msg len %u\n",
(unsigned)message.length);
return errSSLProtocol;
}
uint8_t *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 == kSSLServerSide);
if(ctx->dhParamsEncoded.data == NULL) {
assert(0);
return errSSLInternal;
}
uint8_t *charPtr = keyExchange.data;
publicLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
SSLFreeBuffer(&ctx->dhPeerPublic, ctx); ortn = SSLAllocBuffer(&ctx->dhPeerPublic, publicLen, ctx);
if(ortn) {
return ortn;
}
memmove(ctx->dhPeerPublic.data, charPtr, publicLen);
SSLFreeBuffer(&ctx->preMasterSecret, ctx);
#if USE_CDSA_CRYPTO
ortn = sslDhKeyExchange(ctx, ctx->dhParamsPrime.length * 8,
&ctx->preMasterSecret);
#else
ortn = sslDhKeyExchange(ctx);
#endif
dumpBuf("server peer pub", &ctx->dhPeerPublic);
dumpBuf("server premaster", &ctx->preMasterSecret);
return ortn;
}
static OSStatus
SSLEncodeDHClientKeyExchange(SSLRecord *keyExchange, SSLContext *ctx)
{ OSStatus err;
size_t outputLen;
int head;
assert(ctx->protocolSide == kSSLClientSide);
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
keyExchange->contentType = SSL_RecordTypeHandshake;
keyExchange->protocolVersion = ctx->negProtocolVersion;
if ((err = SSLGenClientDHKeyAndExchange(ctx)) != 0)
return err;
outputLen = ctx->dhExchangePublic.length + 2;
head = SSLHandshakeHeaderSize(keyExchange);
if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head,ctx)) != 0)
return err;
uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExchange, SSL_HdskClientKeyExchange, outputLen);
charPtr = SSLEncodeSize(charPtr, ctx->dhExchangePublic.length, 2);
memcpy(charPtr, ctx->dhExchangePublic.data, ctx->dhExchangePublic.length);
dumpBuf("client pub key", &ctx->dhExchangePublic);
dumpBuf("client premaster", &ctx->preMasterSecret);
return noErr;
}
#endif
#pragma mark -
#pragma mark ECDSA Key Exchange
static OSStatus
SSLGenClientECDHKeyAndExchange(SSLContext *ctx)
{
OSStatus ortn;
assert(ctx->protocolSide == kSSLClientSide);
switch(ctx->selectedCipherSpec.keyExchangeMethod) {
case SSL_ECDHE_ECDSA:
case SSL_ECDHE_RSA:
if(ctx->ecdhPeerPublic.data == NULL) {
sslErrorLog("SSLGenClientECDHKeyAndExchange: incomplete server params\n");
return errSSLProtocol;
}
break;
case SSL_ECDH_ECDSA:
case SSL_ECDH_RSA:
{
if(ctx->peerPubKey == NULL) {
sslErrorLog("SSLGenClientECDHKeyAndExchange: no peer key\n");
return errSSLInternal;
}
ortn = sslEcdsaPeerCurve(ctx->peerPubKey, &ctx->ecdhPeerCurve);
if(ortn) {
return ortn;
}
sslEcdsaDebug("SSLGenClientECDHKeyAndExchange: derived peerCurve %u",
(unsigned)ctx->ecdhPeerCurve);
break;
}
default:
assert(0);
return errSSLInternal;
}
if((ctx->negAuthType == SSLClientAuth_RSAFixedECDH) ||
(ctx->negAuthType == SSLClientAuth_ECDSAFixedECDH)) {
assert(ctx->signingPrivKeyRef != NULL);
#if USE_CDSA_CRYPTO
sslFreeKey(ctx->cspHand, &ctx->ecdhPrivate, NULL);
SSLFreeBuffer(&ctx->ecdhExchangePublic, ctx);
ortn = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, (const CSSM_KEY **)&ctx->ecdhPrivate);
if(ortn) {
return ortn;
}
ortn = SecKeyGetCSPHandle(ctx->signingPrivKeyRef, &ctx->ecdhPrivCspHand);
if(ortn) {
sslErrorLog("SSLGenClientECDHKeyAndExchange: SecKeyGetCSPHandle err %d\n",
(int)ortn);
}
#endif
sslEcdsaDebug("+++ Extracted ECDH private key");
}
else {
ortn = sslEcdhGenerateKeyPair(ctx, ctx->ecdhPeerCurve);
if(ortn) {
return ortn;
}
#if USE_CDSA_CRYPTO
sslEcdsaDebug("+++ Generated %u bit (%u byte) ECDH key pair",
(unsigned)ctx->ecdhPrivate->KeyHeader.LogicalKeySizeInBits,
(unsigned)((ctx->ecdhPrivate->KeyHeader.LogicalKeySizeInBits + 7) / 8));
#endif
}
ortn = sslEcdhKeyExchange(ctx, &ctx->preMasterSecret);
if(ortn) {
return ortn;
}
return noErr;
}
static OSStatus
SSLDecodeECDHKeyParams(
SSLContext *ctx,
uint8_t **charPtr, size_t length)
{
OSStatus err = noErr;
sslEcdsaDebug("+++ Decoding ECDH Server Key Exchange");
assert(ctx->protocolSide == kSSLClientSide);
uint8_t *endCp = *charPtr + length;
SSLFreeBuffer(&ctx->ecdhPeerPublic, ctx);
uint8_t curveType = **charPtr;
if(curveType != SSL_CurveTypeNamed) {
sslEcdsaDebug("+++ SSLDecodeECDHKeyParams: Bad curveType (%u)\n", (unsigned)curveType);
return errSSLProtocol;
}
(*charPtr)++;
if(*charPtr > endCp) {
return errSSLProtocol;
}
ctx->ecdhPeerCurve = SSLDecodeInt(*charPtr, 2);
(*charPtr) += 2;
if(*charPtr > endCp) {
return errSSLProtocol;
}
switch(ctx->ecdhPeerCurve) {
case SSL_Curve_secp256r1:
case SSL_Curve_secp384r1:
case SSL_Curve_secp521r1:
break;
default:
sslEcdsaDebug("+++ SSLDecodeECDHKeyParams: Bad curve (%u)\n",
(unsigned)ctx->ecdhPeerCurve);
return errSSLProtocol;
}
sslEcdsaDebug("+++ SSLDecodeECDHKeyParams: ecdhPeerCurve %u",
(unsigned)ctx->ecdhPeerCurve);
UInt32 len = SSLDecodeInt(*charPtr, 1);
(*charPtr)++;
if((*charPtr + len) > endCp) {
return errSSLProtocol;
}
err = SSLAllocBuffer(&ctx->ecdhPeerPublic, len, ctx);
if(err) {
return err;
}
memmove(ctx->ecdhPeerPublic.data, *charPtr, len);
(*charPtr) += len;
dumpBuf("client peer pub", &ctx->ecdhPeerPublic);
return err;
}
static OSStatus
SSLEncodeECDHClientKeyExchange(SSLRecord *keyExchange, SSLContext *ctx)
{ OSStatus err;
size_t outputLen;
int head;
assert(ctx->protocolSide == kSSLClientSide);
if ((err = SSLGenClientECDHKeyAndExchange(ctx)) != 0)
return err;
bool emptyMsg = false;
switch(ctx->negAuthType) {
case SSLClientAuth_RSAFixedECDH:
case SSLClientAuth_ECDSAFixedECDH:
emptyMsg = true;
break;
default:
break;
}
if(emptyMsg) {
outputLen = 0;
}
else {
outputLen = ctx->ecdhExchangePublic.length + 1;
}
keyExchange->contentType = SSL_RecordTypeHandshake;
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
keyExchange->protocolVersion = ctx->negProtocolVersion;
head = SSLHandshakeHeaderSize(keyExchange);
if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head,ctx)) != 0)
return err;
uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExchange, SSL_HdskClientKeyExchange, outputLen);
if(emptyMsg) {
sslEcdsaDebug("+++ Sending EMPTY ECDH Client Key Exchange");
}
else {
charPtr = SSLEncodeSize(charPtr, ctx->ecdhExchangePublic.length, 1);
memcpy(charPtr, ctx->ecdhExchangePublic.data, ctx->ecdhExchangePublic.length);
sslEcdsaDebug("+++ Encoded ECDH Client Key Exchange");
}
dumpBuf("client pub key", &ctx->ecdhExchangePublic);
dumpBuf("client premaster", &ctx->preMasterSecret);
return noErr;
}
#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
case SSL_ECDHE_ECDSA:
case SSL_ECDHE_RSA:
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 == kSSLClientSide);
switch (ctx->selectedCipherSpec.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
sslDebugLog("SSLEncodeKeyExchange: RSA method\n");
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:
sslDebugLog("SSLEncodeKeyExchange: DH method\n");
err = SSLEncodeDHClientKeyExchange(keyExchange, ctx);
break;
#endif
case SSL_ECDH_ECDSA:
case SSL_ECDHE_ECDSA:
case SSL_ECDH_RSA:
case SSL_ECDHE_RSA:
case SSL_ECDH_anon:
sslDebugLog("SSLEncodeKeyExchange: ECDH method\n");
err = SSLEncodeECDHClientKeyExchange(keyExchange, ctx);
break;
default:
sslDebugLog("SSLEncodeKeyExchange: unknown method (%d)\n",
ctx->selectedCipherSpec.keyExchangeMethod);
err = unimpErr;
}
return err;
}
OSStatus
SSLProcessKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
{ OSStatus err;
switch (ctx->selectedCipherSpec.keyExchangeMethod)
{ case SSL_RSA:
case SSL_RSA_EXPORT:
sslDebugLog("SSLProcessKeyExchange: processing RSA key exchange (%d)\n",
ctx->selectedCipherSpec.keyExchangeMethod);
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:
sslDebugLog("SSLProcessKeyExchange: processing DH key exchange (%d)\n",
ctx->selectedCipherSpec.keyExchangeMethod);
if ((err = SSLDecodeDHClientKeyExchange(keyExchange, ctx)) != 0)
return err;
break;
#endif
default:
sslErrorLog("SSLProcessKeyExchange: unknown keyExchangeMethod (%d)\n",
ctx->selectedCipherSpec.keyExchangeMethod);
return unimpErr;
}
return noErr;
}
OSStatus
SSLInitPendingCiphers(SSLContext *ctx)
{ OSStatus err;
SSLBuffer key;
uint8_t *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;
if(ctx->negProtocolVersion == DTLS_Version_1_0)
{
ctx->readPending.sequenceNum.high = (ctx->readPending.sequenceNum.high & (0xffff<<16)) + (1<<16);
ctx->writePending.sequenceNum.high = (ctx->writePending.sequenceNum.high & (0xffff<<16)) + (1<<16);
} else {
ctx->writePending.sequenceNum.high=0;
ctx->readPending.sequenceNum.high=0;
}
ctx->readPending.sequenceNum.low = 0;
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 == kSSLServerSide)
{ 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;
UInt8 ivSize = ctx->selectedCipherSpec.cipher->ivSize;
if (ivSize == 0)
{
ivPtr = NULL;
}
else
{
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;
if (ivSize == 0)
{
ivPtr = NULL;
}
else
{
ivPtr = keyDataProgress + ctx->selectedCipherSpec.cipher->ivSize;
}
if ((err = ctx->selectedCipherSpec.cipher->initialize(keyPtr, ivPtr,
serverPending, ctx)) != 0)
goto fail;
}
else {
uint8_t 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;
}