X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_ssl/lib/sslHandshake.c diff --git a/libsecurity_ssl/lib/sslHandshake.c b/libsecurity_ssl/lib/sslHandshake.c deleted file mode 100644 index 6914908e..00000000 --- a/libsecurity_ssl/lib/sslHandshake.c +++ /dev/null @@ -1,1383 +0,0 @@ -/* - * Copyright (c) 1999-2001,2005-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@ - */ - - -/* - * sslHandshake.c - SSL 3.0 handshake state machine. - */ - -#include "sslContext.h" -#include "sslHandshake.h" -#include "sslMemory.h" -#include "sslAlertMessage.h" -#include "sslSession.h" -#include "sslUtils.h" -#include "sslDebug.h" -#include "sslCrypto.h" -#include "sslRand.h" -#include "sslDigests.h" -#include "sslCipherSpecs.h" -#include "cipherSpecs.h" - -#include - -#include -#include -#include -#include - -#define REQUEST_CERT_CORRECT 0 - -#if __LP64__ -#define PRIstatus "d" -#else -#define PRIstatus "ld" -#endif - - -uint8_t * -SSLEncodeHandshakeHeader(SSLContext *ctx, SSLRecord *rec, SSLHandshakeType type, size_t msglen) -{ - uint8_t *charPtr; - - charPtr = rec->contents.data; - *charPtr++ = type; - charPtr = SSLEncodeSize(charPtr, msglen, 3); - - if(rec->protocolVersion == DTLS_Version_1_0) { - charPtr = SSLEncodeInt(charPtr, ctx->hdskMessageSeq, 2); - /* fragmentation -- we encode header as if unfragmented, - actual fragmentation happens at lower layer. */ - charPtr = SSLEncodeInt(charPtr, 0, 3); - charPtr = SSLEncodeSize(charPtr, msglen, 3); - } - - return charPtr; -} - -static OSStatus SSLProcessHandshakeMessage(SSLHandshakeMsg message, SSLContext *ctx); - -static OSStatus -SSLUpdateHandshakeMacs(const SSLBuffer *messageData, SSLContext *ctx) -{ - OSStatus err = errSSLInternal; - bool do_md5 = false; - bool do_sha1 = false; - bool do_sha256 = false; - bool do_sha384 = false; - - //TODO: We can stop updating the unecessary hashes once the CertVerify message is processed in case where we do Client Side Auth, or . - - if(ctx->negProtocolVersion == SSL_Version_Undetermined) - { - // we dont know yet, so we might need MD5 & SHA1 - Server should always call in with known protocol version. - assert(ctx->protocolSide==kSSLClientSide); - do_md5 = do_sha1 = true; - if(ctx->isDTLS - ? ctx->maxProtocolVersion < DTLS_Version_1_0 - : ctx->maxProtocolVersion >= TLS_Version_1_2) - { - // We wil need those too, unless we are sure we wont end up doing TLS 1.2 - do_sha256 = do_sha384 = true; - } - } else { - // we know which version we use at this point - if(sslVersionIsLikeTls12(ctx)) { - do_sha1 = do_sha256 = do_sha384 = true; - } else { - do_md5 = do_sha1 = true; - } - } - - if (do_md5 && - (err = SSLHashMD5.update(&ctx->md5State, messageData)) != 0) - goto done; - if (do_sha1 && - (err = SSLHashSHA1.update(&ctx->shaState, messageData)) != 0) - goto done; - if (do_sha256 && - (err = SSLHashSHA256.update(&ctx->sha256State, messageData)) != 0) - goto done; - if (do_sha384 && - (err = SSLHashSHA384.update(&ctx->sha512State, messageData)) != 0) - goto done; - - sslLogNegotiateDebug("%s protocol: %02X max: %02X cipher: %02X%s%s%s%s", - ctx->protocolSide == kSSLClientSide ? "client" : "server", - ctx->negProtocolVersion, - ctx->maxProtocolVersion, - ctx->selectedCipher, - do_md5 ? " md5" : "", - do_sha1 ? " sha1" : "", - do_sha256 ? " sha256" : "", - do_sha384 ? " sha384" : ""); -done: - return err; -} - -OSStatus -SSLProcessHandshakeRecord(SSLRecord rec, SSLContext *ctx) -{ OSStatus err; - size_t remaining; - UInt8 *p; - UInt8 *startingP; // top of record we're parsing - SSLHandshakeMsg message = {}; - SSLBuffer messageData; - - if (ctx->fragmentedMessageCache.data != 0) - { - size_t origLen = ctx->fragmentedMessageCache.length; - if ((err = SSLReallocBuffer(&ctx->fragmentedMessageCache, - ctx->fragmentedMessageCache.length + rec.contents.length)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - memcpy(ctx->fragmentedMessageCache.data + origLen, - rec.contents.data, rec.contents.length); - remaining = ctx->fragmentedMessageCache.length; - p = ctx->fragmentedMessageCache.data; - } - else - { remaining = rec.contents.length; - p = rec.contents.data; - } - startingP = p; - - size_t head = 4; - - while (remaining > 0) - { - if (remaining < head) - break; /* we must have at least a header */ - - messageData.data = p; - message.type = (SSLHandshakeType)*p++; - message.contents.length = SSLDecodeSize(p, 3); - - - p += 3; - - if ((message.contents.length + head) > remaining) - break; - - message.contents.data = p; - p += message.contents.length; - messageData.length = head + message.contents.length; - assert(p == messageData.data + messageData.length); - - /* message fragmentation */ - remaining -= messageData.length; - if ((err = SSLProcessHandshakeMessage(message, ctx)) != 0) - return err; - - if (message.type != SSL_HdskHelloRequest) - - { if ((err = SSLUpdateHandshakeMacs(&messageData, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - - if ((err = SSLAdvanceHandshake(message.type, ctx)) != 0) - return err; - } - - if (remaining > 0) /* Fragmented handshake message */ - { /* If there isn't a cache, allocate one */ - if (ctx->fragmentedMessageCache.data == 0) - { if ((err = SSLAllocBuffer(&ctx->fragmentedMessageCache, remaining))) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - if (startingP != ctx->fragmentedMessageCache.data) - { memcpy(ctx->fragmentedMessageCache.data, startingP, remaining); - ctx->fragmentedMessageCache.length = remaining; - } - } - else if (ctx->fragmentedMessageCache.data != 0) - { if ((err = SSLFreeBuffer(&ctx->fragmentedMessageCache))) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - - return errSecSuccess; -} - -OSStatus -DTLSProcessHandshakeRecord(SSLRecord rec, SSLContext *ctx) -{ OSStatus err = errSecParam; - size_t remaining; - UInt8 *p; - UInt8 *startingP; // top of record we're parsing - - const UInt32 head = 12; - - assert(ctx->isDTLS); - - remaining = rec.contents.length; - p = rec.contents.data; - startingP = p; - - while (remaining > 0) - { - UInt8 msgtype; - UInt32 msglen; - UInt32 msgseq; - UInt32 fraglen; - UInt32 fragofs; - - if (remaining < head) { - /* flush it - record is too small */ - sslErrorLog("DTLSProcessHandshakeRecord: remaining too small (%lu out of %lu)\n", remaining, rec.contents.length); - assert(0); // keep this assert until we find a test case that triggers it - err = errSSLProtocol; - goto flushit; - } - - /* Thats the 12 bytes of header : */ - msgtype = (SSLHandshakeType)*p++; - msglen = SSLDecodeInt(p, 3); p+=3; - msgseq = SSLDecodeInt(p, 2); p+=2; - fragofs = SSLDecodeInt(p, 3); p+=3; - fraglen = SSLDecodeInt(p, 3); p+=3; - - remaining -= head; - - SSLLogHdskMsg(msgtype, 0); - sslHdskMsgDebug("DTLS Hdsk Record: type=%u, len=%u, seq=%u (%u), f_ofs=%u, f_len=%u, remaining=%u", - msgtype, (int)msglen, (int)msgseq, (int)ctx->hdskMessageSeqNext, (int)fragofs, (int)fraglen, (int)remaining); - - if( - ((fraglen+fragofs) > msglen) - || (fraglen > remaining) - || (msgseq!=ctx->hdskMessageSeqNext) - || (fragofs!=ctx->hdskMessageCurrentOfs) - || (fragofs && (msgtype!=ctx->hdskMessageCurrent.type)) - || (fragofs && (msglen != ctx->hdskMessageCurrent.contents.length)) - ) - { - sslErrorLog("DTLSProcessHandshakeRecord: wrong fragment\n"); - // assert(0); // keep this assert until we find a test case that triggers it - // This is a recoverable error, we just drop this fragment. - // TODO: this should probably trigger a retransmit - err = errSecSuccess; - goto flushit; - } - - /* First fragment - allocate */ - if(fragofs==0) { - sslHdskMsgDebug("Allocating hdsk buf for msg type %d", msgtype); - assert(ctx->hdskMessageCurrent.contents.data==NULL); - assert(ctx->hdskMessageCurrent.contents.length==0); - if((err=SSLAllocBuffer(&(ctx->hdskMessageCurrent.contents), msglen))) { - SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - ctx->hdskMessageCurrent.type = msgtype; - } - - /* We have the next fragment, lets save it */ - memcpy(ctx->hdskMessageCurrent.contents.data + ctx->hdskMessageCurrentOfs, p, fraglen); - ctx->hdskMessageCurrentOfs+=fraglen; - p+=fraglen; - remaining-=fraglen; - - /* This was the last fragment, lets process the message */ - if(ctx->hdskMessageCurrentOfs == ctx->hdskMessageCurrent.contents.length) { - err = SSLProcessHandshakeMessage(ctx->hdskMessageCurrent, ctx); - if(err) - goto flushit; - - if ((msgtype != SSL_HdskHelloRequest) && (msgtype != SSL_HdskHelloVerifyRequest)) - { - /* We need to hash a fake header as if no fragmentation */ - uint8_t pseudo_header[head]; - SSLBuffer header; - header.data=pseudo_header; - header.length=head; - - pseudo_header[0]=msgtype; - SSLEncodeInt(pseudo_header+1, msglen, 3); - SSLEncodeInt(pseudo_header+4, msgseq, 2); - SSLEncodeInt(pseudo_header+6, 0, 3); - SSLEncodeInt(pseudo_header+9, msglen, 3); - - if ((err = SSLHashSHA1.update(&ctx->shaState, &header)) != 0 || - (err = SSLHashMD5.update(&ctx->md5State, &header)) != 0) - { - SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - goto flushit; - } - - SSLBuffer *messageData=&ctx->hdskMessageCurrent.contents; - if ((err = SSLHashSHA1.update(&ctx->shaState, messageData)) != 0 || - (err = SSLHashMD5.update(&ctx->md5State, messageData)) != 0) - { - SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - goto flushit; - } - - sslHdskMsgDebug("Hashing %d bytes of msg seq %d\n", (int)messageData->length, (int)msgseq); - } - - sslHdskMsgDebug("processed message of type %d", msgtype); - - if ((err = SSLAdvanceHandshake(msgtype, ctx)) != 0) - { - sslErrorLog("AdvanceHandshake error: %" PRIdOSStatus "\n", err); - goto flushit; - } - - /* Free the buffer for current message, and reset offset */ - SSLFreeBuffer(&(ctx->hdskMessageCurrent.contents)); - ctx->hdskMessageCurrentOfs=0; - - /* If we successfully processed a message, we wait for the next one */ - ctx->hdskMessageSeqNext++; - - } - - sslHdskMsgDebug("remaining = %ld", remaining); - } - - return errSecSuccess; - -flushit: - sslErrorLog("DTLSProcessHandshakeRecord: flusing record (err=%"PRIstatus")\n", err); - - /* This will flush the current handshake message */ - SSLFreeBuffer(&(ctx->hdskMessageCurrent.contents)); - ctx->hdskMessageCurrentOfs=0; - - return err; -} - -OSStatus -DTLSRetransmit(SSLContext *ctx) -{ - sslHdskMsgDebug("DTLSRetransmit in state %s. Last Sent = %d, Last Recv=%d, timeout=%f\n", - hdskStateToStr(ctx->state), ctx->hdskMessageSeq, ctx->hdskMessageSeqNext, ctx->timeout_duration); - - /* Too many retransmits, just give up!! */ - if(ctx->hdskMessageRetryCount>10) - return errSSLConnectionRefused; - - /* go back to previous cipher if retransmitting a flight including changecipherspec */ - if(ctx->messageQueueContainsChangeCipherSpec) { - OSStatus err; - err = ctx->recFuncs->rollbackWriteCipher(ctx->recCtx); - if(err) - return err; - } - - /* set timeout deadline */ - ctx->hdskMessageRetryCount++; - ctx->timeout_deadline = CFAbsoluteTimeGetCurrent()+((1<hdskMessageRetryCount)*ctx->timeout_duration); - - /* Lets resend the last flight */ - return SSLSendFlight(ctx); -} - -static OSStatus -SSLProcessHandshakeMessage(SSLHandshakeMsg message, SSLContext *ctx) -{ OSStatus err; - - err = errSecSuccess; - SSLLogHdskMsg(message.type, 0); - switch (message.type) - { case SSL_HdskHelloRequest: - if (ctx->protocolSide != kSSLClientSide) - goto wrongMessage; - if (message.contents.length > 0) - err = errSSLProtocol; - break; - case SSL_HdskClientHello: - if (ctx->state != SSL_HdskStateServerUninit) - goto wrongMessage; - err = SSLProcessClientHello(message.contents, ctx); - break; - case SSL_HdskServerHello: - if (ctx->state != SSL_HdskStateServerHello) - goto wrongMessage; - err = SSLProcessServerHello(message.contents, ctx); - break; -#if ENABLE_DTLS - case SSL_HdskHelloVerifyRequest: - if (ctx->protocolSide != kSSLClientSide) - goto wrongMessage; - if(ctx->state != SSL_HdskStateServerHello) - goto wrongMessage; - /* TODO: Do we need to check the client state here ? */ - err = SSLProcessServerHelloVerifyRequest(message.contents, ctx); - break; -#endif - case SSL_HdskCert: - if (ctx->state != SSL_HdskStateCert && - ctx->state != SSL_HdskStateClientCert) - goto wrongMessage; - err = SSLProcessCertificate(message.contents, ctx); - /* - * Note that cert evaluation can now be performed asynchronously, - * so SSLProcessCertificate may return errSSLWouldBlock here. - */ - break; - case SSL_HdskCertRequest: - if (((ctx->state != SSL_HdskStateHelloDone) && - (ctx->state != SSL_HdskStateKeyExchange)) - || ctx->certRequested) - goto wrongMessage; - err = SSLProcessCertificateRequest(message.contents, ctx); - if (ctx->breakOnCertRequest) - ctx->signalCertRequest = true; - break; - case SSL_HdskServerKeyExchange: - /* - * Since this message is optional for some key exchange - * mechanisms, and completely at the server's discretion, - * we need to be able to handle this in one of two states... - */ - switch(ctx->state) { - case SSL_HdskStateKeyExchange: /* explicitly waiting for this */ - case SSL_HdskStateHelloDone: - break; - default: - goto wrongMessage; - } - err = SSLProcessServerKeyExchange(message.contents, ctx); - break; - case SSL_HdskServerHelloDone: - if (ctx->state != SSL_HdskStateHelloDone) - goto wrongMessage; - err = SSLProcessServerHelloDone(message.contents, ctx); - break; - case SSL_HdskCertVerify: - if (ctx->state != SSL_HdskStateClientCertVerify) - goto wrongMessage; - err = SSLProcessCertificateVerify(message.contents, ctx); - assert(ctx->protocolSide == kSSLServerSide); - if(err) { - ctx->clientCertState = kSSLClientCertRejected; - } - break; - case SSL_HdskClientKeyExchange: - if (ctx->state != SSL_HdskStateClientKeyExchange) - goto wrongMessage; - err = SSLProcessKeyExchange(message.contents, ctx); - break; - case SSL_HdskFinished: - if (ctx->state != SSL_HdskStateFinished) - goto wrongMessage; - err = SSLProcessFinished(message.contents, ctx); - break; - default: - goto wrongMessage; - break; - } - - if (err && !ctx->sentFatalAlert) - { if (err == errSSLProtocol) - SSLFatalSessionAlert(SSL_AlertIllegalParam, ctx); - else if (err == errSSLNegotiation) - SSLFatalSessionAlert(SSL_AlertHandshakeFail, ctx); - else if (err != errSSLWouldBlock && - err != errSSLServerAuthCompleted /* == errSSLClientAuthCompleted */ && - err != errSSLClientCertRequested) - SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); - } - return err; - -wrongMessage: - SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx); - return errSSLProtocol; -} - -/* - * Given a server-side SSLContext that's fully restored for a resumed session, - * queue up the remaining outgoing messages to finish the handshake. - */ -static OSStatus -SSLResumeServerSide( - SSLContext *ctx) -{ - OSStatus err; - if ((err = SSLPrepareAndQueueMessage(SSLEncodeServerHello, ctx)) != 0) - return err; - if ((err = SSLInitPendingCiphers(ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - if ((err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, - ctx)) != 0) - return err; - - if ((err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, - ctx)) != 0) - return err; - - SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); - - return errSecSuccess; - -} - -OSStatus -SSLAdvanceHandshake(SSLHandshakeType processed, SSLContext *ctx) -{ OSStatus err; - SSLBuffer sessionIdentifier; - - SSLResetFlight(ctx); - - switch (processed) - { -#if ENABLE_DTLS - case SSL_HdskHelloVerifyRequest: - /* Just fall through */ -#endif - case SSL_HdskHelloRequest: - /* - * Reset the client auth state machine in case this is - * a renegotiation. - */ - ctx->certRequested = 0; - ctx->certSent = 0; - ctx->certReceived = 0; - ctx->x509Requested = 0; - ctx->clientCertState = kSSLClientCertNone; - ctx->readCipher_ready = 0; - ctx->writeCipher_ready = 0; - if ((err = SSLPrepareAndQueueMessage(SSLEncodeClientHello, ctx)) != 0) - return err; - SSLChangeHdskState(ctx, SSL_HdskStateServerHello); - break; - case SSL_HdskClientHello: - assert(ctx->protocolSide == kSSLServerSide); - ctx->sessionMatch = 0; - - if((ctx->negProtocolVersion==DTLS_Version_1_0) && (ctx->cookieVerified==false)) - { /* Send Hello Verify Request */ - if((err=SSLPrepareAndQueueMessage(SSLEncodeServerHelloVerifyRequest, ctx)) !=0 ) - return err; - break; - } - - #if SSL_PAC_SERVER_ENABLE - if((ctx->sessionTicket.data != NULL) && - (ctx->masterSecretCallback != NULL)) { - /* - * Client sent us a session ticket and we know how to ask - * the app for master secret. Go for it. - */ - size_t secretLen = SSL_MASTER_SECRET_SIZE; - sslEapDebug("Server side resuming based on masterSecretCallback"); - - /* the master secret callback requires serverRandom, now... */ - if ((err = SSLEncodeRandom(ctx->serverRandom, ctx)) != 0) - return err; - ctx->serverRandomValid = 1; - - ctx->masterSecretCallback(ctx, ctx->masterSecretArg, - ctx->masterSecret, &secretLen); - ctx->sessionMatch = 1; - /* set up selectedCipherSpec */ - if ((err = FindCipherSpec(ctx)) != 0) { - return err; - } - /* queue up remaining messages to finish handshake */ - if((err = SSLResumeServerSide(ctx)) != 0) - return err; - break; - } - #endif /* SSL_PAC_SERVER_ENABLE */ - if (ctx->sessionID.data != 0) - /* If session ID != 0, client is trying to resume */ - { if (ctx->resumableSession.data != 0) - { - SSLProtocolVersion sessionProt; - if ((err = SSLRetrieveSessionID(ctx->resumableSession, - &sessionIdentifier, ctx)) != 0) - return err; - if ((err = SSLRetrieveSessionProtocolVersion(ctx->resumableSession, - &sessionProt, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - if ((sessionIdentifier.length == ctx->sessionID.length) && - (memcmp(sessionIdentifier.data, ctx->sessionID.data, - ctx->sessionID.length) == 0) && - (sessionProt == ctx->negProtocolVersion)) - { /* Everything matches; resume the session */ - sslLogResumSessDebug("===RESUMING SSL3 server-side session"); - if ((err = SSLInstallSessionFromData(ctx->resumableSession, - ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - ctx->sessionMatch = 1; - SSLFreeBuffer(&sessionIdentifier); - - /* queue up remaining messages to finish handshake */ - if((err = SSLResumeServerSide(ctx)) != 0) - return err; - break; - } - else { - sslLogResumSessDebug( - "===FAILED TO RESUME SSL3 server-side session"); - } - if ((err = SSLFreeBuffer(&sessionIdentifier)) != 0 || - (err = SSLDeleteSessionData(ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - if ((err = SSLFreeBuffer(&ctx->sessionID)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - - /* - * If we get here, we're not resuming; generate a new session ID - * if we know our peer - */ - if (ctx->peerID.data != 0) - { /* Ignore errors; just treat as uncached session */ - assert(ctx->sessionID.data == 0); - err = SSLAllocBuffer(&ctx->sessionID, SSL_SESSION_ID_LEN); - if (err == 0) - { - if((err = sslRand(&ctx->sessionID)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - } - - if ((err = SSLPrepareAndQueueMessage(SSLEncodeServerHello, ctx)) != 0) - return err; - switch (ctx->selectedCipherSpecParams.keyExchangeMethod) - { case SSL_NULL_auth: - #if APPLE_DH - case SSL_DH_anon: - case SSL_ECDH_anon: - if(ctx->clientAuth == kAlwaysAuthenticate) { - /* app requires this; abort */ - SSLFatalSessionAlert(SSL_AlertHandshakeFail, ctx); - return errSSLNegotiation; - } - ctx->tryClientAuth = false; - /* DH server side needs work */ - break; - #endif /* APPLE_DH */ - case TLS_PSK: - /* skip the cert */ - break; - - case SSL_RSA: - case SSL_DH_DSS: - case SSL_DH_RSA: - case SSL_DHE_DSS: - case SSL_DHE_RSA: - case SSL_ECDH_ECDSA: - case SSL_ECDHE_ECDSA: - case SSL_ECDH_RSA: - case SSL_ECDHE_RSA: - if(ctx->localCert == NULL) { - /* no cert but configured for, and negotiated, a - * ciphersuite which requires one */ - sslErrorLog("SSLAdvanceHandshake: No server key!\n"); - return errSSLBadConfiguration; - } - if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, - ctx)) != 0) - return err; - break; - - default: /* everything else */ - sslErrorLog("SSLAdvanceHandshake: Unsupported KEM!\n"); - return errSSLInternal; - } - /* - * At this point we decide whether to send a server key exchange - * method. For Apple servers, I think we'll ALWAYS do this, because - * of key usage restrictions (can't decrypt and sign with the same - * private key), but conceptually in this code, we do it if - * enabled by the presence of encryptPrivKey. - */ - { - bool doServerKeyExch = false; - switch(ctx->selectedCipherSpecParams.keyExchangeMethod) { - case SSL_RSA: - if(ctx->encryptPrivKeyRef != NULL) { - doServerKeyExch = true; - } - break; - case SSL_DH_anon: - case SSL_DHE_RSA: - case SSL_DHE_DSS: - doServerKeyExch = true; - break; - default: /* In all other cases, we don't send a ServerkeyExchange message */ - break; - } - if(doServerKeyExch) { - err = SSLPrepareAndQueueMessage(SSLEncodeServerKeyExchange, ctx); - if(err) { - return err; - } - } - } - if (ctx->tryClientAuth) - { if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificateRequest, - ctx)) != 0) - return err; - ctx->certRequested = 1; - ctx->clientCertState = kSSLClientCertRequested; - } - if ((err = SSLPrepareAndQueueMessage(SSLEncodeServerHelloDone, ctx)) != 0) - return err; - if (ctx->certRequested) { - SSLChangeHdskState(ctx, SSL_HdskStateClientCert); - } - else { - SSLChangeHdskState(ctx, SSL_HdskStateClientKeyExchange); - } - break; - case SSL_HdskServerHello: - ctx->sessionMatch = 0; - if (ctx->resumableSession.data != 0 && ctx->sessionID.data != 0) - { - SSLProtocolVersion sessionProt; - if ((err = SSLRetrieveSessionID(ctx->resumableSession, - &sessionIdentifier, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - if ((err = SSLRetrieveSessionProtocolVersion(ctx->resumableSession, - &sessionProt, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - if ((sessionIdentifier.length == ctx->sessionID.length) && - (memcmp(sessionIdentifier.data, ctx->sessionID.data, - ctx->sessionID.length) == 0) && - (sessionProt == ctx->negProtocolVersion)) - { /* Everything matches; resume the session */ - sslLogResumSessDebug("===RESUMING SSL3 client-side session"); - if ((err = SSLInstallSessionFromData(ctx->resumableSession, - ctx)) != 0 || - (err = SSLInitPendingCiphers(ctx)) != 0 || - (err = SSLFreeBuffer(&sessionIdentifier)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - ctx->sessionMatch = 1; - SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); - break; - } - else { - sslLogResumSessDebug("===FAILED TO RESUME SSL3 client-side " - "session"); - } - if ((err = SSLFreeBuffer(&sessionIdentifier)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - } - switch (ctx->selectedCipherSpecParams.keyExchangeMethod) - { - /* these require a key exchange message */ - case SSL_NULL_auth: - case SSL_DH_anon: - SSLChangeHdskState(ctx, SSL_HdskStateKeyExchange); - break; - case SSL_RSA: - case SSL_DH_DSS: - case SSL_DH_RSA: - case SSL_RSA_EXPORT: - case SSL_DHE_DSS: - case SSL_DHE_RSA: - case SSL_Fortezza: - case SSL_ECDH_ECDSA: - case SSL_ECDHE_ECDSA: - case SSL_ECDH_RSA: - case SSL_ECDHE_RSA: - SSLChangeHdskState(ctx, SSL_HdskStateCert); - break; - case TLS_PSK: - SSLChangeHdskState(ctx, SSL_HdskStateHelloDone); - break; - default: - assert("Unknown key exchange method"); - break; - } - break; - case SSL_HdskCert: - if (ctx->state == SSL_HdskStateCert) - switch (ctx->selectedCipherSpecParams.keyExchangeMethod) - { case SSL_RSA: - /* - * I really think the two RSA cases should be - * handled the same here - the server key exchange is - * optional, and is up to the server. - * Note this isn't the same as SSL_SERVER_KEYEXCH_HACK; - * we're a client here. - */ - case SSL_DH_DSS: - case SSL_DH_RSA: - case SSL_ECDH_ECDSA: - case SSL_ECDH_RSA: - SSLChangeHdskState(ctx, SSL_HdskStateHelloDone); - break; - case SSL_DHE_DSS: - case SSL_DHE_RSA: - case SSL_Fortezza: - case SSL_ECDHE_ECDSA: - case SSL_ECDHE_RSA: - SSLChangeHdskState(ctx, SSL_HdskStateKeyExchange); - break; - default: - assert("Unknown or unexpected key exchange method"); - break; - } - else if (ctx->state == SSL_HdskStateClientCert) - { SSLChangeHdskState(ctx, SSL_HdskStateClientKeyExchange); - if (ctx->peerCert != 0) - ctx->certReceived = 1; - } - break; - case SSL_HdskCertRequest: - /* state stays in SSL_HdskStateHelloDone; distinction is in - * ctx->certRequested */ - if (ctx->peerCert == 0) - { SSLFatalSessionAlert(SSL_AlertHandshakeFail, ctx); - return errSSLProtocol; - } - assert(ctx->protocolSide == kSSLClientSide); - ctx->certRequested = 1; - ctx->clientCertState = kSSLClientCertRequested; - break; - case SSL_HdskServerKeyExchange: - SSLChangeHdskState(ctx, SSL_HdskStateHelloDone); - break; - case SSL_HdskServerHelloDone: - /* - * Waiting until server has sent hello done to interrupt and allow - * setting client cert, so we can send certificate, keyexchange and - * cert verify message together - */ - if (ctx->state != SSL_HdskStateClientCert) { - if (ctx->signalServerAuth) { - ctx->signalServerAuth = false; - SSLChangeHdskState(ctx, SSL_HdskStateClientCert); - return errSSLServerAuthCompleted; - } else if (ctx->signalCertRequest) { - ctx->signalCertRequest = false; - SSLChangeHdskState(ctx, SSL_HdskStateClientCert); - return errSSLClientCertRequested; - } else if (ctx->signalClientAuth) { - ctx->signalClientAuth = false; - return errSSLClientAuthCompleted; - } - } - - if (ctx->clientCertState == kSSLClientCertRequested) { - /* - * Server wants a client authentication cert - do - * we have one? - */ - if (ctx->localCert != 0 && ctx->x509Requested) { - if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, - ctx)) != 0) { - return err; - } - } - else { - /* response for no cert depends on protocol version */ - if(ctx->negProtocolVersion >= TLS_Version_1_0) { - /* TLS: send empty cert msg */ - if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, - ctx)) != 0) { - return err; - } - } - else { - /* SSL3: "no cert" alert */ - if ((err = SSLSendAlert(SSL_AlertLevelWarning, SSL_AlertNoCert_RESERVED, - ctx)) != 0) { - return err; - } - } - } /* no cert to send */ - } /* server requested a cert */ - if ((err = SSLPrepareAndQueueMessage(SSLEncodeKeyExchange, ctx)) != 0) - return err; - assert(ctx->sslTslCalls != NULL); - if ((err = ctx->sslTslCalls->generateMasterSecret(ctx)) != 0 || - (err = SSLInitPendingCiphers(ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - memset(ctx->preMasterSecret.data, 0, ctx->preMasterSecret.length); - if ((err = SSLFreeBuffer(&ctx->preMasterSecret))) { - return err; - } - if (ctx->certSent) { - /* Not all client auth mechanisms require a cert verify message */ - switch(ctx->negAuthType) { - case SSLClientAuth_RSASign: - case SSLClientAuth_ECDSASign: - if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificateVerify, - ctx)) != 0) { - return err; - } - break; - default: - break; - } - } - if ((err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, - ctx)) != 0) { - return err; - } - if ((err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0) - return err; - SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); - break; - case SSL_HdskCertVerify: - SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); - break; - case SSL_HdskClientKeyExchange: - assert(ctx->sslTslCalls != NULL); - if ((err = ctx->sslTslCalls->generateMasterSecret(ctx)) != 0 || - (err = SSLInitPendingCiphers(ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - memset(ctx->preMasterSecret.data, 0, ctx->preMasterSecret.length); - if ((err = SSLFreeBuffer(&ctx->preMasterSecret))) - return err; - if (ctx->certReceived) { - SSLChangeHdskState(ctx, SSL_HdskStateClientCertVerify); - } - else { - SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); - } - break; - case SSL_HdskFinished: - /* Handshake is over; enable data transfer on read channel */ - ctx->readCipher_ready = 1; - /* If writePending is set, we haven't yet sent a finished message; - * send it */ - /* Note: If using session resumption, the client will hit this, otherwise the server will */ - if (ctx->writePending_ready != 0) - { if ((err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, - ctx)) != 0) - return err; - if ((err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, - ctx)) != 0) - return err; - } - if (ctx->protocolSide == kSSLServerSide) { - SSLChangeHdskState(ctx, SSL_HdskStateServerReady); - } - else { - SSLChangeHdskState(ctx, SSL_HdskStateClientReady); - } - if ((ctx->peerID.data != 0) && (ctx->sessionTicket.data == NULL)) { - /* note we avoid caching session data for PAC-style resumption */ - SSLAddSessionData(ctx); - } - break; - default: - assert(0); - break; - } - - /* We should have a full flight when we reach here, sending it for the first time */ - ctx->hdskMessageRetryCount = 0; - ctx->timeout_deadline = CFAbsoluteTimeGetCurrent() + ctx->timeout_duration; - return SSLSendFlight(ctx); -} - -OSStatus -SSLPrepareAndQueueMessage(EncodeMessageFunc msgFunc, SSLContext *ctx) -{ OSStatus err; - SSLRecord rec = {0, 0, {0, NULL}}; - WaitingMessage *out; - WaitingMessage *queue; - - if ((err = msgFunc(&rec, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); - goto fail; - } - - if (rec.contentType == SSL_RecordTypeHandshake) - { - if ((err = SSLUpdateHandshakeMacs(&rec.contents, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - goto fail; - } - SSLLogHdskMsg((SSLHandshakeType)rec.contents.data[0], 1); - ctx->hdskMessageSeq++; - } - - err=errSSLInternal; - out = (WaitingMessage *)sslMalloc(sizeof(WaitingMessage)); - if(out==NULL) goto fail; - - out->next = NULL; - out->rec = rec; - - queue=ctx->messageWriteQueue; - if (queue == NULL) { - sslHdskMsgDebug("Queuing first message in flight\n"); - ctx->messageWriteQueue = out; - } else { - int n=1; - while (queue->next != 0) { - queue = queue->next; - n++; - } - sslHdskMsgDebug("Queuing message %d in flight\n", n); - queue->next = out; - } - - return errSecSuccess; -fail: - SSLFreeBuffer(&rec.contents); - return err; -} - -static -OSStatus SSLSendMessage(SSLRecord rec, SSLContext *ctx) -{ - OSStatus err; - - - if ((err = SSLWriteRecord(rec, ctx)) != 0) - return err; - if(rec.contentType == SSL_RecordTypeChangeCipher) { - /* Install new cipher spec on write side */ - /* Can't send data until Finished is sent */ - ctx->writeCipher_ready = 0; - ctx->wroteAppData = 0; - - if ((err = ctx->recFuncs->advanceWriteCipher(ctx->recCtx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - - /* pending cipher is invalid now - this is currently used to figure out if we need - to send out the last flight */ - ctx->writePending_ready = 0; - - /* TODO: that should only happen after Finished message is sent. */ - ctx->writeCipher_ready = 1; - } - - return errSecSuccess; -} - -static -OSStatus DTLSSendMessage(SSLRecord rec, SSLContext *ctx) -{ - OSStatus err=errSecSuccess; - - if(rec.contentType != SSL_RecordTypeHandshake) { - sslHdskMsgDebug("Not fragmenting message type=%d len=%d\n", (int)rec.contentType, (int)rec.contents.length); - if ((err = SSLWriteRecord(rec, ctx)) != 0) - return err; - if(rec.contentType == SSL_RecordTypeChangeCipher) { - /* Can't send data until Finished is sent */ - ctx->writeCipher_ready = 0; - ctx->wroteAppData = 0; - - /* Install new cipher spec on write side */ - if ((err = ctx->recFuncs->advanceWriteCipher(ctx->recCtx)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - - /* pending cipher is invalid now - this is currently used to figure out if we need - to send out the last flight */ - ctx->writePending_ready = 0; - - /* TODO: that should only happen after Finished message is sent. See */ - ctx->writeCipher_ready = 1; - - } - } else { - /* fragmenting */ - SSLRecord fragrec; - - int msghead = 12; /* size of message header in DTLS */ - size_t fraglen; - size_t len = rec.contents.length-msghead; - UInt32 seq = SSLDecodeInt(rec.contents.data+4, 2); - (void) seq; // Suppress warnings - size_t ofs = 0; - - sslHdskMsgDebug("Fragmenting msg seq %d (rl=%d, ml=%d)", (int)seq, (int)rec.contents.length, - SSLDecodeInt(rec.contents.data+1, 3)); - - - SSLGetDatagramWriteSize(ctx, &fraglen); - fraglen -= msghead; - - fragrec.contentType = rec.contentType; - fragrec.protocolVersion = rec.protocolVersion; - if((err=SSLAllocBuffer(&fragrec.contents, fraglen + msghead))) - return err; - - /* copy the constant part of the header */ - memcpy(fragrec.contents.data,rec.contents.data, 6); - - while(len>fraglen) { - - sslHdskMsgDebug("Fragmenting msg seq %d (o=%d,l=%d)", (int)seq, (int)ofs, (int)fraglen); - - /* fragment offset and fragment length */ - SSLEncodeSize(fragrec.contents.data+6, ofs, 3); - SSLEncodeSize(fragrec.contents.data+9, fraglen, 3); - /* copy the payload */ - memcpy(fragrec.contents.data+msghead, rec.contents.data+msghead+ofs, fraglen); - if ((err = SSLWriteRecord(fragrec, ctx)) != 0) - goto cleanup; - len-=fraglen; - ofs+=fraglen; - } - - sslHdskMsgDebug("Fragmenting msg seq %d - Last Fragment (o=%d,l=%d)", (int)seq, (int)ofs, (int)len); - - /* last fragment */ - /* fragment offset and fragment length */ - SSLEncodeSize(fragrec.contents.data+6, ofs, 3); - SSLEncodeSize(fragrec.contents.data+9, len, 3); - /* copy the payload */ - memcpy(fragrec.contents.data+msghead, rec.contents.data+msghead+ofs, len); - fragrec.contents.length=len+msghead; - err = SSLWriteRecord(fragrec, ctx); - - cleanup: - /* Free the allocated fragment buffer */ - SSLFreeBuffer(&fragrec.contents); - - } - - return err; -} - - -OSStatus SSLResetFlight(SSLContext *ctx) -{ - OSStatus err; - WaitingMessage *queue; - WaitingMessage *next; - int n=0; - - queue=ctx->messageWriteQueue; - ctx->messageQueueContainsChangeCipherSpec=false; - - while(queue) { - n++; - err = SSLFreeBuffer(&queue->rec.contents); - if (err != 0) - goto fail; - next=queue->next; - sslFree(queue); - queue=next; - } - - ctx->messageWriteQueue=NULL; - - return errSecSuccess; -fail: - check_noerr(err); - return err; -} - -OSStatus SSLSendFlight(SSLContext *ctx) -{ - OSStatus err; - WaitingMessage *queue; - int n=0; - - queue=ctx->messageWriteQueue; - - while(queue) { - if (ctx->isDTLS) { - err=DTLSSendMessage(queue->rec, ctx); - } else { - err=SSLSendMessage(queue->rec, ctx); - } - if (err != 0) - goto fail; - queue=queue->next; - n++; - } - - return errSecSuccess; -fail: - check_noerr(err); - return err; -} - -OSStatus -SSL3ReceiveSSL2ClientHello(SSLRecord rec, SSLContext *ctx) -{ OSStatus err; - - if ((err = SSLInitMessageHashes(ctx)) != 0) - return err; - - if ((err = SSLHashSHA1.update(&ctx->shaState, &rec.contents)) != 0 || - (err = SSLHashMD5.update(&ctx->md5State, &rec.contents)) != 0) - { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); - return err; - } - - if ((err = SSLAdvanceHandshake(SSL_HdskClientHello, ctx)) != 0) - return err; - - return errSecSuccess; -} - -/* - * Determine max enabled protocol, i.e., the one we try to negotiate for. - * Only returns an error (errSecParam) if NO protocols are enabled, which can - * in fact happen by malicious or ignorant use of SSLSetProtocolVersionEnabled(). - */ -OSStatus sslGetMaxProtVersion( - SSLContext *ctx, - SSLProtocolVersion *version) // RETURNED -{ - /* This check is here until SSLSetProtocolVersionEnabled() is gone .*/ - if (ctx->maxProtocolVersion == SSL_Version_Undetermined) - return errSecBadReq; - - *version = ctx->maxProtocolVersion; - return errSecSuccess; -} - - -/* log changes in handshake state */ -#ifndef NDEBUG -#include - -char *hdskStateToStr(SSLHandshakeState state) -{ - static char badStr[100]; - - switch(state) { - case SSL_HdskStateUninit: - return "Uninit"; - case SSL_HdskStateServerUninit: - return "ServerUninit"; - case SSL_HdskStateClientUninit: - return "ClientUninit"; - case SSL_HdskStateGracefulClose: - return "GracefulClose"; - case SSL_HdskStateErrorClose: - return "ErrorClose"; - case SSL_HdskStateNoNotifyClose: - return "NoNotifyClose"; - case SSL_HdskStateServerHello: - return "ServerHello"; - case SSL_HdskStateKeyExchange: - return "KeyExchange"; - case SSL_HdskStateCert: - return "Cert"; - case SSL_HdskStateHelloDone: - return "HelloDone"; - case SSL_HdskStateClientCert: - return "ClientCert"; - case SSL_HdskStateClientKeyExchange: - return "ClientKeyExchange"; - case SSL_HdskStateClientCertVerify: - return "ClientCertVerify"; - case SSL_HdskStateChangeCipherSpec: - return "ChangeCipherSpec"; - case SSL_HdskStateFinished: - return "Finished"; - case SSL_HdskStateServerReady: - return "SSL_ServerReady"; - case SSL_HdskStateClientReady: - return "SSL_ClientReady"; - default: - sprintf(badStr, "Unknown state (%d(d)", state); - return badStr; - } -} - -/* This is a macro in Release mode */ -void SSLChangeHdskState(SSLContext *ctx, SSLHandshakeState newState) -{ - sslHdskStateDebug("...hdskState = %s", hdskStateToStr(newState)); - ctx->state = newState; -} - -/* log handshake messages */ - -static char *hdskMsgToStr(SSLHandshakeType msg) -{ - static char badStr[100]; - - switch(msg) { - case SSL_HdskHelloRequest: - return "SSL_HdskHelloRequest"; - case SSL_HdskClientHello: - return "SSL_HdskClientHello"; - case SSL_HdskServerHello: - return "SSL_HdskServerHello"; - case SSL_HdskHelloVerifyRequest: - return "SSL_HdskHelloVerifyRequest"; - case SSL_HdskCert: - return "SSL_HdskCert"; - case SSL_HdskServerKeyExchange: - return "SSL_HdskServerKeyExchange"; - case SSL_HdskCertRequest: - return "SSL_HdskCertRequest"; - case SSL_HdskServerHelloDone: - return "SSL_HdskServerHelloDone"; - case SSL_HdskCertVerify: - return "SSL_HdskCertVerify"; - case SSL_HdskClientKeyExchange: - return "SSL_HdskClientKeyExchange"; - case SSL_HdskFinished: - return "SSL_HdskFinished"; - default: - sprintf(badStr, "Unknown msg (%d(d))", msg); - return badStr; - } -} - -void SSLLogHdskMsg(SSLHandshakeType msg, char sent) -{ - sslHdskMsgDebug("---%s handshake msg %s", - hdskMsgToStr(msg), (sent ? "sent" : "recv")); -} - -#endif /* NDEBUG */ -