⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssltrspt.c

📁 Netscape公司提供的安全套接字层
💻 C
字号:
/*  *********************************************************************
    File: ssltrspt.c

    SSLRef 3.0 Final -- 11/19/96

    Copyright (c)1996 by Netscape Communications Corp.

    By retrieving this software you are bound by the licensing terms
    disclosed in the file "LICENSE.txt". Please read it, and if you don't
    accept the terms, delete this software.

    SSLRef 3.0 was developed by Netscape Communications Corp. of Mountain
    View, California <http://home.netscape.com/> and Consensus Development
    Corporation of Berkeley, California <http://www.consensus.com/>.

    *********************************************************************

    File: ssltrspt.c   Data transportation functionality

    Transports data between the application and the record layer; also
    hands off handshake, alert, and change cipher spec messages to their
    handlers. Also, ensures that negotiation happens before application
    data goes out on the wire.

    ****************************************************************** */

#ifndef _SSLTRSPT_H_
#include "ssltrspt.h"
#endif

#ifndef _SSLALLOC_H_
#include "sslalloc.h"
#endif

#ifndef _SSLCTX_H_
#include "sslctx.h"
#endif

#ifndef _SSLCTX_H_
#include "sslrec.h"
#endif

#ifndef _SSLALERT_H_
#include "sslalert.h"
#endif

#ifndef _SSLSESS_H_
#include "sslsess.h"
#endif

#ifndef _SSL2_H_
#include "ssl2.h"
#endif

#include <string.h>

static SSLErr SSLProcessProtocolMessage(SSLRecord rec, SSLContext *ctx);
static SSLErr SSLHandshakeProceed(SSLContext *ctx);
static SSLErr SSLInitConnection(SSLContext *ctx);

