+++ /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.
- */
-
-#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;
- }
-
- /*
- * Note we can be here, processing a v2 client hello, even if
- * we don't support SSL2. That can happen if the client is
- * sending a v2 hello with an attempt to upgrade.
- */
- 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 {
- /* default from context init */
- 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); // i.e., not undetermined
- if (ctx->negProtocolVersion >= SSL_Version_3_0) {
- /* If we're negotiating an SSL 3.0 session, use SSL 3.0 suites first */
- 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; /* Skip SSL 2 suites */
- matchingCipher = (SSLCipherSuite)((UInt32)cipherKind & 0x00FFFF);
- for (j = 0; j<ctx->numValidCipherSpecs; j++) {
- if (ctx->validCipherSpecs[j].cipherSpec == matchingCipher) {
- selectedCipher = matchingCipher;
- break;
- }
- } /* searching thru all our valid ciphers */
- } /* for each client cipher */
- } /* v3 or greater */
-
- if(selectedCipher == SSL_NO_SUCH_CIPHERSUITE) {
- /* try again using SSL2 ciphers only */
- charPtr = cipherList;
- for (i = 0; i < cipherKindCount; i++) {
- cipherKind = (SSL2CipherKind)SSLDecodeInt(charPtr, 3);
- charPtr += 3;
- if (selectedCipher == SSL_NO_SUCH_CIPHERSUITE) {
- /* After we find one, just keep advancing ptr past
- * the unused ones */
- if ((((UInt32)cipherKind) & 0xFF0000) != 0) {
- /* If it's a real SSL2 spec, look for it in the list */
- matchingCipher = SSL_NO_SUCH_CIPHERSUITE;
- for (j = 0; j < SSL2CipherMapCount; j++) {
- if (cipherKind == SSL2CipherMap[j].cipherKind) {
- matchingCipher = SSL2CipherMap[j].cipherSuite;
- break;
- }
- }
- } /* real 3-byte SSL2 suite */
- else {
- /* if the first byte is zero, it's an encoded SSL 3 CipherSuite */
- matchingCipher = (SSLCipherSuite)((UInt32)cipherKind & 0x00FFFF);
- /*
- * One more restriction - if we've negotiated a v2 session,
- * ignore this matching cipher if it's not in the SSL2 map.
- */
- 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) {
- /* Sorry, no can do */
- matchingCipher = SSL_NO_SUCH_CIPHERSUITE;
- }
- } /* SSL2 check */
- } /* two-byte suite */
-
- /* now see if we are enabled for this cipher */
- if (matchingCipher != SSL_NO_SUCH_CIPHERSUITE) {
- for (j = 0; j < ctx->numValidCipherSpecs; j++) {
- if (ctx->validCipherSpecs[j].cipherSpec == matchingCipher) {
- selectedCipher = matchingCipher;
- break;
- }
- }
- }
- } /* not ignoring this suite */
- } /* for each suite in the hello msg */
- } /* not found in SSL3 ciphersuites */
-
- 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)
- { /* Don't die on error; just treat it as an uncacheable session */
- 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;
-}
-
-/*
- * The SSL v2 spec says that the challenge string sent by the client can be
- * between 16 and 32 bytes. However all Netscape enterprise servers actually
- * require a 16 byte challenge. Q.v. cdnow.com, store.apple.com.
- * Unfortunately this means that when we're trying to do an
- * SSL2 hello with possible upgrade, we have to limit ourself to a
- * 16-byte clientRandom, which we have to concatenate to 16 bytes of zeroes
- * if we end up with a 3.0 or 3.1 connection. Thus we lose 16 bytes of entropy.
- */
-#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) {
- /* we don't have a protocol enabled */
- return err;
- }
- version = maxVersion;
- if(version > SSL_Version_2_0) {
- /* see if server can handle upgrading */
- 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;
- }
-
- /* msg length = 9 + 3 * totalCipherCount + sessionIDLen + 16 bytes of challenge
- * Use exactly 16 bytes of challenge because Netscape products have a bug
- * that requires this 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 we can send SSL3 ciphers, encode the two-byte cipher specs into three-byte
- * CipherKinds which have a leading 0.
- */
- if (useSSL3Ciphers != 0)
- for (i = 0; i < ctx->numValidCipherSpecs; i++)
- charPtr = SSLEncodeInt(charPtr, ctx->validCipherSpecs[i].cipherSpec, 3);
-
- /* Now send those SSL2 specs for which we have implementations */
- 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;
-
- /* Zero out the first 16 bytes of clientRandom, and store
- * the challenge in the second 16 bytes */
- #if (SSL2_CHALLENGE_LEN == SSL_CLIENT_SRVR_RAND_SIZE)
- /* this path verified to fail with Netscape Enterprise servers 1/16/02 */
- 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 *cssmKey;
- SecKeyRef decryptKeyRef = NULL;
-
- 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;
- }
-
- /* Master key == CLEAR_DATA || SECRET_DATA */
- memcpy(ctx->masterSecret, charPtr, clearLength);
- charPtr += clearLength;
-
- /*
- * Just as in SSL2EncodeServerHello, which key we use depends on the
- * app's config.
- */
- if(ctx->encryptPrivKeyRef) {
- decryptKeyRef = ctx->encryptPrivKeyRef;
- /* FIXME: when 3420180 is implemented, pick appropriate creds here */
- }
- else if(ctx->signingPrivKeyRef) {
- decryptKeyRef = ctx->signingPrivKeyRef;
- /* FIXME: when 3420180 is implemented, pick appropriate creds here */
- }
- else {
- /* app configuration error */
- sslErrorLog("SSL2ProcessClientMasterKey: No server key!\n");
- return errSSLBadConfiguration;
- }
- err = SecKeyGetCSSMKey(decryptKeyRef, &cssmKey);
- if(err) {
- sslErrorLog("SSL2ProcessClientMasterKey: SecKeyGetCSSMKey err %d\n", (int)err);
- return err;
- }
- localKeyModulusLen = sslKeyLengthInBytes(cssmKey);
-
- if (encryptedLength != localKeyModulusLen) {
- sslErrorLog("SSL2ProcessClientMasterKey: encryptedLength error 1\n");
- return errSSLProtocol;
- }
-
- /* Allocate enough room to hold any decrypted value */
- if ((err = SSLAllocBuffer(secretData, encryptedLength, ctx)) != 0)
- return err;
-
- err = sslRsaDecrypt(ctx,
- decryptKeyRef,
- charPtr,
- encryptedLength,
- secretData.data,
- encryptedLength, // same length for both...?
- &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;
- }
-
- /* Stash the IV after the master key in master secret storage */
- 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 is 10 + clear key size + encrypted output size + iv size */
- 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);
-
- /* Generate the keying material; we need enough data for the key and IV */
- keyData.data = ctx->masterSecret;
- keyData.length = ctx->selectedCipherSpec->cipher->keySize + ctx->selectedCipherSpec->cipher->ivSize;
- assert(keyData.length <= 48); /* Must be able to store it in the masterSecret array */
- if ((err = sslRand(ctx, &keyData)) != 0)
- return err;
-
- memcpy(charPtr, ctx->masterSecret, clearLen);
- charPtr += clearLen;
-
- /* Replace this with code to do encryption at lower level & set PKCS1 padding
- for rollback attack */
-
- /*
- * encrypt only the secret key portion of masterSecret, starting at
- * clearLen bytes
- */
- err = sslRsaEncrypt(ctx,
- ctx->peerPubKey,
- ctx->peerPubKeyCsp, // XX - maybe cspHand
- ctx->masterSecret + clearLen,
- ctx->selectedCipherSpec->cipher->keySize - clearLen,
- charPtr,
- peerKeyModulusLen,
- &outputLen);
- if(err) {
- return err;
- }
-
- charPtr += outputLen;
-
- /* copy clear IV to msg buf */
- 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; // avoid compiler warning
- 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 /* || certType != 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) /* After we find one, just keep advancing charPtr past the unused ones */
- { 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;
-
- /* Create the connection ID */
- 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; /* cert type */
- charPtr = SSLEncodeInt(charPtr, ctx->negProtocolVersion, 2);
- charPtr = SSLEncodeInt(charPtr, 0, 2); /* cert len */
- charPtr = SSLEncodeInt(charPtr, 0, 2); /* cipherspecs len */
- charPtr = SSLEncodeInt(charPtr, ctx->ssl2ConnectionIDLength, 2);
- memcpy(charPtr, ctx->serverRandom, ctx->ssl2ConnectionIDLength);
- charPtr += ctx->ssl2ConnectionIDLength;
- }
- else
- { /* First, find the last cert in the chain; it's the one we'll send */
-
- /*
- * Use encryptCert if we have it, but allow for the case of app
- * specifying one cert which can encrypt and sign.
- */
- if(ctx->encryptCert != NULL) {
- cert = ctx->encryptCert;
- }
- else if(ctx->localCert != NULL) {
- cert = ctx->localCert;
- }
- else {
- /* really should not happen... */
- 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; /* cert type */
-
- #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); /* cipherspecs len */
- 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;
-}