X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_ssl/lib/sslTransport.c diff --git a/Security/libsecurity_ssl/lib/sslTransport.c b/Security/libsecurity_ssl/lib/sslTransport.c deleted file mode 100644 index c7627b3c..00000000 --- a/Security/libsecurity_ssl/lib/sslTransport.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (c) 1999-2001,2005-2014 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@ - */ - -/* - * sslTransport.c - SSL transport layer - */ - -#include "ssl.h" -#include "sslMemory.h" -#include "sslContext.h" -#include "sslRecord.h" -#include "sslAlertMessage.h" -#include "sslSession.h" -#include "sslDebug.h" -#include "sslCipherSpecs.h" -#include "sslUtils.h" - -#include -#include - -#include - -#ifndef NDEBUG -static inline void sslIoTrace( - SSLContext *ctx, - const char *op, - size_t req, - size_t moved, - OSStatus stat) -{ - sslLogRecordIo("[%p] ===%s: req %4lu moved %4lu status %d", - ctx, op, req, moved, (int)stat); -} -#else -#define sslIoTrace(ctx, op, req, moved, stat) -#endif /* NDEBUG */ - -extern int kSplitDefaultValue; - -static OSStatus SSLProcessProtocolMessage(SSLRecord *rec, SSLContext *ctx); -static OSStatus SSLHandshakeProceed(SSLContext *ctx); -//static OSStatus SSLInitConnection(SSLContext *ctx); - -OSStatus -SSLWrite( - SSLContext *ctx, - const void * data, - size_t dataLength, - size_t *bytesWritten) /* RETURNED */ -{ - OSStatus err; - SSLRecord rec; - size_t dataLen, processed; - - sslLogRecordIo("[%p] SSLWrite top", ctx); - if((ctx == NULL) || (bytesWritten == NULL)) { - return errSecParam; - } - dataLen = dataLength; - processed = 0; /* Initialize in case we return with errSSLWouldBlock */ - *bytesWritten = 0; - - switch(ctx->state) { - case SSL_HdskStateGracefulClose: - err = errSSLClosedGraceful; - goto abort; - case SSL_HdskStateErrorClose: - err = errSSLClosedAbort; - goto abort; - case SSL_HdskStateReady: - break; - case SSL_HdskStateUninit: - /* not ready for I/O, and handshake not in progress */ - sslIoTrace(ctx, "SSLWrite(1)", dataLength, 0, errSecBadReq); - return errSecBadReq; - default: - /* handshake in progress or done. Will call SSLHandshakeProceed below if necessary */ - break; - } - - /* First, we have to wait until the session is ready to send data, - so the encryption keys and such have been established. */ - err = errSecSuccess; - while (!(ctx->writeCipher_ready)) - { if ((err = SSLHandshakeProceed(ctx)) != 0) - goto exit; - } - - /* Attempt to empty the write queue before queueing more data */ - if ((err = SSLServiceWriteQueue(ctx)) != 0) - goto abort; - - processed = 0; - - /* Skip empty writes, fragmentation is done at the coreTLS layer */ - if(dataLen) { - rec.contentType = SSL_RecordTypeAppData; - rec.protocolVersion = ctx->negProtocolVersion; - rec.contents.data = ((uint8_t *)data) + processed; - rec.contents.length = dataLen; - if ((err = SSLWriteRecord(rec, ctx)) != 0) - goto exit; - processed += rec.contents.length; - } - - /* All the data has been advanced to the write queue */ - *bytesWritten = processed; - if ((err = SSLServiceWriteQueue(ctx)) == 0) { - err = errSecSuccess; - } -exit: - switch(err) { - case errSecSuccess: - case errSSLWouldBlock: - case errSSLUnexpectedRecord: - case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */ - case errSSLClientCertRequested: - case errSSLClosedGraceful: - break; - default: - sslErrorLog("SSLWrite: going to state errorClose due to err %d\n", - (int)err); - SSLChangeHdskState(ctx, SSL_HdskStateErrorClose); - break; - } -abort: - sslIoTrace(ctx, "SSLWrite(2)", dataLength, *bytesWritten, err); - return err; -} - -OSStatus -SSLRead ( - SSLContext *ctx, - void * data, - size_t dataLength, - size_t *processed) /* RETURNED */ -{ - OSStatus err; - uint8_t *charPtr; - size_t bufSize, remaining, count; - SSLRecord rec; - - sslLogRecordIo("[%p] SSLRead top (dataLength=%ld)", ctx, dataLength); - if((ctx == NULL) || (data == NULL) || (processed == NULL)) { - return errSecParam; - } - bufSize = dataLength; - *processed = 0; /* Initialize in case we return with errSSLWouldBlock */ - -readRetry: - /* first handle cases in which we know we're finished */ - switch(ctx->state) { - case SSL_HdskStateGracefulClose: - err = errSSLClosedGraceful; - goto abort; - case SSL_HdskStateErrorClose: - err = errSSLClosedAbort; - goto abort; - case SSL_HdskStateNoNotifyClose: - err = errSSLClosedNoNotify; - goto abort; - default: - break; - } - - /* First, we have to wait until the session is ready to receive data, - so the encryption keys and such have been established. */ - err = errSecSuccess; - while (ctx->readCipher_ready == 0) { - if ((err = SSLHandshakeProceed(ctx)) != 0) { - goto exit; - } - } - - /* Attempt to service the write queue */ - if ((err = SSLServiceWriteQueue(ctx)) != 0) { - if (err != errSSLWouldBlock) { - goto exit; - } - err = errSecSuccess; /* Write blocking shouldn't stop attempts to read */ - } - - remaining = bufSize; - charPtr = (uint8_t *)data; - if (ctx->receivedDataBuffer.data) - { count = ctx->receivedDataBuffer.length - ctx->receivedDataPos; - if (count > bufSize) - count = bufSize; - memcpy(data, ctx->receivedDataBuffer.data + ctx->receivedDataPos, count); - remaining -= count; - charPtr += count; - *processed += count; - ctx->receivedDataPos += count; - } - - assert(ctx->receivedDataPos <= ctx->receivedDataBuffer.length); - assert(*processed + remaining == bufSize); - assert(charPtr == ((uint8_t *)data) + *processed); - - if (ctx->receivedDataBuffer.data != 0 && - ctx->receivedDataPos >= ctx->receivedDataBuffer.length) - { SSLFreeBuffer(&ctx->receivedDataBuffer); - ctx->receivedDataBuffer.data = 0; - ctx->receivedDataPos = 0; - } - - /* - * This while statement causes a hang when using nonblocking low-level I/O! - while (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose) - ..what we really have to do is just return as soon as we read one - record. A performance hit in the nonblocking case, but that is - the only way this code can work in both modes... - */ - if (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose) - { assert(ctx->receivedDataBuffer.data == 0); - if ((err = SSLReadRecord(&rec, ctx)) != 0) { - goto exit; - } - if (rec.contentType == SSL_RecordTypeAppData || - rec.contentType == SSL_RecordTypeV2_0) - { if (rec.contents.length <= remaining) - { memcpy(charPtr, rec.contents.data, rec.contents.length); - remaining -= rec.contents.length; - charPtr += rec.contents.length; - *processed += rec.contents.length; - { - if ((err = SSLFreeRecord(rec, ctx))) { - goto exit; - } - } - } - else - { memcpy(charPtr, rec.contents.data, remaining); - charPtr += remaining; - *processed += remaining; - ctx->receivedDataBuffer = rec.contents; - ctx->receivedDataPos = remaining; - remaining = 0; - } - } - else { - if ((err = SSLProcessProtocolMessage(&rec, ctx)) != 0) { - /* This may not make much sense, but this is required so that we - process the write queue. This replicate exactly the behavior - before the coreTLS adoption */ - if(err == errSSLClosedGraceful) { - err = SSLClose(ctx); - } else { - goto exit; - } - } - if ((err = SSLFreeRecord(rec, ctx))) { - goto exit; - } - } - } - - err = errSecSuccess; - -exit: - /* test for renegotiate: loop until something useful happens */ - if(((err == errSecSuccess) && (*processed == 0) && dataLength) || (err == errSSLUnexpectedRecord)) { - sslLogNegotiateDebug("SSLRead recursion"); - goto readRetry; - } - /* shut down on serious errors */ - switch(err) { - case errSecSuccess: - case errSSLWouldBlock: - case errSSLUnexpectedRecord: - case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */ - case errSSLClientCertRequested: - case errSSLClosedGraceful: - case errSSLClosedNoNotify: - break; - default: - sslErrorLog("SSLRead: going to state errorClose due to err %d\n", - (int)err); - SSLChangeHdskState(ctx, SSL_HdskStateErrorClose); - break; - } -abort: - sslIoTrace(ctx, "SSLRead returns", dataLength, *processed, err); - return err; -} - -#if SSL_DEBUG -#include "sslCrypto.h" -#endif - -OSStatus -SSLHandshake(SSLContext *ctx) -{ - OSStatus err; - - if(ctx == NULL) { - return errSecParam; - } - if (ctx->state == SSL_HdskStateGracefulClose) - return errSSLClosedGraceful; - if (ctx->state == SSL_HdskStateErrorClose) - return errSSLClosedAbort; - - if(ctx->validCipherSuites == NULL) { - /* build list of legal cipherSpecs */ - err = sslBuildCipherSuiteArray(ctx); - if(err) { - return err; - } - } - - err = errSecSuccess; - - if(ctx->isDTLS && ctx->timeout_deadline) { - CFAbsoluteTime current = CFAbsoluteTimeGetCurrent(); - - if (ctx->timeout_deadlinehdsk); - if(err) { - return err; - } - } - } - - while (ctx->readCipher_ready == 0 || ctx->writeCipher_ready == 0) - { - err = SSLHandshakeProceed(ctx); - if((err != 0) && (err != errSSLUnexpectedRecord)) - return err; - } - - /* one more flush at completion of successful handshake */ - if ((err = SSLServiceWriteQueue(ctx)) != 0) { - return err; - } - - return errSecSuccess; -} - - -static OSStatus -SSLHandshakeProceed(SSLContext *ctx) -{ - OSStatus err; - - - if(ctx->state==SSL_HdskStateUninit) { - /* If we are the client, we start the negotiation */ - if(ctx->protocolSide == kSSLClientSide) { - err = tls_handshake_negotiate(ctx->hdsk, &ctx->peerID); - if(err) - return err; - } - SSLChangeHdskState(ctx, SSL_HdskStatePending); - } - - if ((err = tls_handshake_continue(ctx->hdsk)) != 0) - return err; - - if ((err = SSLServiceWriteQueue(ctx)) != 0) - return err; - - SSLRecord rec; - - err = SSLReadRecord(&rec, ctx); - - if(!err) { - sslDebugLog("%p going to process a record (rec.len=%zd, ct=%d)\n", ctx, rec.contents.length, rec.contentType); - err = tls_handshake_process(ctx->hdsk, rec.contents, rec.contentType); - sslDebugLog("%p processed a record (rec.len=%zd, ct=%d, err=%d)\n", ctx, rec.contents.length, rec.contentType, (int)err); - SSLFreeRecord(rec, ctx); - } else if(err!=errSSLWouldBlock) { - sslDebugLog("%p Read error err=%d\n\n", ctx, (int)err); - } - - return err; -} - -static OSStatus -SSLProcessProtocolMessage(SSLRecord *rec, SSLContext *ctx) -{ - return tls_handshake_process(ctx->hdsk, rec->contents, rec->contentType); -} - -OSStatus -SSLClose(SSLContext *ctx) -{ - OSStatus err = errSecSuccess; - - sslHdskStateDebug("SSLClose"); - if(ctx == NULL) { - return errSecParam; - } - - err = tls_handshake_close(ctx->hdsk); - - if (err == 0) - err = SSLServiceWriteQueue(ctx); - - SSLChangeHdskState(ctx, SSL_HdskStateGracefulClose); - if (err == errSecIO) - err = errSecSuccess; /* Ignore errors related to closed streams */ - return err; -} - -/* - * Determine how much data the client can be guaranteed to - * obtain via SSLRead() without blocking or causing any low-level - * read operations to occur. - * - * Implemented here because the relevant info in SSLContext (receivedDataBuffer - * and receivedDataPos) are only used in this file. - */ -OSStatus -SSLGetBufferedReadSize(SSLContextRef ctx, - size_t *bufSize) /* RETURNED */ -{ - if(ctx == NULL) { - return errSecParam; - } - if(ctx->receivedDataBuffer.data == NULL) { - *bufSize = 0; - } - else { - assert(ctx->receivedDataBuffer.length >= ctx->receivedDataPos); - *bufSize = ctx->receivedDataBuffer.length - ctx->receivedDataPos; - } - return errSecSuccess; -}