#include "ssl.h"
#include "ssl2.h"
#include "sslRecord.h"
#include "sslMemory.h"
#include "sslContext.h"
#include "sslAlertMessage.h"
#include "sslHandshake.h"
#include "sslSession.h"
#include "sslDebug.h"
#include "cipherSpecs.h"
#include "appleCdsa.h"
#include "sslUtils.h"
#include <string.h>
#include <assert.h>
OSStatus
SSL2ProcessClientHello(SSLBuffer msg, SSLContext *ctx)
{ OSStatus err;
UInt8 *charPtr, *cipherList;
unsigned i, j, cipherKindCount, sessionIDLen, challengeLen;
SSL2CipherKind cipherKind;
SSLCipherSuite matchingCipher, selectedCipher;
SSLProtocolVersion negVersion;
if (msg.length < 27) {
sslErrorLog("SSL2ProcessClientHello: msg len error 1\n");
return errSSLProtocol;
}
charPtr = msg.data;
ctx->clientReqProtocol = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
err = sslVerifyProtVersion(ctx, ctx->clientReqProtocol, &negVersion);
if(err) {
return err;
}
if (ctx->negProtocolVersion == SSL_Version_Undetermined) {
#ifndef NDEBUG
sslLogNegotiateDebug("===SSL2 server: negVersion was undetermined; "
"is %s", protocolVersStr(negVersion));
#endif
ctx->negProtocolVersion = negVersion;
if(negVersion >= TLS_Version_1_0) {
ctx->sslTslCalls = &Tls1Callouts;
}
else {
assert(ctx->sslTslCalls == &Ssl3Callouts);
}
}
charPtr += 2;
cipherKindCount = SSLDecodeInt(charPtr, 2);
charPtr += 2;
if (cipherKindCount % 3 != 0) {
sslErrorLog("SSL2ProcessClientHello: cipherKindCount error\n");
return errSSLProtocol;
}
cipherKindCount /= 3;
sessionIDLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
challengeLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
if (msg.length != 8 + 3*cipherKindCount + sessionIDLen + challengeLen ||
(sessionIDLen != 0 && sessionIDLen != 16) ||
challengeLen < 16 || challengeLen > 32 ) {
sslErrorLog("SSL2ProcessClientHello: msg len error 2\n");
return errSSLProtocol;
}
cipherList = charPtr;
selectedCipher = SSL_NO_SUCH_CIPHERSUITE;
assert(ctx->negProtocolVersion >= SSL_Version_2_0); if (ctx->negProtocolVersion >= SSL_Version_3_0) {
for (i = 0; i < cipherKindCount; i++) {
cipherKind = (SSL2CipherKind)SSLDecodeInt(charPtr, 3);
charPtr += 3;
if (selectedCipher != SSL_NO_SUCH_CIPHERSUITE)
continue;
if ((((UInt32)cipherKind) & 0xFF0000) != 0)
continue;
matchingCipher = (SSLCipherSuite)((UInt32)cipherKind & 0x00FFFF);
for (j = 0; j<ctx->numValidCipherSpecs; j++) {
if (ctx->validCipherSpecs[j].cipherSpec == matchingCipher) {
selectedCipher = matchingCipher;
break;
}
}
}
}
if(selectedCipher == SSL_NO_SUCH_CIPHERSUITE) {
charPtr = cipherList;
for (i = 0; i < cipherKindCount; i++) {
cipherKind = (SSL2CipherKind)SSLDecodeInt(charPtr, 3);
charPtr += 3;
if (selectedCipher == SSL_NO_SUCH_CIPHERSUITE) {
if ((((UInt32)cipherKind) & 0xFF0000) != 0) {
matchingCipher = SSL_NO_SUCH_CIPHERSUITE;
for (j = 0; j < SSL2CipherMapCount; j++) {
if (cipherKind == SSL2CipherMap[j].cipherKind) {
matchingCipher = SSL2CipherMap[j].cipherSuite;
break;
}
}
}
else {
matchingCipher = (SSLCipherSuite)((UInt32)cipherKind & 0x00FFFF);
if(ctx->negProtocolVersion < SSL_Version_3_0) {
int isInMap = 0;
for (j = 0; j < SSL2CipherMapCount; j++) {
if (matchingCipher == SSL2CipherMap[j].cipherSuite) {
isInMap = 1;
break;
}
}
if(!isInMap) {
matchingCipher = SSL_NO_SUCH_CIPHERSUITE;
}
}
}
if (matchingCipher != SSL_NO_SUCH_CIPHERSUITE) {
for (j = 0; j < ctx->numValidCipherSpecs; j++) {
if (ctx->validCipherSpecs[j].cipherSpec == matchingCipher) {
selectedCipher = matchingCipher;
break;
}
}
}
}
}
}
if (selectedCipher == SSL_NO_SUCH_CIPHERSUITE)
return errSSLNegotiation;
ctx->selectedCipher = selectedCipher;
err = FindCipherSpec(ctx);
if(err != 0) {
return err;
}
if (sessionIDLen > 0 && ctx->peerID.data != 0)
{
err = SSLAllocBuffer(ctx->sessionID, sessionIDLen, ctx);
if (err == 0)
memcpy(ctx->sessionID.data, charPtr, sessionIDLen);
}
charPtr += sessionIDLen;
ctx->ssl2ChallengeLength = challengeLen;
memset(ctx->clientRandom, 0, SSL_CLIENT_SRVR_RAND_SIZE);
memcpy(ctx->clientRandom + SSL_CLIENT_SRVR_RAND_SIZE - challengeLen,
charPtr, challengeLen);
charPtr += challengeLen;
assert(charPtr == msg.data + msg.length);
return noErr;
}
#define SSL2_CHALLENGE_LEN 16
OSStatus
SSL2EncodeClientHello(SSLBuffer &msg, SSLContext *ctx)
{ OSStatus err;
UInt8 *charPtr;
unsigned i, j;
int useSSL3Ciphers = 0;
int totalCipherCount;
int sessionIDLen;
UInt16 version;
SSLBuffer sessionIdentifier, randomData;
SSLProtocolVersion maxVersion;
assert(ctx->versionSsl2Enable);
err = sslGetMaxProtVersion(ctx, &maxVersion);
if(err) {
return err;
}
version = maxVersion;
if(version > SSL_Version_2_0) {
useSSL3Ciphers = 1;
}
#ifndef NDEBUG
sslLogNegotiateDebug("===SSL client: proclaiming %s capable",
protocolVersStr((SSLProtocolVersion)version));
#endif
if (useSSL3Ciphers != 0)
totalCipherCount = ctx->numValidCipherSpecs;
else
totalCipherCount = 0;
for (i = 0; i < SSL2CipherMapCount; i++)
for (j = 0; j < ctx->numValidCipherSpecs; j++)
if (ctx->validCipherSpecs[j].cipherSpec == SSL2CipherMap[i].cipherSuite)
{ totalCipherCount++;
break;
}
if(totalCipherCount == 0) {
sslErrorLog("SSL2EncodeClientHello: no valid ciphers for SSL2");
return errSSLBadConfiguration;
}
sessionIDLen = 0;
sessionIdentifier.data = 0;
if (ctx->resumableSession.data != 0)
{ if ((err = SSLRetrieveSessionID(ctx->resumableSession, &sessionIdentifier, ctx)) != 0)
return err;
sessionIDLen = sessionIdentifier.length;
}
if ((err = SSLAllocBuffer(msg, 9 + (3*totalCipherCount) + sessionIDLen +
SSL2_CHALLENGE_LEN, ctx)) != 0)
{ SSLFreeBuffer(sessionIdentifier, ctx);
return err;
}
charPtr = msg.data;
*charPtr++ = SSL2_MsgClientHello;
charPtr = SSLEncodeInt(charPtr, version, 2);
charPtr = SSLEncodeInt(charPtr, 3*totalCipherCount, 2);
charPtr = SSLEncodeInt(charPtr, sessionIDLen, 2);
charPtr = SSLEncodeInt(charPtr, SSL2_CHALLENGE_LEN, 2);
if (useSSL3Ciphers != 0)
for (i = 0; i < ctx->numValidCipherSpecs; i++)
charPtr = SSLEncodeInt(charPtr, ctx->validCipherSpecs[i].cipherSpec, 3);
for (i = 0; i < SSL2CipherMapCount; i++)
for (j = 0; j < ctx->numValidCipherSpecs; j++)
if (ctx->validCipherSpecs[j].cipherSpec == SSL2CipherMap[i].cipherSuite)
{ charPtr = SSLEncodeInt(charPtr, SSL2CipherMap[i].cipherKind, 3);
break;
}
if (sessionIDLen > 0)
{ memcpy(charPtr, sessionIdentifier.data, sessionIDLen);
charPtr += sessionIDLen;
SSLFreeBuffer(sessionIdentifier, ctx);
}
randomData.data = charPtr;
randomData.length = SSL2_CHALLENGE_LEN;
if ((err = sslRand(ctx, &randomData)) != 0)
{ SSLFreeBuffer(msg, ctx);
return err;
}
charPtr += SSL2_CHALLENGE_LEN;
#if (SSL2_CHALLENGE_LEN == SSL_CLIENT_SRVR_RAND_SIZE)
memcpy(ctx->clientRandom, randomData.data, SSL2_CHALLENGE_LEN);
#else
memset(ctx->clientRandom, 0, SSL_CLIENT_SRVR_RAND_SIZE - SSL2_CHALLENGE_LEN);
memcpy(ctx->clientRandom + SSL_CLIENT_SRVR_RAND_SIZE - SSL2_CHALLENGE_LEN,
randomData.data, SSL2_CHALLENGE_LEN);
#endif
ctx->ssl2ChallengeLength = SSL2_CHALLENGE_LEN;
assert(charPtr == msg.data + msg.length);
return noErr;
}
OSStatus
SSL2ProcessClientMasterKey(SSLBuffer msg, SSLContext *ctx)
{ OSStatus err;
SSL2CipherKind cipherKind;
SSLBuffer secretData;
unsigned clearLength, encryptedLength, keyArgLength;
UInt32 secretLength, localKeyModulusLen;
UInt8 *charPtr;
const CSSM_KEY *decryptKey;
CSSM_CSP_HANDLE decryptCspHand;
if (msg.length < 9) {
sslErrorLog("SSL2ProcessClientMasterKey: msg.length error 1\n");
return errSSLProtocol;
}
assert(ctx->protocolSide == SSL_ServerSide);
charPtr = msg.data;
cipherKind = (SSL2CipherKind)SSLDecodeInt(charPtr, 3);
charPtr += 3;
clearLength = SSLDecodeInt(charPtr, 2);
charPtr += 2;
encryptedLength = SSLDecodeInt(charPtr, 2);
charPtr += 2;
keyArgLength = SSLDecodeInt(charPtr, 2);
charPtr += 2;
if (msg.length != 9 + clearLength + encryptedLength + keyArgLength) {
sslErrorLog("SSL2ProcessClientMasterKey: msg.length error 2\n");
return errSSLProtocol;
}
memcpy(ctx->masterSecret, charPtr, clearLength);
charPtr += clearLength;
if(ctx->encryptPrivKey) {
decryptKey = ctx->encryptPrivKey;
assert(ctx->encryptKeyCsp != 0);
decryptCspHand = ctx->encryptKeyCsp;
}
else if(ctx->signingPrivKey) {
decryptKey = ctx->signingPrivKey;
assert(ctx->signingKeyCsp != 0);
decryptCspHand = ctx->signingKeyCsp;
}
else {
sslErrorLog("SSL2ProcessClientMasterKey: No server key!\n");
return errSSLBadConfiguration;
}
localKeyModulusLen = sslKeyLengthInBytes(decryptKey);
if (encryptedLength != localKeyModulusLen) {
sslErrorLog("SSL2ProcessClientMasterKey: encryptedLength error 1\n");
return errSSLProtocol;
}
if ((err = SSLAllocBuffer(secretData, encryptedLength, ctx)) != 0)
return err;
err = sslRsaDecrypt(ctx,
decryptKey,
decryptCspHand,
charPtr,
encryptedLength,
secretData.data,
encryptedLength, &secretLength);
if(err) {
SSLFreeBuffer(secretData, ctx);
return err;
}
charPtr += encryptedLength;
if (clearLength + secretLength != ctx->selectedCipherSpec->cipher->keySize) {
sslErrorLog("SSL2ProcessClientMasterKey: length error 3\n");
return errSSLProtocol;
}
memcpy(ctx->masterSecret + clearLength, secretData.data, secretLength);
if ((err = SSLFreeBuffer(secretData, ctx)) != 0)
return err;
if (keyArgLength != ctx->selectedCipherSpec->cipher->ivSize) {
sslErrorLog("SSL2ProcessClientMasterKey: length error 4\n");
return errSSLProtocol;
}
memcpy(ctx->masterSecret + ctx->selectedCipherSpec->cipher->keySize, charPtr, keyArgLength);
charPtr += keyArgLength;
assert(charPtr = msg.data + msg.length);
return noErr;
}
OSStatus
SSL2EncodeClientMasterKey(SSLBuffer &msg, SSLContext *ctx)
{ OSStatus err;
unsigned length, i, clearLen;
UInt32 outputLen, peerKeyModulusLen;
SSLBuffer keyData;
UInt8 *charPtr;
peerKeyModulusLen = sslKeyLengthInBytes(ctx->peerPubKey);
length = 10;
clearLen = ctx->selectedCipherSpec->cipher->keySize - ctx->selectedCipherSpec->cipher->secretKeySize;
length += clearLen;
length += peerKeyModulusLen;
length += ctx->selectedCipherSpec->cipher->ivSize;
if ((err = SSLAllocBuffer(msg, length, ctx)) != 0)
return err;
charPtr = msg.data;
*charPtr++ = SSL2_MsgClientMasterKey;
for (i = 0; i < SSL2CipherMapCount; i++)
if (ctx->selectedCipher == SSL2CipherMap[i].cipherSuite)
break;
assert(i < SSL2CipherMapCount);
sslLogNegotiateDebug("===SSL2EncodeClientMasterKey: sending cipherKind 0x%x",
SSL2CipherMap[i].cipherKind);
charPtr = SSLEncodeInt(charPtr, SSL2CipherMap[i].cipherKind, 3);
charPtr = SSLEncodeInt(charPtr, clearLen, 2);
charPtr = SSLEncodeInt(charPtr, peerKeyModulusLen, 2);
charPtr = SSLEncodeInt(charPtr, ctx->selectedCipherSpec->cipher->ivSize, 2);
keyData.data = ctx->masterSecret;
keyData.length = ctx->selectedCipherSpec->cipher->keySize + ctx->selectedCipherSpec->cipher->ivSize;
assert(keyData.length <= 48);
if ((err = sslRand(ctx, &keyData)) != 0)
return err;
memcpy(charPtr, ctx->masterSecret, clearLen);
charPtr += clearLen;
err = sslRsaEncrypt(ctx,
ctx->peerPubKey,
ctx->peerPubKeyCsp, ctx->masterSecret + clearLen,
ctx->selectedCipherSpec->cipher->keySize - clearLen,
charPtr,
peerKeyModulusLen,
&outputLen);
if(err) {
return err;
}
charPtr += outputLen;
memcpy(charPtr, ctx->masterSecret + ctx->selectedCipherSpec->cipher->keySize,
ctx->selectedCipherSpec->cipher->ivSize);
charPtr += ctx->selectedCipherSpec->cipher->ivSize;
assert(charPtr == msg.data + msg.length);
return noErr;
}
OSStatus
SSL2ProcessClientFinished(SSLBuffer msg, SSLContext *ctx)
{ if (msg.length != ctx->sessionID.length) {
sslErrorLog("SSL2ProcessClientFinished: length error\n");
return errSSLProtocol;
}
if (memcmp(msg.data, ctx->serverRandom, ctx->ssl2ConnectionIDLength) != 0) {
sslErrorLog("SSL2ProcessClientFinished: data compare error\n");
return errSSLProtocol;
}
return noErr;
}
OSStatus
SSL2EncodeClientFinished(SSLBuffer &msg, SSLContext *ctx)
{ OSStatus err;
if ((err = SSLAllocBuffer(msg, ctx->ssl2ConnectionIDLength+1, ctx)) != 0)
return err;
msg.data[0] = SSL2_MsgClientFinished;
memcpy(msg.data+1, ctx->serverRandom, ctx->ssl2ConnectionIDLength);
return noErr;
}
OSStatus
SSL2ProcessServerHello(SSLBuffer msg, SSLContext *ctx)
{ OSStatus err;
SSL2CertTypeCode certType;
unsigned sessionIDMatch, certLen, cipherSpecsLen, connectionIDLen;
unsigned i, j;
SSL2CipherKind cipherKind;
SSLCertificate *cert;
SSLCipherSuite matchingCipher = 0; SSLCipherSuite selectedCipher;
UInt8 *charPtr;
SSLProtocolVersion version;
if (msg.length < 10) {
sslErrorLog("SSL2ProcessServerHello: length error\n");
return errSSLProtocol;
}
charPtr = msg.data;
sessionIDMatch = *charPtr++;
certType = (SSL2CertTypeCode)*charPtr++;
version = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
charPtr += 2;
if (version != SSL_Version_2_0) {
sslErrorLog("SSL2ProcessServerHello: version error\n");
return errSSLProtocol;
}
ctx->negProtocolVersion = version;
sslLogNegotiateDebug("===SSL2 client: negVersion is 2_0");
certLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
cipherSpecsLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
connectionIDLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
if (connectionIDLen < 16 || connectionIDLen > 32 || cipherSpecsLen % 3 != 0 ||
(msg.length != 10 + certLen + cipherSpecsLen + connectionIDLen) )
return errSSLProtocol;
if (sessionIDMatch != 0)
{ if (certLen != 0 || cipherSpecsLen != 0 )
return errSSLProtocol;
ctx->sessionMatch = 1;
ctx->ssl2ConnectionIDLength = connectionIDLen;
memcpy(ctx->serverRandom, charPtr, connectionIDLen);
charPtr += connectionIDLen;
}
else
{ if (certType != SSL2_CertTypeX509)
return errSSLNegotiation;
cipherSpecsLen /= 3;
cert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
if(cert == NULL) {
return memFullErr;
}
cert->next = 0;
if ((err = SSLAllocBuffer(cert->derCert, certLen, ctx)) != 0)
{
sslFree(cert);
return err;
}
memcpy(cert->derCert.data, charPtr, certLen);
charPtr += certLen;
ctx->peerCert = cert;
if((err = sslVerifyCertChain(ctx, *ctx->peerCert)) != 0) {
return err;
}
if((err = sslPubKeyFromCert(ctx,
cert->derCert,
&ctx->peerPubKey,
&ctx->peerPubKeyCsp)) != 0)
return err;
selectedCipher = SSL_NO_SUCH_CIPHERSUITE;
for (i = 0; i < cipherSpecsLen; i++)
{ cipherKind = (SSL2CipherKind)SSLDecodeInt(charPtr, 3);
charPtr += 3;
if (selectedCipher == SSL_NO_SUCH_CIPHERSUITE)
{ for (j = 0; j < SSL2CipherMapCount; j++)
if (cipherKind == SSL2CipherMap[j].cipherKind)
{ matchingCipher = SSL2CipherMap[j].cipherSuite;
break;
}
for (j = 0; j < ctx->numValidCipherSpecs; j++)
if (ctx->validCipherSpecs[j].cipherSpec == matchingCipher)
{ selectedCipher = matchingCipher;
break;
}
}
}
if (selectedCipher == SSL_NO_SUCH_CIPHERSUITE)
return errSSLNegotiation;
sslLogNegotiateDebug("===SSL2 client: selectedCipher 0x%x",
(unsigned)selectedCipher);
ctx->selectedCipher = selectedCipher;
if ((err = FindCipherSpec(ctx)) != 0) {
return err;
}
ctx->ssl2ConnectionIDLength = connectionIDLen;
memcpy(ctx->serverRandom, charPtr, connectionIDLen);
charPtr += connectionIDLen;
}
assert(charPtr == msg.data + msg.length);
return noErr;
}
OSStatus
SSL2EncodeServerHello(SSLBuffer &msg, SSLContext *ctx)
{ OSStatus err;
SSLCertificate *cert;
SSLBuffer randomData;
UInt8 *charPtr;
unsigned i;
ctx->ssl2ConnectionIDLength = SSL2_CONNECTION_ID_LENGTH;
randomData.data = ctx->serverRandom;
randomData.length = ctx->ssl2ConnectionIDLength;
if ((err = sslRand(ctx, &randomData)) != 0)
return err;
if (ctx->sessionMatch != 0)
{ if ((err = SSLAllocBuffer(msg, 11 + ctx->sessionID.length, ctx)) != 0)
return err;
charPtr = msg.data;
*charPtr++ = SSL2_MsgServerHello;
*charPtr++ = ctx->sessionMatch;
*charPtr++ = 0;
charPtr = SSLEncodeInt(charPtr, ctx->negProtocolVersion, 2);
charPtr = SSLEncodeInt(charPtr, 0, 2);
charPtr = SSLEncodeInt(charPtr, 0, 2);
charPtr = SSLEncodeInt(charPtr, ctx->ssl2ConnectionIDLength, 2);
memcpy(charPtr, ctx->serverRandom, ctx->ssl2ConnectionIDLength);
charPtr += ctx->ssl2ConnectionIDLength;
}
else
{
if(ctx->encryptCert != NULL) {
cert = ctx->encryptCert;
}
else if(ctx->localCert != NULL) {
cert = ctx->localCert;
}
else {
sslErrorLog("SSL2EncodeServerHello: No server cert!\n");
return badReqErr;
}
while (cert->next != 0)
cert = cert->next;
if ((err = SSLAllocBuffer(msg, 11 + cert->derCert.length + 3 + ctx->sessionID.length, ctx)) != 0)
return err;
charPtr = msg.data;
*charPtr++ = SSL2_MsgServerHello;
*charPtr++ = ctx->sessionMatch;
*charPtr++ = SSL2_CertTypeX509;
#ifndef NDEBUG
sslLogNegotiateDebug("===SSL2 server: sending vers info %s",
protocolVersStr((SSLProtocolVersion)ctx->negProtocolVersion));
#endif
charPtr = SSLEncodeInt(charPtr, ctx->negProtocolVersion, 2);
charPtr = SSLEncodeInt(charPtr, cert->derCert.length, 2);
charPtr = SSLEncodeInt(charPtr, 3, 2);
charPtr = SSLEncodeInt(charPtr, ctx->ssl2ConnectionIDLength, 2);
memcpy(charPtr, cert->derCert.data, cert->derCert.length);
charPtr += cert->derCert.length;
for (i = 0; i < SSL2CipherMapCount; i++)
if (ctx->selectedCipher == SSL2CipherMap[i].cipherSuite)
break;
assert(i < SSL2CipherMapCount);
charPtr = SSLEncodeInt(charPtr, SSL2CipherMap[i].cipherKind, 3);
sslLogNegotiateDebug("ssl2: server specifying cipherKind 0x%lx",
(UInt32)SSL2CipherMap[i].cipherKind);
memcpy(charPtr, ctx->serverRandom, ctx->ssl2ConnectionIDLength);
charPtr += ctx->ssl2ConnectionIDLength;
}
assert(charPtr == msg.data + msg.length);
return noErr;
}
OSStatus
SSL2ProcessServerVerify(SSLBuffer msg, SSLContext *ctx)
{ if (msg.length != ctx->ssl2ChallengeLength)
return errSSLProtocol;
if (memcmp(msg.data, ctx->clientRandom + SSL_CLIENT_SRVR_RAND_SIZE -
ctx->ssl2ChallengeLength, ctx->ssl2ChallengeLength) != 0)
return errSSLProtocol;
return noErr;
}
OSStatus
SSL2EncodeServerVerify(SSLBuffer &msg, SSLContext *ctx)
{ OSStatus err;
if ((err = SSLAllocBuffer(msg, 1 + ctx->ssl2ChallengeLength, ctx)) != 0)
return err;
msg.data[0] = SSL2_MsgServerVerify;
memcpy(msg.data+1, ctx->clientRandom + SSL_CLIENT_SRVR_RAND_SIZE -
ctx->ssl2ChallengeLength, ctx->ssl2ChallengeLength);
return noErr;
}
OSStatus
SSL2ProcessServerFinished(SSLBuffer msg, SSLContext *ctx)
{ OSStatus err;
if ((err = SSLAllocBuffer(ctx->sessionID, msg.length, ctx)) != 0)
return err;
memcpy(ctx->sessionID.data, msg.data, msg.length);
return noErr;
}
OSStatus
SSL2EncodeServerFinished(SSLBuffer &msg, SSLContext *ctx)
{ OSStatus err;
if ((err = SSLAllocBuffer(msg, 1 + ctx->sessionID.length, ctx)) != 0)
return err;
msg.data[0] = SSL2_MsgServerFinished;
memcpy(msg.data+1, ctx->sessionID.data, ctx->sessionID.length);
return noErr;
}