SSLErr
SSLWrite(void *data, uint32 *length, SSLContext *ctx)
{   SSLErr          err;
    SSLRecord       rec;
    uint32          dataLen, processed;
    
    dataLen = *length;
    *length = 0;        /* Initialize in case we return with SSLWouldBlockErr */
    
    if (ctx->state == SSLGracefulClose)
        return SSLConnectionClosedGraceful;
    if (ctx->state == SSLErrorClose)
        return ERR(SSLConnectionClosedError);
    
    /* First, we have to wait until the session is ready to send data,
        so the encryption keys and such have been established. */
    err = SSLNoErr;
    while (ctx->writeCipher.ready == 0)
    {   if ((err = SSLHandshakeProceed(ctx)) != 0)
            goto exit;
    }
    
    /* Attempt to empty the write queue before queueing more data */
    if ((err = SSLServiceWriteQueue(ctx)) != 0)
        return ERR(err);
    
    processed = 0;
    /* Fragment, package and encrypt the data and queue the resulting data for sending */
    while (dataLen > 0)
    {   rec.contentType = SSL_application_data;
        rec.protocolVersion = ctx->protocolVersion;
        rec.contents.data = ((uint8*)data) + processed;
        
        if (dataLen < MAX_RECORD_LENGTH)
            rec.contents.length = dataLen;
        else
            rec.contents.length = MAX_RECORD_LENGTH;
        
        if (ERR(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 */
    *length = processed;
    if (ERR(err = SSLServiceWriteQueue(ctx)) != 0)
        goto exit;
    
    err = SSLNoErr;
exit:
    if (err != 0 && err != SSLWouldBlockErr && err != SSLConnectionClosedGraceful)
        ctx->state = SSLErrorClose;
    
    return ERR(err);
}

SSLErr
SSLRead(void *data, uint32 *length, SSLContext *ctx)
{   SSLErr          err;
    uint8           *progress;
    uint32          bufSize, remaining, count;
    SSLRecord       rec;
    
    bufSize = *length;
    *length = 0;        /* Initialize in case we return with SSLWouldBlockErr */
    
    if (ctx->state == SSLGracefulClose)
        return SSLConnectionClosedGraceful;
    if (ctx->state == SSLErrorClose)
        return ERR(SSLConnectionClosedError);
    
    /* First, we have to wait until the session is ready to receive data,
        so the encryption keys and such have been established. */
    err = SSLNoErr;
    while (ctx->readCipher.ready == 0)
    {   if (ERR(err = SSLHandshakeProceed(ctx)) != 0)
            goto exit;
    }
    
    /* Attempt to service the write queue */
    if (ERR(err = SSLServiceWriteQueue(ctx)) != 0)
    {   if (err != SSLWouldBlockErr)
            goto exit;
        err = SSLNoErr; /* Write blocking shouldn't stop attempts to read */
    }
    
    remaining = bufSize;
    progress = (uint8*)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;
        progress += count;
        *length += count;
        ctx->receivedDataPos += count;
    }
    
    ASSERT(ctx->receivedDataPos <= ctx->receivedDataBuffer.length);
    ASSERT(*length + remaining == bufSize);
    ASSERT(progress == ((uint8*)data) + *length);
    
    if (ctx->receivedDataBuffer.data != 0 &&
        ctx->receivedDataPos >= ctx->receivedDataBuffer.length)
    {   SSLFreeBuffer(&ctx->receivedDataBuffer, &ctx->sysCtx);
        ctx->receivedDataBuffer.data = 0;
        ctx->receivedDataPos = 0;
    }
    
    while (remaining > 0 && ctx->state != SSLGracefulClose)
    {   ASSERT(ctx->receivedDataBuffer.data == 0);
        if (ERR(err = SSLReadRecord(&rec, ctx)) != 0)
            goto exit;
        
        if (rec.contentType == SSL_application_data ||
            rec.contentType == SSL_version_2_0_record)
        {   if (rec.contents.length <= remaining)
            {   memcpy(progress, rec.contents.data, rec.contents.length);
                remaining -= rec.contents.length;
                progress += rec.contents.length;
                *length += rec.contents.length;
                if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
                    goto exit;
            }
            else
            {   memcpy(progress, rec.contents.data, remaining);
                progress += remaining;
                *length += remaining;
                ctx->receivedDataBuffer = rec.contents;
                ctx->receivedDataPos = remaining;
                remaining = 0;
            }
        }
        else
        {   if (ERR(err = SSLProcessProtocolMessage(rec, ctx)) != 0)
                goto exit;
            if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
                goto exit;
        }
    }
    
    err = SSLNoErr;
    
exit:
    if (err != 0 && err != SSLWouldBlockErr && err != SSLConnectionClosedGraceful)
        ctx->state = SSLErrorClose;
    
    return ERR(err);
}

SSLErr
SSLHandshake(SSLContext *ctx)
{   SSLErr  err;

    if (ctx->state == SSLGracefulClose)
        return SSLConnectionClosedGraceful;
    if (ctx->state == SSLErrorClose)
        return ERR(SSLConnectionClosedError);
    
    err = SSLNoErr;
    while (ctx->readCipher.ready == 0 || ctx->writeCipher.ready == 0)
    {   if (ERR(err = SSLHandshakeProceed(ctx)) != 0)
            return err;
    }
    
    return SSLNoErr;
}


static SSLErr
SSLHandshakeProceed(SSLContext *ctx)
{   SSLErr      err;
    SSLRecord   rec;
    
    if (ctx->state == SSLUninitialized)
        if (ERR(err = SSLInitConnection(ctx)) != 0)
            return err;
    if (ERR(err = SSLServiceWriteQueue(ctx)) != 0)
        return err;
    ASSERT(ctx->readCipher.ready == 0);
    if (ERR(err = SSLReadRecord(&rec, ctx)) != 0)
        return err;
    if (ERR(err = SSLProcessProtocolMessage(rec, ctx)) != 0)
    {   SSLFreeBuffer(&rec.contents, &ctx->sysCtx);
        return err;
    }
    if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
        return err;
        
    return SSLNoErr;
}

static SSLErr
SSLInitConnection(SSLContext *ctx)
{   SSLErr      err;
    
    if (ctx->protocolSide == SSL_ClientSide)
        ctx->state = HandshakeClientIdle;
    else
    {   ASSERT(ctx->protocolSide == SSL_ServerSide);
        ctx->state = HandshakeServerIdle;
    }
    
    if (ctx->peerID.data != 0)
    {   ERR(SSLGetSessionID(&ctx->resumableSession, ctx));
        /* Ignore errors; just treat as uncached session */
    }
    
/* If we're a client, and we have a cached resumable session, we want
 *  to try to negotiate the same session type we negotiated before,
 *  because an SSL 3.0 session can only be resumed with an SSL 3.0
 *  hello message.
 */
    if (ctx->protocolSide == SSL_ClientSide && ctx->resumableSession.data != 0)
    {   if (ERR(err = SSLRetrieveSessionIDProtocolVersion(ctx->resumableSession,
                                        &ctx->protocolVersion, ctx)) != 0)
            return err;
    }
    
/* If we're the client & handshake hasn't yet begun, start it by
 *  pretending we just received a hello request
 */
    if (ctx->state == HandshakeClientIdle && ctx->writeCipher.ready == 0)
    {   switch (ctx->protocolVersion)
        {   case SSL_Version_Undetermined:
            case SSL_Version_3_0_With_2_0_Hello:
            case SSL_Version_2_0:
                if (ERR(err = SSL2AdvanceHandshake(ssl2_mt_kickstart_handshake, ctx)) != 0)
                    return err;
                break;
            case SSL_Version_3_0_Only:
            case SSL_Version_3_0:
                if (ERR(err = SSLAdvanceHandshake(SSL_hello_request, ctx)) != 0)
                    return err;
                break;
            default:
                ASSERTMSG("Bad protocol version");
                break;
        }
    }
    
    return SSLNoErr;
}

SSLErr
SSLServiceWriteQueue(SSLContext *ctx)
{   SSLErr          err;
    uint32          written;
    SSLBuffer       buf, recBuf;
    WaitingRecord   *rec;
    
    while ((rec = ctx->recordWriteQueue) != 0)
    {   buf.data = rec->data.data + rec->sent;
        buf.length = rec->data.length - rec->sent;
        err = ctx->ioCtx.write(buf, &written, ctx->ioCtx.ioRef);
        ERR(err);
        rec->sent += written;
        if (rec->sent >= rec->data.length)
        {   ASSERT(rec->sent == rec->data.length);
            ASSERT(err == 0);
            err = SSLFreeBuffer(&rec->data, &ctx->sysCtx);
            ASSERT(err == 0);
            recBuf.data = (uint8*)rec;
            recBuf.length = sizeof(WaitingRecord);
            ctx->recordWriteQueue = rec->next;
            err = SSLFreeBuffer(&recBuf, &ctx->sysCtx);
            ASSERT(err == 0);
        }
        if (ERR(err))
            return err;
        ASSERT(ctx->recordWriteQueue == 0 || ctx->recordWriteQueue->sent == 0);
    }
    
    return SSLNoErr;
}

static SSLErr
SSLProcessProtocolMessage(SSLRecord rec, SSLContext *ctx)
{   SSLErr      err;
    
    switch (rec.contentType)
    {   case SSL_handshake:
            ERR(err = SSLProcessHandshakeRecord(rec, ctx));
            break;
        case SSL_alert:
            ERR(err = SSLProcessAlert(rec, ctx));
            break;
        case SSL_change_cipher_spec:
            ERR(err = SSLProcessChangeCipherSpec(rec, ctx));
            break;
        case SSL_version_2_0_record:
            ERR(err = SSL2ProcessMessage(rec, ctx));
            break;
        default:
            return ERR(SSLProtocolErr);
    }
    
    return err;
}

SSLErr
SSLClose(SSLContext *ctx)
{   SSLErr      err;
    
    if (ctx->protocolVersion == SSL_Version_3_0)
        ERR(err = SSLSendAlert(alert_warning, alert_close_notify, ctx));
    if (err == 0)
        ERR(err = SSLServiceWriteQueue(ctx));
    ctx->state = SSLGracefulClose;
    if (err == SSLIOErr)
        err = SSLNoErr;     /* Ignore errors related to closed streams */
    return err;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -