#include "sslAlertMessage.h"
#include "sslSession.h"
#include "sslDebug.h"
-#include "cipherSpecs.h"
+#include "sslCipherSpecs.h"
#include "sslUtils.h"
#include <assert.h>
#include <string.h>
+#include <utilities/SecIOFormat.h>
+
#ifndef NDEBUG
static inline void sslIoTrace(
const char *op,
size_t moved,
OSStatus stat)
{
- sslLogRecordIo("===%s: req %4lu moved %4lu status %ld",
- op, req, moved, stat);
+ sslLogRecordIo("===%s: req %4lu moved %4lu status %d",
+ op, req, moved, (int)stat);
}
#else
#define sslIoTrace(op, req, moved, stat)
static OSStatus SSLProcessProtocolMessage(SSLRecord *rec, SSLContext *ctx);
static OSStatus SSLHandshakeProceed(SSLContext *ctx);
static OSStatus SSLInitConnection(SSLContext *ctx);
-static OSStatus SSLServiceWriteQueue(SSLContext *ctx);
-OSStatus
+static Boolean isFalseStartAllowed(SSLContext *ctx)
+{
+ SSL_CipherAlgorithm c=sslCipherSuiteGetSymmetricCipherAlgorithm(ctx->selectedCipher);
+ KeyExchangeMethod kem=sslCipherSuiteGetKeyExchangeMethod(ctx->selectedCipher);
+
+
+ /* Whitelisting allowed ciphers, kem and client auth type */
+ return
+ (
+ (c==SSL_CipherAlgorithmAES_128_CBC) ||
+ (c==SSL_CipherAlgorithmAES_128_GCM) ||
+ (c==SSL_CipherAlgorithmAES_256_CBC) ||
+ (c==SSL_CipherAlgorithmAES_256_GCM) ||
+ (c==SSL_CipherAlgorithmRC4_128)
+ ) && (
+ (kem==SSL_ECDHE_ECDSA) ||
+ (kem==SSL_ECDHE_RSA) ||
+ (kem==SSL_DHE_RSA) ||
+ (kem==SSL_DHE_DSS)
+ ) && (
+ (ctx->negAuthType==SSLClientAuthNone) ||
+ (ctx->negAuthType==SSLClientAuth_DSSSign) ||
+ (ctx->negAuthType==SSLClientAuth_RSASign) ||
+ (ctx->negAuthType==SSLClientAuth_ECDSASign)
+ );
+}
+
+
+OSStatus
SSLWrite(
SSLContext *ctx,
const void * data,
sslLogRecordIo("SSLWrite top");
if((ctx == NULL) || (bytesWritten == NULL)) {
- return paramErr;
+ return errSecParam;
}
dataLen = dataLength;
processed = 0; /* Initialize in case we return with errSSLWouldBlock */
default:
if(ctx->state < SSL_HdskStateServerHello) {
/* not ready for I/O, and handshake not in progress */
- sslIoTrace("SSLWrite", dataLength, 0, badReqErr);
- return badReqErr;
+ sslIoTrace("SSLWrite", dataLength, 0, errSecBadReq);
+ return errSecBadReq;
}
/* handshake in progress; will call SSLHandshakeProceed below */
break;
/* First, we have to wait until the session is ready to send data,
so the encryption keys and such have been established. */
- err = noErr;
- while (ctx->writeCipher.ready == 0)
+ err = errSecSuccess;
+ while (!(
+ (ctx->state==SSL_HdskStateServerReady) ||
+ (ctx->state==SSL_HdskStateClientReady) ||
+ (ctx->writeCipher_ready && ctx->falseStartEnabled && isFalseStartAllowed(ctx))
+ ))
{ if ((err = SSLHandshakeProceed(ctx)) != 0)
goto exit;
}
rec.contents.length = dataLen;
else
rec.contents.length = MAX_RECORD_LENGTH;
-
- assert(ctx->sslTslCalls != NULL);
- if ((err = ctx->sslTslCalls->writeRecord(rec, ctx)) != 0)
+
+ if ((err = SSLWriteRecord(rec, ctx)) != 0)
goto exit;
processed += rec.contents.length;
dataLen -= rec.contents.length;
/* All the data has been advanced to the write queue */
*bytesWritten = processed;
if ((err = SSLServiceWriteQueue(ctx)) == 0) {
- err = noErr;
+ err = errSecSuccess;
}
exit:
switch(err) {
- case noErr:
+ case errSecSuccess:
case errSSLWouldBlock:
+ case errSSLUnexpectedRecord:
case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */
case errSSLClientCertRequested:
case errSSLClosedGraceful:
sslLogRecordIo("SSLRead top");
if((ctx == NULL) || (data == NULL) || (processed == NULL)) {
- return paramErr;
+ return errSecParam;
}
bufSize = dataLength;
*processed = 0; /* Initialize in case we return with errSSLWouldBlock */
/* First, we have to wait until the session is ready to receive data,
so the encryption keys and such have been established. */
- err = noErr;
- while (ctx->readCipher.ready == 0) {
+ err = errSecSuccess;
+ while (ctx->readCipher_ready == 0) {
if ((err = SSLHandshakeProceed(ctx)) != 0) {
goto exit;
}
if (err != errSSLWouldBlock) {
goto exit;
}
- err = noErr; /* Write blocking shouldn't stop attempts to read */
+ err = errSecSuccess; /* Write blocking shouldn't stop attempts to read */
}
remaining = bufSize;
if (ctx->receivedDataBuffer.data != 0 &&
ctx->receivedDataPos >= ctx->receivedDataBuffer.length)
- { SSLFreeBuffer(&ctx->receivedDataBuffer, ctx);
+ { SSLFreeBuffer(&ctx->receivedDataBuffer);
ctx->receivedDataBuffer.data = 0;
ctx->receivedDataPos = 0;
}
remaining -= rec.contents.length;
charPtr += rec.contents.length;
*processed += rec.contents.length;
- /* COMPILER BUG!
- * This:
- * if ((err = SSLFreeBuffer(rec.contents, ctx)) != 0)
- * passes the address of rec to SSLFreeBuffer, not the address
- * of the contents field (which should be offset 8 from the start
- * of rec).
- */
{
- SSLBuffer *b = &rec.contents;
- if ((err = SSLFreeBuffer(b, ctx)) != 0) {
+ if ((err = SSLFreeRecord(rec, ctx))) {
goto exit;
}
}
if ((err = SSLProcessProtocolMessage(&rec, ctx)) != 0) {
goto exit;
}
- if ((err = SSLFreeBuffer(&rec.contents, ctx)) != 0) {
+ if ((err = SSLFreeRecord(rec, ctx))) {
goto exit;
}
}
}
- err = noErr;
+ err = errSecSuccess;
exit:
/* test for renegotiate: loop until something useful happens */
- if((err == noErr) && (*processed == 0) && !(dataLength == 0)) {
+ if(((err == errSecSuccess) && (*processed == 0) && dataLength) || (err == errSSLUnexpectedRecord)) {
sslLogNegotiateDebug("SSLRead recursion");
goto readRetry;
}
/* shut down on serious errors */
switch(err) {
- case noErr:
+ case errSecSuccess:
case errSSLWouldBlock:
+ case errSSLUnexpectedRecord:
case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */
case errSSLClientCertRequested:
case errSSLClosedGraceful:
OSStatus err;
if(ctx == NULL) {
- return paramErr;
+ return errSecParam;
}
if (ctx->state == SSL_HdskStateGracefulClose)
return errSSLClosedGraceful;
return err;
}
}
- err = noErr;
+ err = errSecSuccess;
if(ctx->isDTLS) {
if (ctx->timeout_deadline<CFAbsoluteTimeGetCurrent()) {
}
}
- while (ctx->readCipher.ready == 0 || ctx->writeCipher.ready == 0)
- { if ((err = SSLHandshakeProceed(ctx)) != 0)
+ while (ctx->readCipher_ready == 0 || ctx->writeCipher_ready == 0)
+ {
+ err = SSLHandshakeProceed(ctx);
+ if((err != 0) && (err != errSSLUnexpectedRecord))
return err;
}
if ((err = SSLServiceWriteQueue(ctx)) != 0) {
return err;
}
- return noErr;
+
+ return errSecSuccess;
}
if ((err = SSLServiceWriteQueue(ctx)) != 0)
return err;
- assert(ctx->readCipher.ready == 0);
+
+ assert(ctx->readCipher_ready == 0);
if ((err = SSLReadRecord(&rec, ctx)) != 0)
return err;
if ((err = SSLProcessProtocolMessage(&rec, ctx)) != 0)
- { SSLFreeBuffer(&rec.contents, ctx);
+ {
+ SSLFreeRecord(rec, ctx);
return err;
}
- if ((err = SSLFreeBuffer(&rec.contents, ctx)) != 0)
+ if ((err = SSLFreeRecord(rec, ctx)))
return err;
- return noErr;
+ return errSecSuccess;
}
static OSStatus
SSLInitConnection(SSLContext *ctx)
-{ OSStatus err = noErr;
+{ OSStatus err = errSecSuccess;
if (ctx->protocolSide == kSSLClientSide) {
SSLChangeHdskState(ctx, SSL_HdskStateClientUninit);
sslLogResumSessDebug("===attempting to resume session");
} else {
sslLogResumSessDebug("===Resumable session protocol mismatch");
- SSLFreeBuffer(&ctx->resumableSession, ctx);
+ SSLFreeBuffer(&ctx->resumableSession);
}
}
* If we're the client & handshake hasn't yet begun, start it by
* pretending we just received a hello request
*/
- if (ctx->state == SSL_HdskStateClientUninit && ctx->writeCipher.ready == 0)
- {
+ if (ctx->state == SSL_HdskStateClientUninit && ctx->writeCipher_ready == 0)
+ {
assert(ctx->negProtocolVersion == SSL_Version_Undetermined);
#if ENABLE_SSLV2
if(!cachedV3OrTls1) {
return err;
}
-static OSStatus
-SSLServiceWriteQueue(SSLContext *ctx)
-{ OSStatus err = noErr, werr = noErr;
- size_t written = 0;
- SSLBuffer buf;
- WaitingRecord *rec;
-
- while (!werr && ((rec = ctx->recordWriteQueue) != 0))
- { buf.data = rec->data + rec->sent;
- buf.length = rec->length - rec->sent;
- werr = sslIoWrite(buf, &written, ctx);
- rec->sent += written;
- if (rec->sent >= rec->length)
- { assert(rec->sent == rec->length);
- assert(err == 0);
- ctx->recordWriteQueue = rec->next;
- sslFree(rec);
- }
- if (err)
- return err;
- }
-
- return werr;
-}
static OSStatus
SSLProcessProtocolMessage(SSLRecord *rec, SSLContext *ctx)
OSStatus
SSLClose(SSLContext *ctx)
{
- OSStatus err = noErr;
+ OSStatus err = errSecSuccess;
sslHdskStateDebug("SSLClose");
if(ctx == NULL) {
- return paramErr;
+ return errSecParam;
}
if (ctx->negProtocolVersion >= SSL_Version_3_0)
err = SSLSendAlert(SSL_AlertLevelWarning, SSL_AlertCloseNotify, ctx);
+
if (err == 0)
err = SSLServiceWriteQueue(ctx);
+
SSLChangeHdskState(ctx, SSL_HdskStateGracefulClose);
- if (err == ioErr)
- err = noErr; /* Ignore errors related to closed streams */
+ if (err == errSecIO)
+ err = errSecSuccess; /* Ignore errors related to closed streams */
return err;
}
size_t *bufSize) /* RETURNED */
{
if(ctx == NULL) {
- return paramErr;
+ return errSecParam;
}
if(ctx->receivedDataBuffer.data == NULL) {
*bufSize = 0;
assert(ctx->receivedDataBuffer.length >= ctx->receivedDataPos);
*bufSize = ctx->receivedDataBuffer.length - ctx->receivedDataPos;
}
- return noErr;
+ return errSecSuccess;
}