+++ /dev/null
-/*
- * Copyright (c) 1999-2001,2005-2008,2010-2012 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The 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.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * sslHandshakeHello.c - Support for client hello and server hello messages.
- */
-
-#include "sslContext.h"
-#include "sslHandshake.h"
-#include "sslMemory.h"
-#include "sslSession.h"
-#include "sslUtils.h"
-#include "sslDebug.h"
-#include "sslCrypto.h"
-#include "sslRand.h"
-#include "sslDigests.h"
-#include "sslCipherSpecs.h"
-
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-
-#include <inttypes.h>
-
-/*
- * Given a protocol version sent by peer, determine if we accept that version
- * and downgrade if appropriate (which can not be done for the client side).
- */
-static
-OSStatus sslVerifyProtVersion(
- SSLContext *ctx,
- SSLProtocolVersion peerVersion, // sent by peer
- SSLProtocolVersion *negVersion) // final negotiated version if return success
-{
- if ((ctx->isDTLS)
- ? peerVersion > ctx->minProtocolVersion
- : peerVersion < ctx->minProtocolVersion) {
- return errSSLNegotiation;
- }
- if ((ctx->isDTLS)
- ? peerVersion < ctx->maxProtocolVersion
- : peerVersion > ctx->maxProtocolVersion) {
- if (ctx->protocolSide == kSSLClientSide) {
- return errSSLNegotiation;
- }
- *negVersion = ctx->maxProtocolVersion;
- } else {
- *negVersion = peerVersion;
- }
-
- return errSecSuccess;
-}
-
-
-/* IE treats null session id as valid; two consecutive sessions with NULL ID
- * are considered a match. Workaround: when resumable sessions are disabled,
- * send a random session ID. */
-#define SSL_IE_NULL_RESUME_BUG 1
-#if SSL_IE_NULL_RESUME_BUG
-#define SSL_NULL_ID_LEN 32 /* length of bogus session ID */
-#endif
-
-OSStatus
-SSLEncodeServerHello(SSLRecord *serverHello, SSLContext *ctx)
-{ OSStatus err;
- UInt8 *charPtr;
- int sessionIDLen;
- size_t msglen;
- int head;
-
- sessionIDLen = 0;
- if (ctx->sessionID.data != 0)
- sessionIDLen = (UInt8)ctx->sessionID.length;
- #if SSL_IE_NULL_RESUME_BUG
- if(sessionIDLen == 0) {
- sessionIDLen = SSL_NULL_ID_LEN;
- }
- #endif /* SSL_IE_NULL_RESUME_BUG */
-
- msglen = 38 + sessionIDLen;
-
- /* this was set to a known quantity in SSLProcessClientHello */
- check(ctx->negProtocolVersion != SSL_Version_Undetermined);
- /* should not be here in this case */
- check(ctx->negProtocolVersion != SSL_Version_2_0);
- sslLogNegotiateDebug("===SSL3 server: sending version %d_%d",
- ctx->negProtocolVersion >> 8, ctx->negProtocolVersion & 0xff);
- sslLogNegotiateDebug("...sessionIDLen = %d", sessionIDLen);
- serverHello->protocolVersion = ctx->negProtocolVersion;
- serverHello->contentType = SSL_RecordTypeHandshake;
- head = SSLHandshakeHeaderSize(serverHello);
- if ((err = SSLAllocBuffer(&serverHello->contents, msglen + head)))
- return err;
-
- charPtr = SSLEncodeHandshakeHeader(ctx, serverHello, SSL_HdskServerHello, msglen);
-
- charPtr = SSLEncodeInt(charPtr, serverHello->protocolVersion, 2);
-
- #if SSL_PAC_SERVER_ENABLE
- /* serverRandom might have already been set, in SSLAdvanceHandshake() */
- if(!ctx->serverRandomValid) {
- if ((err = SSLEncodeRandom(ctx->serverRandom, ctx)) != 0) {
- return err;
- }
- }
- #else
- /* This is the normal production code path */
- if ((err = SSLEncodeRandom(ctx->serverRandom, ctx)) != 0)
- return err;
- #endif /* SSL_PAC_SERVER_ENABLE */
-
- memcpy(charPtr, ctx->serverRandom, SSL_CLIENT_SRVR_RAND_SIZE);
-
- charPtr += SSL_CLIENT_SRVR_RAND_SIZE;
- *(charPtr++) = (UInt8)sessionIDLen;
- #if SSL_IE_NULL_RESUME_BUG
- if(ctx->sessionID.data != NULL) {
- /* normal path for enabled resumable session */
- memcpy(charPtr, ctx->sessionID.data, sessionIDLen);
- }
- else {
- /* IE workaround */
- SSLBuffer rb;
- rb.data = charPtr;
- rb.length = SSL_NULL_ID_LEN;
- sslRand(&rb);
- }
- #else
- if (sessionIDLen > 0)
- memcpy(charPtr, ctx->sessionID.data, sessionIDLen);
- #endif /* SSL_IE_NULL_RESUME_BUG */
- charPtr += sessionIDLen;
- charPtr = SSLEncodeInt(charPtr, ctx->selectedCipher, 2);
- *(charPtr++) = 0; /* Null compression */
-
- sslLogNegotiateDebug("ssl3: server specifying cipherSuite 0x%lx",
- (unsigned long)ctx->selectedCipher);
-
- assert(charPtr == serverHello->contents.data + serverHello->contents.length);
-
- return errSecSuccess;
-}
-
-OSStatus
-SSLEncodeServerHelloVerifyRequest(SSLRecord *helloVerifyRequest, SSLContext *ctx)
-{ OSStatus err;
- UInt8 *charPtr;
- size_t msglen;
- int head;
-
- assert(ctx->protocolSide == kSSLServerSide);
- assert(ctx->negProtocolVersion == DTLS_Version_1_0);
- assert(ctx->dtlsCookie.length);
-
- msglen = 3 + ctx->dtlsCookie.length;
-
- helloVerifyRequest->protocolVersion = DTLS_Version_1_0;
- helloVerifyRequest->contentType = SSL_RecordTypeHandshake;
- head = SSLHandshakeHeaderSize(helloVerifyRequest);
- if ((err = SSLAllocBuffer(&helloVerifyRequest->contents, msglen + head)))
- return err;
-
- charPtr = SSLEncodeHandshakeHeader(ctx, helloVerifyRequest, SSL_HdskHelloVerifyRequest, msglen);
-
- charPtr = SSLEncodeInt(charPtr, helloVerifyRequest->protocolVersion, 2);
-
- *charPtr++ = ctx->dtlsCookie.length;
- memcpy(charPtr, ctx->dtlsCookie.data, ctx->dtlsCookie.length);
- charPtr += ctx->dtlsCookie.length;
-
- assert(charPtr == (helloVerifyRequest->contents.data + helloVerifyRequest->contents.length));
-
- return errSecSuccess;
-}
-
-
-OSStatus
-SSLProcessServerHelloVerifyRequest(SSLBuffer message, SSLContext *ctx)
-{ OSStatus err;
- SSLProtocolVersion protocolVersion;
- unsigned int cookieLen;
- UInt8 *p;
-
- assert(ctx->protocolSide == kSSLClientSide);
-
- /* TODO: those length values should not be hardcoded */
- /* 3 bytes at least with empty cookie */
- if (message.length < 3 ) {
- sslErrorLog("SSLProcessServerHelloVerifyRequest: msg len error\n");
- return errSSLProtocol;
- }
- p = message.data;
-
- protocolVersion = (SSLProtocolVersion)SSLDecodeInt(p, 2);
- p += 2;
-
- /* TODO: Not clear what else to do with protocol version here */
- if(protocolVersion != DTLS_Version_1_0) {
- sslErrorLog("SSLProcessServerHelloVerifyRequest: protocol version error\n");
- return errSSLProtocol;
- }
-
- cookieLen = *p++;
- sslLogNegotiateDebug("cookieLen = %d, msglen=%d\n", (int)cookieLen, (int)message.length);
- /* TODO: hardcoded '15' again */
- if (message.length < (3 + cookieLen)) {
- sslErrorLog("SSLProcessServerHelloVerifyRequest: msg len error 2\n");
- return errSSLProtocol;
- }
-
- err = SSLAllocBuffer(&ctx->dtlsCookie, cookieLen);
- if (err == 0)
- memcpy(ctx->dtlsCookie.data, p, cookieLen);
-
- return err;
-}
-
-static void
-SSLProcessServerHelloExtension_SecureRenegotiation(SSLContext *ctx, UInt16 extLen, UInt8 *p)
-{
- if(extLen!= (1 + ctx->ownVerifyData.length + ctx->peerVerifyData.length))
- return;
-
- if(*p!=ctx->ownVerifyData.length + ctx->ownVerifyData.length)
- return;
- p++;
-
- if(memcmp(p, ctx->ownVerifyData.data, ctx->ownVerifyData.length))
- return;
- p+=ctx->ownVerifyData.length;
-
- if(memcmp(p, ctx->peerVerifyData.data, ctx->peerVerifyData.length))
- return;
-
- ctx->secure_renegotiation_received = true;
-}
-
-
-static OSStatus
-SSLProcessServerHelloExtensions(SSLContext *ctx, UInt16 extensionsLen, UInt8 *p)
-{
- Boolean got_secure_renegotiation = false;
- UInt16 remaining;
-
- if(extensionsLen<2) {
- sslErrorLog("SSLProcessHelloExtensions: need a least 2 bytes\n");
- return errSSLProtocol;
- }
-
- remaining = SSLDecodeInt(p, 2); p+=2;
- extensionsLen -=2;
-
- /* remaining = number of bytes remaining to process according to buffer data */
- /* extensionsLen = number of bytes in the buffer */
-
- if(remaining>extensionsLen) {
- sslErrorLog("SSLProcessHelloExtensions: ext len error 1\n");
- return errSSLProtocol;
- }
-
- if(remaining<extensionsLen) {
- sslErrorLog("Warning: SSLProcessServerHelloExtensions: Too many bytes\n");
- }
-
- while(remaining) {
- UInt16 extType;
- UInt16 extLen;
-
- if (remaining<4) {
- sslErrorLog("SSLProcessHelloExtensions: ext len error\n");
- return errSSLProtocol;
- }
-
- extType = SSLDecodeInt(p, 2); p+=2;
- extLen = SSLDecodeInt(p, 2); p+=2;
-
- if (remaining<(4+extLen)) {
- sslErrorLog("SSLProcessHelloExtension: ext len error 2\n");
- return errSSLProtocol;
- }
- remaining -= (4+extLen);
-
- switch (extType) {
- case SSL_HE_SecureRenegotation:
- if(got_secure_renegotiation)
- return errSSLProtocol; /* Fail if we already processed one */
- got_secure_renegotiation = true;
- SSLProcessServerHelloExtension_SecureRenegotiation(ctx, extLen, p);
- break;
- default:
- /*
- Do nothing for other extensions. Per RFC 5246, we should (MUST) error
- if we received extensions we didnt specify in the Client Hello.
- Client should also abort handshake if multiple extensions of the same
- type are found
- */
- break;
- }
- p+=extLen;
- }
-
- return errSecSuccess;
-}
-
-
-
-OSStatus
-SSLProcessServerHello(SSLBuffer message, SSLContext *ctx)
-{ OSStatus err;
- SSLProtocolVersion protocolVersion, negVersion;
- size_t sessionIDLen;
- size_t extensionsLen;
- UInt8 *p;
-
- assert(ctx->protocolSide == kSSLClientSide);
-
- if (message.length < 38) {
- sslErrorLog("SSLProcessServerHello: msg len error\n");
- return errSSLProtocol;
- }
- p = message.data;
-
- protocolVersion = (SSLProtocolVersion)SSLDecodeInt(p, 2);
- p += 2;
- /* FIXME this should probably send appropriate alerts */
- err = sslVerifyProtVersion(ctx, protocolVersion, &negVersion);
- if(err) {
- return err;
- }
- ctx->negProtocolVersion = negVersion;
- switch(negVersion) {
- case SSL_Version_3_0:
- ctx->sslTslCalls = &Ssl3Callouts;
- break;
- case TLS_Version_1_0:
- case TLS_Version_1_1:
- case DTLS_Version_1_0:
- ctx->sslTslCalls = &Tls1Callouts;
- break;
- case TLS_Version_1_2:
- ctx->sslTslCalls = &Tls12Callouts;
- break;
- default:
- return errSSLNegotiation;
- }
- err = ctx->recFuncs->setProtocolVersion(ctx->recCtx, negVersion);
- if(err) {
- return err;
- }
-
- sslLogNegotiateDebug("===SSL3 client: negVersion is %d_%d",
- (negVersion >> 8) & 0xff, negVersion & 0xff);
-
- memcpy(ctx->serverRandom, p, 32);
- p += 32;
-
- sessionIDLen = *p++;
- if (message.length < (38 + sessionIDLen)) {
- sslErrorLog("SSLProcessServerHello: msg len error 2\n");
- return errSSLProtocol;
- }
- if (sessionIDLen > 0 && ctx->peerID.data != 0)
- { /* Don't die on error; just treat it as an uncached session */
- if (ctx->sessionID.data)
- SSLFreeBuffer(&ctx->sessionID);
- err = SSLAllocBuffer(&ctx->sessionID, sessionIDLen);
- if (err == 0)
- memcpy(ctx->sessionID.data, p, sessionIDLen);
- }
- p += sessionIDLen;
-
- ctx->selectedCipher = (UInt16)SSLDecodeInt(p,2);
- sslLogNegotiateDebug("===ssl3: server requests cipherKind %x",
- (unsigned)ctx->selectedCipher);
- p += 2;
- if ((err = FindCipherSpec(ctx)) != 0) {
- return err;
- }
-
- if (*p++ != 0) /* Compression */
- return errSecUnimplemented;
-
- /* Process ServerHello extensions */
- extensionsLen = message.length - (38 + sessionIDLen);
-
- if(extensionsLen) {
- err = SSLProcessServerHelloExtensions(ctx, extensionsLen, p);
- if(err)
- return err;
- }
-
- /* RFC 5746: Make sure the renegotiation is secure */
- if(ctx->secure_renegotiation && !ctx->secure_renegotiation_received)
- return errSSLNegotiation;
-
- if(ctx->secure_renegotiation_received)
- ctx->secure_renegotiation = true;
-
-
- /*
- * Note: the server MAY send a SSL_HE_EC_PointFormats extension if
- * we've negotiated an ECDSA ciphersuite...but
- * a) the provided format list MUST contain SSL_PointFormatUncompressed per
- * RFC 4492 5.2; and
- * b) The uncompressed format is the only one we support.
- *
- * Thus we drop a possible incoming SSL_HE_EC_PointFormats extension here.
- * IF we ever support other point formats, we have to parse the extension
- * to see what the server supports.
- */
- return errSecSuccess;
-}
-
-OSStatus
-SSLEncodeClientHello(SSLRecord *clientHello, SSLContext *ctx)
-{
- size_t length;
- unsigned i;
- OSStatus err;
- unsigned char *p;
- SSLBuffer sessionIdentifier = { 0, NULL };
- size_t sessionIDLen;
- size_t sessionTicketLen = 0;
- size_t serverNameLen = 0;
- size_t pointFormatLen = 0;
- size_t suppCurveLen = 0;
- size_t signatureAlgorithmsLen = 0;
- size_t totalExtenLen = 0;
- UInt16 numCipherSuites;
- int head;
-
- assert(ctx->protocolSide == kSSLClientSide);
-
- clientHello->contents.length = 0;
- clientHello->contents.data = NULL;
-
- sessionIDLen = 0;
- if (ctx->resumableSession.data != 0)
- { if ((err = SSLRetrieveSessionID(ctx->resumableSession,
- &sessionIdentifier, ctx)) != 0)
- { return err;
- }
- sessionIDLen = sessionIdentifier.length;
- }
-
- /*
- * Since we're not in SSLv2 compatibility mode, only count non-SSLv2 ciphers.
- */
-#if ENABLE_SSLV2
- numCipherSuites = ctx->numValidNonSSLv2Specs;
-#else
- numCipherSuites = ctx->numValidCipherSuites;
-#endif
-
- /* RFC 5746 : add the fake ciphersuite unless we are including the extension */
- if(!ctx->secure_renegotiation)
- numCipherSuites+=1;
-
- length = 39 + 2*numCipherSuites + sessionIDLen;
-
- /* We always use the max enabled version in the ClientHello.client_version,
- even in the renegotiation case. This value is saved in the context so it
- can be used in the RSA key exchange */
- err = sslGetMaxProtVersion(ctx, &ctx->clientReqProtocol);
- if(err) {
- /* we don't have a protocol enabled */
- goto err_exit;
- }
-
- /* RFC 5746: If are starting a new handshake, so we didnt received this yet */
- ctx->secure_renegotiation_received = false;
-
- /* This is the protocol version used at the record layer, If we already
- negotiated the protocol version previously, we should just use that,
- otherwise we use the the minimum supported version.
- We do not always use the minimum version because some TLS only servers
- will reject an SSL 3 version in client_hello.
- */
- if(ctx->negProtocolVersion != SSL_Version_Undetermined) {
- clientHello->protocolVersion = ctx->negProtocolVersion;
- } else {
- if(ctx->minProtocolVersion<TLS_Version_1_0 && ctx->maxProtocolVersion>=TLS_Version_1_0)
- clientHello->protocolVersion = TLS_Version_1_0;
- else
- clientHello->protocolVersion = ctx->minProtocolVersion;
- }
-
-#if ENABLE_DTLS
- if(clientHello->protocolVersion == DTLS_Version_1_0) {
- /* extra space for cookie */
- /* TODO: cookie len - 0 for now */
- length += 1 + ctx->dtlsCookie.length;
- sslLogNegotiateDebug("==DTLS Hello: len=%lu\n", length);
- }
- /* Because of the way the version number for DTLS is encoded,
- the following code mean that you can use extensions with DTLS... */
-#endif /* ENABLE_DTLS */
-
- /* RFC 5746: We add the extension only for renegotiation ClientHello */
- if(ctx->secure_renegotiation) {
- totalExtenLen += 2 + /* extension type */
- 2 + /* extension length */
- 1 + /* lenght of renegotiated_conection (client verify data) */
- ctx->ownVerifyData.length;
- }
-
- /* prepare for optional ClientHello extensions */
- if((ctx->clientReqProtocol >= TLS_Version_1_0) &&
- (ctx->peerDomainName != NULL) &&
- (ctx->peerDomainNameLen != 0)) {
- serverNameLen = 2 + /* extension type */
- 2 + /* 2-byte vector length, extension_data */
- 2 + /* length of server_name_list */
- 1 + /* length of name_type */
- 2 + /* length of HostName */
- ctx->peerDomainNameLen;
- totalExtenLen += serverNameLen;
- }
- if(ctx->sessionTicket.length) {
- sessionTicketLen = 2 + /* extension type */
- 2 + /* 2-byte vector length, extension_data */
- ctx->sessionTicket.length;
- totalExtenLen += sessionTicketLen;
- }
- if((ctx->clientReqProtocol >= TLS_Version_1_0) &&
- (ctx->ecdsaEnable)) {
- /* Two more extensions: point format, supported curves */
- pointFormatLen = 2 + /* extension type */
- 2 + /* 2-byte vector length, extension_data */
- 1 + /* length of the ec_point_format_list */
- 1; /* the single format we support */
- suppCurveLen = 2 + /* extension type */
- 2 + /* 2-byte vector length, extension_data */
- 2 + /* length of the elliptic_curve_list */
- (2 * ctx->ecdhNumCurves); /* each curve is 2 bytes */
- totalExtenLen += (pointFormatLen + suppCurveLen);
- }
- if(ctx->isDTLS
- ? ctx->clientReqProtocol < DTLS_Version_1_0
- : ctx->clientReqProtocol >= TLS_Version_1_2) {
- signatureAlgorithmsLen = 2 + /* extension type */
- 2 + /* 2-byte vector length, extension_data */
- 2 + /* length of signatureAlgorithms list */
- 2 * (ctx->ecdsaEnable ? 5 : 3); //FIXME: 5:3 should not be hardcoded here.
- totalExtenLen += signatureAlgorithmsLen;
- }
- if(totalExtenLen != 0) {
- /*
- * Total length extensions have to fit in a 16 bit field...
- */
- if(totalExtenLen > 0xffff) {
- sslErrorLog("Total extensions length EXCEEDED\n");
- totalExtenLen = 0;
- sessionTicketLen = 0;
- serverNameLen = 0;
- pointFormatLen = 0;
- suppCurveLen = 0;
- signatureAlgorithmsLen = 0;
- }
- else {
- /* add length of total length plus lengths of extensions */
- length += (totalExtenLen + 2);
- }
- }
-
- clientHello->contentType = SSL_RecordTypeHandshake;
- head = SSLHandshakeHeaderSize(clientHello);
- if ((err = SSLAllocBuffer(&clientHello->contents, length + head)))
- goto err_exit;
-
- p = SSLEncodeHandshakeHeader(ctx, clientHello, SSL_HdskClientHello, length);
-
- p = SSLEncodeInt(p, ctx->clientReqProtocol, 2);
-
- sslLogNegotiateDebug("===SSL3 client: proclaiming max protocol "
- "%d_%d capable ONLY",
- ctx->clientReqProtocol >> 8, ctx->clientReqProtocol & 0xff);
- if ((err = SSLEncodeRandom(p, ctx)) != 0)
- { goto err_exit;
- }
- memcpy(ctx->clientRandom, p, SSL_CLIENT_SRVR_RAND_SIZE);
- p += 32;
- *p++ = sessionIDLen; /* 1 byte vector length */
- if (sessionIDLen > 0)
- { memcpy(p, sessionIdentifier.data, sessionIDLen);
- }
- p += sessionIDLen;
-#if ENABLE_DTLS
- if (ctx->clientReqProtocol == DTLS_Version_1_0) {
- /* TODO: Add the cookie ! Currently: size=0 -> no cookie */
- *p++ = ctx->dtlsCookie.length;
- if(ctx->dtlsCookie.length) {
- memcpy(p, ctx->dtlsCookie.data, ctx->dtlsCookie.length);
- p+=ctx->dtlsCookie.length;
- }
- sslLogNegotiateDebug("==DTLS Hello: cookie len = %d\n",(int)ctx->dtlsCookie.length);
- }
-#endif
-
-
- p = SSLEncodeInt(p, 2*numCipherSuites, 2);
- /* 2 byte long vector length */
-
- /* RFC 5746 : add the fake ciphersuite unless we are including the extension */
- if(!ctx->secure_renegotiation)
- p = SSLEncodeInt(p, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, 2);
-
- for (i = 0; i<ctx->numValidCipherSuites; ++i) {
-#if ENABLE_SSLV2
- if(CIPHER_SUITE_IS_SSLv2(ctx->validCipherSuites[i])) {
- continue;
- }
-#endif
- sslLogNegotiateDebug("ssl3EncodeClientHello sending suite %x",
- (unsigned)ctx->validCipherSuites[i]);
- p = SSLEncodeInt(p, ctx->validCipherSuites[i], 2);
- }
- *p++ = 1; /* 1 byte long vector */
- *p++ = 0; /* null compression */
-
- /*
- * Append ClientHello extensions.
- */
- if(totalExtenLen != 0) {
- /* first, total length of all extensions */
- p = SSLEncodeSize(p, totalExtenLen, 2);
- }
- if(ctx->secure_renegotiation){
- assert(ctx->ownVerifyData.length<=255);
- p = SSLEncodeInt(p, SSL_HE_SecureRenegotation, 2);
- p = SSLEncodeSize(p, ctx->ownVerifyData.length+1, 2);
- p = SSLEncodeSize(p, ctx->ownVerifyData.length, 1);
- memcpy(p, ctx->ownVerifyData.data, ctx->ownVerifyData.length);
- p += ctx->ownVerifyData.length;
- }
- if(sessionTicketLen) {
- sslEapDebug("Adding %lu bytes of sessionTicket to ClientHello",
- ctx->sessionTicket.length);
- p = SSLEncodeInt(p, SSL_HE_SessionTicket, 2);
- p = SSLEncodeSize(p, ctx->sessionTicket.length, 2);
- memcpy(p, ctx->sessionTicket.data, ctx->sessionTicket.length);
- p += ctx->sessionTicket.length;
- }
- if(serverNameLen) {
- sslEapDebug("Specifying ServerNameIndication");
- p = SSLEncodeInt(p, SSL_HE_ServerName, 2);
- p = SSLEncodeSize(p, ctx->peerDomainNameLen + 5, 2);
- p = SSLEncodeSize(p, ctx->peerDomainNameLen + 3, 2);
- p = SSLEncodeInt(p, SSL_NT_HostName, 1);
- p = SSLEncodeSize(p, ctx->peerDomainNameLen, 2);
- memcpy(p, ctx->peerDomainName, ctx->peerDomainNameLen);
- p += ctx->peerDomainNameLen;
- }
- if(suppCurveLen) {
- UInt32 len = 2 * ctx->ecdhNumCurves;
- unsigned dex;
- p = SSLEncodeInt(p, SSL_HE_EllipticCurves, 2);
- p = SSLEncodeSize(p, len+2, 2); /* length of extension data */
- p = SSLEncodeSize(p, len, 2); /* length of elliptic_curve_list */
- for(dex=0; dex<ctx->ecdhNumCurves; dex++) {
- sslEcdsaDebug("+++ adding supported curves %u to ClientHello",
- (unsigned)ctx->ecdhCurves[dex]);
- p = SSLEncodeInt(p, ctx->ecdhCurves[dex], 2);
- }
- }
- if(pointFormatLen) {
- sslEcdsaDebug("+++ adding point format to ClientHello");
- p = SSLEncodeInt(p, SSL_HE_EC_PointFormats, 2);
- p = SSLEncodeSize(p, 2, 2); /* length of extension data */
- p = SSLEncodeSize(p, 1, 1); /* length of ec_point_format_list */
- p = SSLEncodeInt(p, SSL_PointFormatUncompressed, 1);
- }
- if (signatureAlgorithmsLen) {
- sslEcdsaDebug("+++ adding signature algorithms to ClientHello");
- /* TODO: Don't hardcode this */
- /* We dont support SHA512 or SHA224 because we didnot implement the digest abstraction for those
- and we dont keep a running hash for those.
- We dont support SHA384/ECDSA because corecrypto ec does not support it with 256 bits curves */
- UInt32 len = 2 * (ctx->ecdsaEnable ? 5 : 3); //FIXME: 5:3 should not be hardcoded here.
- p = SSLEncodeInt(p, SSL_HE_SignatureAlgorithms, 2);
- p = SSLEncodeSize(p, len+2, 2); /* length of extension data */
- p = SSLEncodeSize(p, len, 2); /* length of extension data */
- // p = SSLEncodeInt(p, SSL_HashAlgorithmSHA512, 1);
- // p = SSLEncodeInt(p, SSL_SignatureAlgorithmRSA, 1);
- p = SSLEncodeInt(p, SSL_HashAlgorithmSHA384, 1);
- p = SSLEncodeInt(p, SSL_SignatureAlgorithmRSA, 1);
- p = SSLEncodeInt(p, SSL_HashAlgorithmSHA256, 1);
- p = SSLEncodeInt(p, SSL_SignatureAlgorithmRSA, 1);
- // p = SSLEncodeInt(p, SSL_HashAlgorithmSHA224, 1);
- // p = SSLEncodeInt(p, SSL_SignatureAlgorithmRSA, 1);
- p = SSLEncodeInt(p, SSL_HashAlgorithmSHA1, 1);
- p = SSLEncodeInt(p, SSL_SignatureAlgorithmRSA, 1);
- if (ctx->ecdsaEnable) {
- // p = SSLEncodeInt(p, SSL_HashAlgorithmSHA512, 1);
- // p = SSLEncodeInt(p, SSL_SignatureAlgorithmECDSA, 1);
- // p = SSLEncodeInt(p, SSL_HashAlgorithmSHA384, 1);
- // p = SSLEncodeInt(p, SSL_SignatureAlgorithmECDSA, 1);
- p = SSLEncodeInt(p, SSL_HashAlgorithmSHA256, 1);
- p = SSLEncodeInt(p, SSL_SignatureAlgorithmECDSA, 1);
- // p = SSLEncodeInt(p, SSL_HashAlgorithmSHA224, 1);
- // p = SSLEncodeInt(p, SSL_SignatureAlgorithmECDSA, 1);
- p = SSLEncodeInt(p, SSL_HashAlgorithmSHA1, 1);
- p = SSLEncodeInt(p, SSL_SignatureAlgorithmECDSA, 1);
- }
- }
-
- sslLogNegotiateDebug("Client Hello : data=%p p=%p len=%08lx\n", clientHello->contents.data, p, (unsigned long)clientHello->contents.length);
-
- assert(p == clientHello->contents.data + clientHello->contents.length);
-
- if ((err = SSLInitMessageHashes(ctx)) != 0)
- goto err_exit;
-
-err_exit:
- if (err != 0) {
- SSLFreeBuffer(&clientHello->contents);
- }
- SSLFreeBuffer(&sessionIdentifier);
-
- return err;
-}
-
-OSStatus
-SSLProcessClientHello(SSLBuffer message, SSLContext *ctx)
-{ OSStatus err;
- SSLProtocolVersion negVersion;
- UInt16 cipherListLen, cipherCount, desiredSuite, cipherSuite;
- UInt8 sessionIDLen, compressionCount;
- UInt8 *charPtr;
- unsigned i;
- UInt8 *eom; /* end of message */
-
- if (message.length < 41) {
- sslErrorLog("SSLProcessClientHello: msg len error 1\n");
- return errSSLProtocol;
- }
- charPtr = message.data;
- eom = charPtr + message.length;
- ctx->clientReqProtocol = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- err = sslVerifyProtVersion(ctx, ctx->clientReqProtocol, &negVersion);
- if(err) {
- sslErrorLog("SSLProcessClientHello: protocol version error %04x - %04x\n", ctx->clientReqProtocol, negVersion);
- return err;
- }
- switch(negVersion) {
- case SSL_Version_3_0:
- ctx->sslTslCalls = &Ssl3Callouts;
- break;
- case TLS_Version_1_0:
- case TLS_Version_1_1:
- case DTLS_Version_1_0:
- ctx->sslTslCalls = &Tls1Callouts;
- break;
- case TLS_Version_1_2:
- ctx->sslTslCalls = &Tls12Callouts;
- break;
- default:
- return errSSLNegotiation;
- }
- ctx->negProtocolVersion = negVersion;
- err = ctx->recFuncs->setProtocolVersion(ctx->recCtx, negVersion);
- if(err) {
- return err;
- }
- sslLogNegotiateDebug("===SSL3 server: negVersion is %d_%d",
- negVersion >> 8, negVersion & 0xff);
-
- memcpy(ctx->clientRandom, charPtr, SSL_CLIENT_SRVR_RAND_SIZE);
- charPtr += 32;
- sessionIDLen = *(charPtr++);
- if (message.length < (unsigned)(41 + sessionIDLen)) {
- sslErrorLog("SSLProcessClientHello: msg len error 2\n");
- return errSSLProtocol;
- }
- /* FIXME peerID is never set on server side.... */
- if (sessionIDLen > 0 && ctx->peerID.data != 0)
- { /* Don't die on error; just treat it as an uncacheable session */
- err = SSLAllocBuffer(&ctx->sessionID, sessionIDLen);
- if (err == 0)
- memcpy(ctx->sessionID.data, charPtr, sessionIDLen);
- }
- charPtr += sessionIDLen;
-
-#if ENABLE_DTLS
- /* TODO: actually do something with this cookie */
- if(negVersion==DTLS_Version_1_0) {
- UInt8 cookieLen = *charPtr++;
-
- sslLogNegotiateDebug("cookieLen=%d\n", cookieLen);
-
- if((ctx->dtlsCookie.length==0) || ((cookieLen==ctx->dtlsCookie.length) && (memcmp(ctx->dtlsCookie.data, charPtr, cookieLen)==0)))
- {
- ctx->cookieVerified=true;
- } else {
- ctx->cookieVerified=false;
- }
-
- charPtr+=cookieLen;
- }
-
- /* TODO: if we are about to send a HelloVerifyRequest, we probably dont need to process the cipherspecs */
-#endif
-
- cipherListLen = (UInt16)SSLDecodeInt(charPtr, 2);
- /* Count of cipherSuites, must be even & >= 2 */
- charPtr += 2;
- if((charPtr + cipherListLen) > eom) {
- sslErrorLog("SSLProcessClientHello: msg len error 5\n");
- return errSSLProtocol;
- }
- if ((cipherListLen & 1) ||
- (cipherListLen < 2) ||
- (message.length < (unsigned)(39 + sessionIDLen + cipherListLen))) {
- sslErrorLog("SSLProcessClientHello: msg len error 3\n");
- return errSSLProtocol;
- }
- cipherCount = cipherListLen/2;
- cipherSuite = 0xFFFF; /* No match marker */
- while (cipherSuite == 0xFFFF && cipherCount--)
- { desiredSuite = (UInt16)SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- for (i = 0; i <ctx->numValidCipherSuites; i++)
- { if (ctx->validCipherSuites[i] == desiredSuite)
- { cipherSuite = desiredSuite;
- break;
- }
- }
- }
-
- if (cipherSuite == 0xFFFF)
- return errSSLNegotiation;
- charPtr += 2 * cipherCount; /* Advance past unchecked cipherCounts */
- ctx->selectedCipher = cipherSuite;
- /* validate cipher later, after we get possible sessionTicket */
-
- compressionCount = *(charPtr++);
- if ((compressionCount < 1) ||
- (message.length <
- (unsigned)(38 + sessionIDLen + cipherListLen + compressionCount))) {
- sslErrorLog("SSLProcessClientHello: msg len error 4\n");
- return errSSLProtocol;
- }
- /* Ignore list; we're doing null */
-
- /*
- * Handle ClientHello extensions.
- */
- /* skip compression list */
- charPtr += compressionCount;
- if(charPtr < eom) {
- ptrdiff_t remLen = eom - charPtr;
- UInt32 totalExtensLen;
- UInt32 extenType;
- UInt32 extenLen;
- if(remLen < 6) {
- /*
- * Not enough for extension type and length, but not an error...
- * skip it and proceed.
- */
- sslEapDebug("SSLProcessClientHello: too small for any extension");
- goto proceed;
- }
- totalExtensLen = SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- if((charPtr + totalExtensLen) > eom) {
- sslEapDebug("SSLProcessClientHello: too small for specified total_extension_length");
- goto proceed;
- }
- while(charPtr < eom) {
- extenType = SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- extenLen = SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- if((charPtr + extenLen) > eom) {
- sslEapDebug("SSLProcessClientHello: too small for specified extension_length");
- break;
- }
- switch(extenType) {
-#if SSL_PAC_SERVER_ENABLE
-
- case SSL_HE_SessionTicket:
- SSLFreeBuffer(&ctx->sessionTicket);
- SSLCopyBufferFromData(charPtr, extenLen, &ctx->sessionTicket);
- sslEapDebug("Saved %lu bytes of sessionTicket from ClientHello",
- (unsigned long)extenLen);
- break;
-#endif
- case SSL_HE_ServerName:
- {
- /*
- * This is for debug only (it's disabled for Deployment builds).
- * Someday, I imagine we'll have a getter in the API to get this info.
- */
- UInt8 *cp = charPtr;
- UInt32 v = SSLDecodeInt(cp, 2);
- cp += 2;
- sslEapDebug("SSL_HE_ServerName: length of server_name_list %lu",
- (unsigned long)v);
- v = SSLDecodeInt(cp, 1);
- cp++;
- sslEapDebug("SSL_HE_ServerName: name_type %lu", (unsigned long)v);
- v = SSLDecodeInt(cp, 2);
- cp += 2;
- sslEapDebug("SSL_HE_ServerName: length of HostName %lu",
- (unsigned long)v);
- char hostString[v + 1];
- memmove(hostString, cp, v);
- hostString[v] = '\0';
- sslEapDebug("SSL_HE_ServerName: ServerName '%s'", hostString);
- break;
- }
- case SSL_HE_SignatureAlgorithms:
- {
- UInt8 *cp = charPtr;
-#ifndef NDEBUG
- UInt8 *end = charPtr + extenLen;
-#endif
- UInt32 sigAlgsSize = SSLDecodeInt(cp, 2);
- cp += 2;
-
- if (extenLen != sigAlgsSize + 2 || extenLen & 1 || sigAlgsSize & 1) {
- sslEapDebug("SSL_HE_SignatureAlgorithms: odd length of signature algorithms list %lu %lu",
- (unsigned long)extenLen, (unsigned long)sigAlgsSize);
- break;
- }
-
- ctx->numClientSigAlgs = sigAlgsSize / 2;
- if(ctx->clientSigAlgs != NULL) {
- sslFree(ctx->clientSigAlgs);
- }
- ctx->clientSigAlgs = (SSLSignatureAndHashAlgorithm *)
- sslMalloc((ctx->numClientSigAlgs) * sizeof(SSLSignatureAndHashAlgorithm));
- for(i=0; i<ctx->numClientSigAlgs; i++) {
- /* TODO: Validate hash and signature fields. */
- ctx->clientSigAlgs[i].hash = *cp++;
- ctx->clientSigAlgs[i].signature = *cp++;
- sslLogNegotiateDebug("===Client specifies sigAlg %d %d",
- ctx->clientSigAlgs[i].hash,
- ctx->clientSigAlgs[i].signature);
- }
- assert(cp==end);
- break;
- }
- default:
- sslEapDebug("SSLProcessClientHello: unknown extenType (%lu)",
- (unsigned long)extenType);
- break;
- }
- charPtr += extenLen;
- }
- }
-proceed:
- if ((err = FindCipherSpec(ctx)) != 0) {
- return err;
- }
- sslLogNegotiateDebug("ssl3 server: selecting cipherKind 0x%x", (unsigned)ctx->selectedCipher);
- if ((err = SSLInitMessageHashes(ctx)) != 0)
- return err;
-
- return errSecSuccess;
-}
-
-static
-OSStatus sslTime(uint32_t *tim)
-{
- time_t t;
- time(&t);
- *tim = (uint32_t)t;
- return errSecSuccess;
-}
-
-OSStatus
-SSLEncodeRandom(unsigned char *p, SSLContext *ctx)
-{ SSLBuffer randomData;
- OSStatus err;
- uint32_t now;
-
- if ((err = sslTime(&now)) != 0)
- return err;
- SSLEncodeInt(p, now, 4);
- randomData.data = p+4;
- randomData.length = 28;
- if((err = sslRand(&randomData)) != 0)
- return err;
- return errSecSuccess;
-}
-
-OSStatus
-SSLInitMessageHashes(SSLContext *ctx)
-{ OSStatus err;
-
- if ((err = CloseHash(&SSLHashSHA1, &ctx->shaState)) != 0)
- return err;
- if ((err = CloseHash(&SSLHashMD5, &ctx->md5State)) != 0)
- return err;
- if ((err = CloseHash(&SSLHashSHA256, &ctx->sha256State)) != 0)
- return err;
- if ((err = CloseHash(&SSLHashSHA384, &ctx->sha512State)) != 0)
- return err;
- if ((err = ReadyHash(&SSLHashSHA1, &ctx->shaState)) != 0)
- return err;
- if ((err = ReadyHash(&SSLHashMD5, &ctx->md5State)) != 0)
- return err;
- if ((err = ReadyHash(&SSLHashSHA256, &ctx->sha256State)) != 0)
- return err;
- if ((err = ReadyHash(&SSLHashSHA384, &ctx->sha512State)) != 0)
- return err;
- return errSecSuccess;
-}