X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_ssl/lib/sslHandshakeHello.c?ds=sidebyside diff --git a/libsecurity_ssl/lib/sslHandshakeHello.c b/libsecurity_ssl/lib/sslHandshakeHello.c deleted file mode 100644 index 81daee81..00000000 --- a/libsecurity_ssl/lib/sslHandshakeHello.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * 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 -#include -#include - -#include - -/* - * 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(remainingprotocolSide == 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->minProtocolVersionmaxProtocolVersion>=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; inumValidCipherSuites; ++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; dexecdhNumCurves; 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 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; inumClientSigAlgs; 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; -}