SSL_read读取流程解析转载

SSL_read函数定义

复制代码
SSL_read(3SSL)                                                                                 OpenSSL                                                                                SSL_read(3SSL)

NAME
       SSL_read - read bytes from a TLS/SSL connection.

SYNOPSIS
        #include <openssl/ssl.h>

        int SSL_read(SSL *ssl, void *buf, int num);

DESCRIPTION
       SSL_read() tries to read num bytes from the specified ssl into the buffer buf.

NOTES
       If necessary, SSL_read() will negotiate a TLS/SSL session, if not already explicitly performed by SSL_connect(3) or SSL_accept(3). If the peer requests a re-negotiation, it will be
       performed transparently during the SSL_read() operation. The behaviour of SSL_read() depends on the underlying BIO.

       For the transparent negotiation to succeed, the ssl must have been initialized to client or server mode. This is being done by calling SSL_set_connect_state(3) or SSL_set_accept_state()
       before the first call to an SSL_read() or SSL_write(3) function.

       SSL_read() works based on the SSL/TLS records. The data are received in records (with a maximum record size of 16kB for SSLv3/TLSv1). Only when a record has been completely received, it can
       be processed (decryption and check of integrity). Therefore data that was not retrieved at the last call of SSL_read() can still be buffered inside the SSL layer and will be retrieved on
       the next call to SSL_read(). If num is higher than the number of bytes buffered, SSL_read() will return with the bytes buffered.  If no more bytes are in the buffer, SSL_read() will trigger
       the processing of the next record. Only when the record has been received and processed completely, SSL_read() will return reporting success. At most the contents of the record will be
       returned. As the size of an SSL/TLS record may exceed the maximum packet size of the underlying transport (e.g. TCP), it may be necessary to read several packets from the transport layer
       before the record is complete and SSL_read() can succeed.

       If the underlying BIO is blocking, SSL_read() will only return, once the read operation has been finished or an error occurred, except when a renegotiation take place, in which case a
       SSL_ERROR_WANT_READ may occur.  This behaviour can be controlled with the SSL_MODE_AUTO_RETRY flag of the SSL_CTX_set_mode(3) call.

       If the underlying BIO is non-blocking, SSL_read() will also return when the underlying BIO could not satisfy the needs of SSL_read() to continue the operation. In this case a call to
       SSL_get_error(3) with the return value of SSL_read() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. As at any time a re-negotiation is possible, a call to SSL_read() can also cause
       write operations! The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_read(). The action depends on the underlying BIO. When using a
       non-blocking socket, nothing is to be done, but select() can be used to check for the required condition. When using a buffering BIO, like a BIO pair, data must be written into or retrieved
       out of the BIO before being able to continue.

       SSL_pending(3) can be used to find out whether there are buffered bytes available for immediate retrieval. In this case SSL_read() can be called without blocking or actually receiving new
       data from the underlying socket.
复制代码

 

  SSL_read()函数基于ssl/tls记录实现,数据被接收到记录中,在SSLv3和TLSv1协议中,单个记录的大小最大为16kB,只有当一条记录被完整的读取之后,才能够被解析(包括解密和鉴权)。所以ssl层可能缓冲一些数据,每次SSL_read()读取的字节数可能不是一个record中的全部数据,但SSL_read从socket读取是以record为最小单位读取的,这些上一个record中未读取的数据会在未被这次SSL_read读取时,缓存在ssl层,等待下一次SSL_read()调用时读取。
如果num(即预期要读取的大小)大于实际已经缓存的字节大小,SSL_read()会返回实际已经缓存的字节大小。如果缓存中已经没有数据,则SSL_read()会触发读tcp流并生成下一个record。只有当一个record记录被完整的读取和解密鉴权处理之后,SSL_read() 才会返回成功。因为单个SSL/TLS record记录的大小可能会超过更底层协议(比如TCP)的单个包的最大大小,故而为了保持一条record记录的完整性和SSL_read()能成功返回,可能会需要从传输层读取多个包来保证。

如果底层的io套接字为阻塞套接字,那SSL_read只有在一次完整的读操作完成或者异常时,才会返回,除非发生了重协商,就会出现返回SSL_ERROR_WANT_READ的错误。不过这个行为也可以通过调用SSL_CTX_set_mode(3)接口设置 SSL_MODE_AUTO_RETRY 标记来控制。

如果底层io是非阻塞套接字,SSL_read()也会在底层BIO 不能满足SSL_read()的需求时返回。在这种情况下,通过SSL_get_error(3)调用 SSL_read()的返回值就会返回 SSL_ERROR_WANT_READ 或SSL_ERROR_WANT_WRITE。在任何时候都可能出现重协商,故而这个时候调用SSL_read() 可能会导致写操作,因为需要发送协商内容。在采取合适措施满足SSL_read()的执行条件后,调用过程需要被重复执行,具体措施取决于底层的BIO类型,在使用非阻塞套接字时,不需要做额外操作,不过select()可以用来检测合适满足条件(即SSL_read()的底层套接字可读)。当使用带缓冲区的IO时,比如BIO pair,后续操作之前,数据必须要被写入或者从BIO中读取。

从上述说明可以知道,理论上ssl返回的数据包并不是流式的,而是封包式的,客户端发包时调用对应sdk的ssl接口发送的包,在接收时会以完整的一条记录形式抛出,但上层的读确实可以按照流式的方式来读取。

SSL_read的代码实现

复制代码
int SSL_read(SSL *s, void *buf, int num)
{
    if (s->handshake_func == 0) {
        SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
        return -1;
    }

    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
        s->rwstate = SSL_NOTHING;
        return (0);
    }
    return (s->method->ssl_read(s, buf, num));
}
复制代码

可知ssl_read为method结构体成员的函数回调指针。SSL为外部初始化的入参,由SSL_new 接口初始化,定义如下
SSL *SSL_new(SSL_CTX *ctx);
SSL_new的实现在ssl_lib.c中,其method结构体成员的初始化方式如下:

复制代码
SSL *SSL_new(SSL_CTX *ctx)
{
    SSL *s;

    if (ctx == NULL) {
        SSLerr(SSL_F_SSL_NEW, SSL_R_NULL_SSL_CTX);
        return (NULL);
    }
    if (ctx->method == NULL) {
        SSLerr(SSL_F_SSL_NEW, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
        return (NULL);
    }
    ...
    s->method = ctx->method;
   ...
}
复制代码

即由SSL_CTX中的method定义。SSL_CTX一般由如下形式定义,在外部初始化时定义,
pSslCtx = SSL_CTX_new(TLSv1_2_client_method());
其定义也位于ssl_lib.c中

复制代码
/*
 * These wrapper functions should remain rather than redeclaring
 * SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
 * variable. The reason is that the functions aren't static, they're exposed
 * via ssl.h.
 */

SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
{
    SSL_CTX *ret = NULL;

    if (meth == NULL) {
        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_NULL_SSL_METHOD_PASSED);
        return NULL;
    }

    if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
        return NULL;

    if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
        goto err;
    }
    ret = OPENSSL_zalloc(sizeof(*ret));
    if (ret == NULL)
        goto err;

    ret->method = meth;
复制代码

 

可知method定义来自 TLSv1_2_client_method() 即根据具体的协议类型来定义。
TLSv1_2_client_method函数由IMPLEMENT_tls_meth_func宏定义定义,在t1_clnt.h中

复制代码
static const SSL_METHOD *tls1_get_client_method(int ver);
static const SSL_METHOD *tls1_get_client_method(int ver)
{
    if (ver == TLS1_2_VERSION)
        return TLSv1_2_client_method();
    if (ver == TLS1_1_VERSION)
        return TLSv1_1_client_method();
    if (ver == TLS1_VERSION)
        return TLSv1_client_method();
    return NULL;
}

IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
                        ssl_undefined_function,
                        ssl3_connect,
                        tls1_get_client_method, TLSv1_2_enc_data)
复制代码

查看IMPLEMENT_tls_meth_func的定义可知,对照SSL_METHOD 方法的定义SSL_read中调用的 s->method->ssl_read函数为 ssl3_read函数

复制代码
# define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \
                                s_get_meth, enc_data) \
const SSL_METHOD *func_name(void)  \
        { \
        static const SSL_METHOD func_name##_data= { \
                version, \
                tls1_new, \
                tls1_clear, \
                tls1_free, \
                s_accept, \
                s_connect, \
                ssl3_read, \
                ssl3_peek, \
                ssl3_write, \
                ssl3_shutdown, \
                ssl3_renegotiate, \
                ssl3_renegotiate_check, \
                ssl3_get_message, \
                ssl3_read_bytes, \
                ssl3_write_bytes, \
                ssl3_dispatch_alert, \
                ssl3_ctrl, \
                ssl3_ctx_ctrl, \
                ssl3_get_cipher_by_char, \
                ssl3_put_cipher_by_char, \
                ssl3_pending, \
                ssl3_num_ciphers, \
                ssl3_get_cipher, \
                s_get_meth, \
                tls1_default_timeout, \
                &enc_data, \
                ssl_undefined_void_function, \
                ssl3_callback_ctrl, \
                ssl3_ctx_callback_ctrl, \
        }; \
        return &func_name##_data; \
        }
复制代码

 

 

 一是ssl3_read_bytes,如果record中没有数据,才会触发从record中读取数据,此处的rr即为SSL *s中存储的最近一次的record的内容和偏移量openssl1-1-1g版本

int ssl3_read(SSL *s, void *buf, size_t len, size_t *readbytes)
{
    return ssl3_read_internal(s, buf, len, 0, readbytes);
}

 

复制代码
int ssl3_read_internal(SSL *s, void *buf, size_t len, int peek,
                              size_t *readbytes)
{
    int ret;

    clear_sys_error();// 清除错误信息 
    if (s->s3->renegotiate)// 检查协商是否成功
        ssl3_renegotiate_check(s, 0);
    s->s3->in_read_app_data = 1;// 标志现在在读应用层数据
    // ssl3读取数据, 类型是SSL3_RT_APPLICATION_DATA,应用数据
    ret =
        s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf, len,
                                  peek, readbytes);
    // s->s3->in_read_app_data == 2表示要读协商数据
    if ((ret == -1) && (s->s3->in_read_app_data == 2)) {
        /*
         * ssl3_read_bytes decided to call s->handshake_func, which called
         * ssl3_read_bytes to read handshake data. However, ssl3_read_bytes
         * actually found application data and thinks that application data
         * makes sense here; so disable handshake processing and try to read
         * application data again.
         */
        ossl_statem_set_in_handshake(s, 1);
        // 重新读数据
        ret =
            s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf,
                                      len, peek, readbytes);
        ossl_statem_set_in_handshake(s, 0);
    } else
        s->s3->in_read_app_data = 0;
    //读取数据的主要函数实际为ssl3_read_bytes():
    return ret;
}
复制代码

 

复制代码
/*-
 * Return up to 'len' payload bytes received in 'type' records.
 * 'type' is one of the following:
 *
 *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
 *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
 *   -  0 (during a shutdown, no data has to be returned)
 *
 * If we don't have stored data to work from, read a SSL/TLS record first
 * (possibly multiple records if we still don't have anything to return).
 *
 * This function must handle any surprises the peer may have for us, such as
 * Alert records (e.g. close_notify) or renegotiation requests. ChangeCipherSpec
 * messages are treated as if they were handshake messages *if* the |recd_type|
 * argument is non NULL.
 * Also if record payloads contain fragments too small to process, we store
 * them until there is enough for the respective protocol (the record protocol
 * may use arbitrary fragmentation and even interleaving):
 *     Change cipher spec protocol
 *             just 1 byte needed, no need for keeping anything stored
 *     Alert protocol
 *             2 bytes needed (AlertLevel, AlertDescription)
 *     Handshake protocol
 *             4 bytes needed (HandshakeType, uint24 length) -- we just have
 *             to detect unexpected Client Hello and Hello Request messages
 *             here, anything else is handled by higher layers
 *     Application data protocol
 *             none of our business
 */
int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                    size_t len, int peek, size_t *readbytes)
{
    int i, j, ret;
    size_t n, curr_rec, num_recs, totalbytes;
    SSL3_RECORD *rr;
    SSL3_BUFFER *rbuf;
    void (*cb) (const SSL *ssl, int type2, int val) = NULL;
    int is_tls13 = SSL_IS_TLS13(s);

    rbuf = &s->rlayer.rbuf;
    // 检查是否分配了接收缓冲区
    if (!SSL3_BUFFER_is_initialised(rbuf)) {
        /* Not initialized yet */
        if (!ssl3_setup_read_buffer(s)) {
            /* SSLfatal() already called */
            return -1;
        }
    }
    // 只处理两种数据,或是应用层数据或者是SSL握手协商数据,
    // peek只处理应用层数据,其他则出错
    if ((type && (type != SSL3_RT_APPLICATION_DATA)
         && (type != SSL3_RT_HANDSHAKE)) || (peek
                                             && (type !=
                                                 SSL3_RT_APPLICATION_DATA))) {
        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES,
                 ERR_R_INTERNAL_ERROR);
        return -1;
    }
    
    if ((type == SSL3_RT_HANDSHAKE) && (s->rlayer.handshake_fragment_len > 0))
        /* (partially) satisfy request from storage */
    {
    // 握手数据碎片, 处理完直到不再是碎片
        unsigned char *src = s->rlayer.handshake_fragment;
        unsigned char *dst = buf;
        unsigned int k;

        /* peek == 0 */
        n = 0;
        while ((len > 0) && (s->rlayer.handshake_fragment_len > 0)) {
            *dst++ = *src++;
            len--;
            s->rlayer.handshake_fragment_len--;
            n++;
        }
        /* move any remaining fragment bytes: */
        for (k = 0; k < s->rlayer.handshake_fragment_len; k++)
            s->rlayer.handshake_fragment[k] = *src++;

        if (recvd_type != NULL)
            *recvd_type = SSL3_RT_HANDSHAKE;

        *readbytes = n;
        return 1;
    }

    /*
     * Now s->rlayer.handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE.
     */

    if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) {
        // 没进握手阶段但属于SSL初始化阶段, 调用SSL握手处理
        /* type == SSL3_RT_APPLICATION_DATA */
        i = s->handshake_func(s);
        /* SSLfatal() already called */
        if (i < 0)
            return i;
        if (i == 0)
            return -1;
    }
 start:
 // 正常的接收数据开始, 开始读写状态为NOTHING
    s->rwstate = SSL_NOTHING;

    /*-
     * For each record 'i' up to |num_recs]
     * rr[i].type     - is the type of record
     * rr[i].data,    - data
     * rr[i].off,     - offset into 'data' for next read
     * rr[i].length,  - number of bytes.
     */
    rr = s->rlayer.rrec;// 记录rrec指针
    num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);

    do {
        /* get new records if necessary */
        if (num_recs == 0) {
            // 当前没rrec,获取新的rrec, 该函数获取SSL记录数据
            ret = ssl3_get_record(s);
            if (ret <= 0) {
                /* SSLfatal() already called if appropriate */
                return ret;
            }
            num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer);
            if (num_recs == 0) {
                /* Shouldn't happen */
                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES,
                         ERR_R_INTERNAL_ERROR);
                return -1;
            }
        }
        /* Skip over any records we have already read */
        for (curr_rec = 0;
             curr_rec < num_recs && SSL3_RECORD_is_read(&rr[curr_rec]);
             curr_rec++) ;
        if (curr_rec == num_recs) {
            RECORD_LAYER_set_numrpipes(&s->rlayer, 0);
            num_recs = 0;
            curr_rec = 0;
        }
    } while (num_recs == 0);
    rr = &rr[curr_rec];

    if (s->rlayer.handshake_fragment_len > 0
            && SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE
            && SSL_IS_TLS13(s)) {
        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                 SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA);
        return -1;
    }

    /*
     * Reset the count of consecutive warning alerts if we've got a non-empty
     * record that isn't an alert.
     */
    if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT
            && SSL3_RECORD_get_length(rr) != 0)
        s->rlayer.alert_count = 0;

    /* we now have a packet which can be read and processed */
    //// 只允许在握手状态下修改当前的算法信息,否则出错
    if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
                                   * reset by ssl3_get_finished */
        && (SSL3_RECORD_get_type(rr) != SSL3_RT_HANDSHAKE)) {
        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                 SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
        return -1;
    }

    /*
     * If the other end has shut down, throw anything we read away (even in
     * 'peek' mode)
     */// 接收到对方的FIN信息, 接收结束
    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
        SSL3_RECORD_set_length(rr, 0);
        s->rwstate = SSL_NOTHING;
        return 0;
    }
    /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
    if (type == SSL3_RECORD_get_type(rr)
        || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
            && type == SSL3_RT_HANDSHAKE && recvd_type != NULL
            && !is_tls13)) {
        /*
         * SSL3_RT_APPLICATION_DATA or
         * SSL3_RT_HANDSHAKE or
         * SSL3_RT_CHANGE_CIPHER_SPEC
         */
        /*
         * make sure that we are not getting application data when we are
         * doing a handshake for the first time
         */
         // 读到是数据类型和期待读到的数据类型一致
        // 这是正常大多数的情况
        if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
            (s->enc_read_ctx == NULL)) {
            // 在初始阶段只应该读握手信息而不该读应用信息
            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_APP_DATA_IN_HANDSHAKE);
            return -1;
        }

        if (type == SSL3_RT_HANDSHAKE
            && SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
            && s->rlayer.handshake_fragment_len > 0) {
            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_CCS_RECEIVED_EARLY);
            return -1;
        }

        if (recvd_type != NULL)
            *recvd_type = SSL3_RECORD_get_type(rr);

        if (len == 0) {
            /*
             * Mark a zero length record as read. This ensures multiple calls to
             * SSL_read() with a zero length buffer will eventually cause
             * SSL_pending() to report data as being available.
             */
            if (SSL3_RECORD_get_length(rr) == 0)
                SSL3_RECORD_set_read(rr);
            return 0;
        }

        totalbytes = 0;
        do {
            // 在期待读取的数据长度len和已经读到的数据记录长度rr->length取小值作为返回的数据长度
            if (len - totalbytes > SSL3_RECORD_get_length(rr))
                n = SSL3_RECORD_get_length(rr);
            else
                n = len - totalbytes;

            memcpy(buf, &(rr->data[rr->off]), n);
            buf += n;
            if (peek) {
                /* Mark any zero length record as consumed CVE-2016-6305 */
                if (SSL3_RECORD_get_length(rr) == 0)
                    SSL3_RECORD_set_read(rr);
            } else {
           // 如果不是peek,移动记录缓冲的数据偏移指针,长度减
                SSL3_RECORD_sub_length(rr, n);
                SSL3_RECORD_add_off(rr, n);
                if (SSL3_RECORD_get_length(rr) == 0) {
                    s->rlayer.rstate = SSL_ST_READ_HEADER;
                    SSL3_RECORD_set_off(rr, 0);
                    SSL3_RECORD_set_read(rr);
                }
            }
            if (SSL3_RECORD_get_length(rr) == 0
                || (peek && n == SSL3_RECORD_get_length(rr))) {
                curr_rec++;
                rr++;
            }
            totalbytes += n;
        } while (type == SSL3_RT_APPLICATION_DATA && curr_rec < num_recs
                 && totalbytes < len);
        if (totalbytes == 0) {
            /* We must have read empty records. Get more data */
            goto start;
        }
        if (!peek && curr_rec == num_recs
            && (s->mode & SSL_MODE_RELEASE_BUFFERS)
            && SSL3_BUFFER_get_left(rbuf) == 0)
            ssl3_release_read_buffer(s);
        *readbytes = totalbytes;
        return 1;// 正常返回
    }

    /*
     * If we get here, then type != rr->type; if we have a handshake message,
     * then it was unexpected (Hello Request or Client Hello) or invalid (we
     * were actually expecting a CCS).
     */

    /*
     * Lets just double check that we've not got an SSLv2 record
     */
    if (rr->rec_version == SSL2_VERSION) {
        /*
         * Should never happen. ssl3_get_record() should only give us an SSLv2
         * record back if this is the first packet and we are looking for an
         * initial ClientHello. Therefore |type| should always be equal to
         * |rr->type|. If not then something has gone horribly wrong
         */
        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL3_READ_BYTES,
                 ERR_R_INTERNAL_ERROR);
        return -1;
    }

    if (s->method->version == TLS_ANY_VERSION
        && (s->server || rr->type != SSL3_RT_ALERT)) {
        /*
         * If we've got this far and still haven't decided on what version
         * we're using then this must be a client side alert we're dealing with
         * (we don't allow heartbeats yet). We shouldn't be receiving anything
         * other than a ClientHello if we are a server.
         */
        s->version = rr->rec_version;
        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                 SSL_R_UNEXPECTED_MESSAGE);
        return -1;
    }

    /*-
     * s->rlayer.handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
     * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
     */
    //处理告警
    if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) {
        unsigned int alert_level, alert_descr;
        unsigned char *alert_bytes = SSL3_RECORD_get_data(rr)
                                     + SSL3_RECORD_get_off(rr);
        PACKET alert;

        if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr))
                || !PACKET_get_1(&alert, &alert_level)
                || !PACKET_get_1(&alert, &alert_descr)
                || PACKET_remaining(&alert) != 0) {
            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_INVALID_ALERT);
            return -1;
        }
                //分别处理msg和info的回调

        if (s->msg_callback)
            s->msg_callback(0, s->version, SSL3_RT_ALERT, alert_bytes, 2, s,
                            s->msg_callback_arg);

        if (s->info_callback != NULL)
            cb = s->info_callback;
        else if (s->ctx->info_callback != NULL)
            cb = s->ctx->info_callback;

        if (cb != NULL) {
            j = (alert_level << 8) | alert_descr;
            cb(s, SSL_CB_READ_ALERT, j);
        }

        if (alert_level == SSL3_AL_WARNING
                || (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED)) {
            s->s3->warn_alert = alert_descr;
            SSL3_RECORD_set_read(rr);

            s->rlayer.alert_count++;
            if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) {
                SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                         SSL_R_TOO_MANY_WARN_ALERTS);
                return -1;
            }
        }

        /*
         * Apart from close_notify the only other warning alert in TLSv1.3
         * is user_cancelled - which we just ignore.
         */
        if (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED) {
            goto start;
        } else if (alert_descr == SSL_AD_CLOSE_NOTIFY
                && (is_tls13 || alert_level == SSL3_AL_WARNING)) {
            s->shutdown |= SSL_RECEIVED_SHUTDOWN;// 普通报警信息
            return 0;
        } else if (alert_level == SSL3_AL_FATAL || is_tls13) {
            char tmp[16];
            // 严重错误信息, 断开SSL会话
            s->rwstate = SSL_NOTHING;
            s->s3->fatal_alert = alert_descr;
            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_READ_BYTES,
                     SSL_AD_REASON_OFFSET + alert_descr);
            BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr);
            ERR_add_error_data(2, "SSL alert number ", tmp);
            s->shutdown |= SSL_RECEIVED_SHUTDOWN;
            SSL3_RECORD_set_read(rr);
            SSL_CTX_remove_session(s->session_ctx, s->session);
            return 0;
        } else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
            /*
             * This is a warning but we receive it if we requested
             * renegotiation and the peer denied it. Terminate with a fatal
             * alert because if application tried to renegotiate it
             * presumably had a good reason and expects it to succeed. In
             * future we might have a renegotiation where we don't care if
             * the peer refused it where we carry on.
             */
            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_NO_RENEGOTIATION);
            return -1;
        } else if (alert_level == SSL3_AL_WARNING) {
            /* We ignore any other warning alert in TLSv1.2 and below */
            goto start;
        }

        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_SSL3_READ_BYTES,
                 SSL_R_UNKNOWN_ALERT_TYPE);
        return -1;
    }

    if ((s->shutdown & SSL_SENT_SHUTDOWN) != 0) {
        if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
            BIO *rbio;

            /*
             * We ignore any handshake messages sent to us unless they are
             * TLSv1.3 in which case we want to process them. For all other
             * handshake messages we can't do anything reasonable with them
             * because we are unable to write any response due to having already
             * sent close_notify.
             */
            if (!SSL_IS_TLS13(s)) {
                SSL3_RECORD_set_length(rr, 0);
                SSL3_RECORD_set_read(rr);

                if ((s->mode & SSL_MODE_AUTO_RETRY) != 0)
                    goto start;

                s->rwstate = SSL_READING;
                rbio = SSL_get_rbio(s);
                BIO_clear_retry_flags(rbio);
                BIO_set_retry_read(rbio);
                return -1;
            }
        } else {
            /*
             * The peer is continuing to send application data, but we have
             * already sent close_notify. If this was expected we should have
             * been called via SSL_read() and this would have been handled
             * above.
             * No alert sent because we already sent close_notify
             */
            SSL3_RECORD_set_length(rr, 0);
            SSL3_RECORD_set_read(rr);
            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_READ_BYTES,
                     SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY);
            return -1;
        }
    }

    /*
     * For handshake data we have 'fragment' storage, so fill that so that we
     * can process the header at a fixed place. This is done after the
     * "SHUTDOWN" code above to avoid filling the fragment storage with data
     * that we're just going to discard.
     */
    if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
        // 现在情况是读取的数据类型和期待读取的数据类型不一致
        // 已经读到的数据不丢弃,而是作为碎片存储起来以后备用
        size_t dest_maxlen = sizeof(s->rlayer.handshake_fragment);
        unsigned char *dest = s->rlayer.handshake_fragment;
        size_t *dest_len = &s->rlayer.handshake_fragment_len;
        // 握手类型数据存到握手碎片区
        n = dest_maxlen - *dest_len; /* available space in 'dest' */
        if (SSL3_RECORD_get_length(rr) < n)
            n = SSL3_RECORD_get_length(rr); /* available bytes */

        /* now move 'n' bytes: */
        memcpy(dest + *dest_len,
               SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr), n);
        SSL3_RECORD_add_off(rr, n);
        SSL3_RECORD_sub_length(rr, n);
        *dest_len += n;
        if (SSL3_RECORD_get_length(rr) == 0)
            SSL3_RECORD_set_read(rr);

        if (*dest_len < dest_maxlen)
            goto start;     /* fragment was too small */
    }

    if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) {
        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                 SSL_R_CCS_RECEIVED_EARLY);
        return -1;
    }

    /*
     * Unexpected handshake message (ClientHello, NewSessionTicket (TLS1.3) or
     * protocol violation)
     该报文类型为 SSL3_RT_HANDSHAKE 而不是 SSL3_RT_APPLICATION_DATA 报文,
     说明我们收到了一个握手报文。服务端会尝试收取到足够长度的握手报文,
     并在此进入握手函数 s->handshake_func 恢复握手过程
     */
    if ((s->rlayer.handshake_fragment_len >= 4)
            && !ossl_statem_get_in_handshake(s)) {
        int ined = (s->early_data_state == SSL_EARLY_DATA_READING);

        /* We found handshake data, so we're going back into init */
        ossl_statem_set_in_init(s, 1);

        i = s->handshake_func(s);// 重新握手协商
        /* SSLfatal() already called if appropriate */
        if (i < 0)
            return i;
        if (i == 0) {
            return -1;
        }

        /*
         * If we were actually trying to read early data and we found a
         * handshake message, then we don't want to continue to try and read
         * the application data any more. It won't be "early" now.
         */
        if (ined)
            return -1;

        if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
            if (SSL3_BUFFER_get_left(rbuf) == 0) {
                /* no read-ahead left? */
                BIO *bio;
                /*
                 * In the case where we try to read application data, but we
                 * trigger an SSL handshake, we return -1 with the retry
                 * option set.  Otherwise renegotiation may cause nasty
                 * problems in the blocking world
                 */
                s->rwstate = SSL_READING;
                bio = SSL_get_rbio(s);
                BIO_clear_retry_flags(bio);
                BIO_set_retry_read(bio);
                return -1;
            }
        }
        goto start;
    }

    switch (SSL3_RECORD_get_type(rr)) {
    default:
        /*
         * TLS 1.0 and 1.1 say you SHOULD ignore unrecognised record types, but
         * TLS 1.2 says you MUST send an unexpected message alert. We use the
         * TLS 1.2 behaviour for all protocol versions to prevent issues where
         * no progress is being made and the peer continually sends unrecognised
         * record types, using up resources processing them.
         */
        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                 SSL_R_UNEXPECTED_RECORD);
        return -1;
    case SSL3_RT_CHANGE_CIPHER_SPEC:
    case SSL3_RT_ALERT:
    case SSL3_RT_HANDSHAKE:
        // 这几种类型前面已经处理过了, 到这还有的话是哪出错了
        /*
         * we already handled all of these, with the possible exception of
         * SSL3_RT_HANDSHAKE when ossl_statem_get_in_handshake(s) is true, but
         * that should not happen when type != rr->type
         */
        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                 ERR_R_INTERNAL_ERROR);
        return -1;
    case SSL3_RT_APPLICATION_DATA:
        /*
         * At this point, we were expecting handshake data, but have
         * application data.  If the library was running inside ssl3_read()
         * (i.e. in_read_app_data is set) and it makes sense to read
         * application data at this point (session renegotiation not yet
         * started), we will indulge it.
         */// 这时情况是收到的是应用数据,而期望接收的是握手数据
        if (ossl_statem_app_data_allowed(s)) {
            s->s3->in_read_app_data = 2;// in_read_app_data设置为2,会重新执行ssl3_read_bytes()
            return -1;
        } else if (ossl_statem_skip_early_data(s)) {
            /*
             * This can happen after a client sends a CH followed by early_data,
             * but the server responds with a HelloRetryRequest. The server
             * reads the next record from the client expecting to find a
             * plaintext ClientHello but gets a record which appears to be
             * application data. The trial decrypt "works" because null
             * decryption was applied. We just skip it and move on to the next
             * record.
             */
            if (!early_data_count_ok(s, rr->length,
                                     EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) {
                /* SSLfatal() already called */
                return -1;
            }
            SSL3_RECORD_set_read(rr);
            goto start;
        } else {
            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_UNEXPECTED_RECORD);
            return -1;
        }
    }
}
复制代码

 

 然后会从record中拷贝数据,如果预期读取数据n大于record的长度,则只会读取record中的长度,如果预期读取的数据n不到record的长度,则会读取n字节,然后调整record记录中已经读取的偏移off。下一次会从off处开始读 ;openssl1-1-1g版本

复制代码
 if (type == SSL3_RECORD_get_type(rr)
        || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
            && type == SSL3_RT_HANDSHAKE && recvd_type != NULL
            && !is_tls13)) {
        /*
         * SSL3_RT_APPLICATION_DATA or
         * SSL3_RT_HANDSHAKE or
         * SSL3_RT_CHANGE_CIPHER_SPEC
         */
        /*
         * make sure that we are not getting application data when we are
         * doing a handshake for the first time
         */
        if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
            (s->enc_read_ctx == NULL)) {
            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_APP_DATA_IN_HANDSHAKE);
            return -1;
        }

        if (type == SSL3_RT_HANDSHAKE
            && SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
            && s->rlayer.handshake_fragment_len > 0) {
            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_READ_BYTES,
                     SSL_R_CCS_RECEIVED_EARLY);
            return -1;
        }

        if (recvd_type != NULL)
            *recvd_type = SSL3_RECORD_get_type(rr);

        if (len == 0) {
            /*
             * Mark a zero length record as read. This ensures multiple calls to
             * SSL_read() with a zero length buffer will eventually cause
             * SSL_pending() to report data as being available.
             */
            if (SSL3_RECORD_get_length(rr) == 0)
                SSL3_RECORD_set_read(rr);
            return 0;
        }

        totalbytes = 0;
        do {
            if (len - totalbytes > SSL3_RECORD_get_length(rr))
                n = SSL3_RECORD_get_length(rr);
            else
                n = len - totalbytes;

            memcpy(buf, &(rr->data[rr->off]), n);
            buf += n;
            if (peek) {
                /* Mark any zero length record as consumed CVE-2016-6305 */
                if (SSL3_RECORD_get_length(rr) == 0)
                    SSL3_RECORD_set_read(rr);
            } else {
                SSL3_RECORD_sub_length(rr, n);
                SSL3_RECORD_add_off(rr, n);
                if (SSL3_RECORD_get_length(rr) == 0) {
                    s->rlayer.rstate = SSL_ST_READ_HEADER;
                    SSL3_RECORD_set_off(rr, 0);
                    SSL3_RECORD_set_read(rr);
                }
            }
            if (SSL3_RECORD_get_length(rr) == 0
                || (peek && n == SSL3_RECORD_get_length(rr))) {
                curr_rec++;
                rr++;
            }
            totalbytes += n;
        } while (type == SSL3_RT_APPLICATION_DATA && curr_rec < num_recs
                 && totalbytes < len);
        if (totalbytes == 0) {
            /* We must have read empty records. Get more data */
            goto start;
        }
        if (!peek && curr_rec == num_recs
            && (s->mode & SSL_MODE_RELEASE_BUFFERS)
            && SSL3_BUFFER_get_left(rbuf) == 0)
            ssl3_release_read_buffer(s);
        *readbytes = totalbytes;
        return 1;
    }
复制代码

 

ssl3_get_record,该函数从socket中读取实际的数据,并执行解密和鉴权的操作,然后得到一条完整的record数据

 

 

 

 

 

 

 

 

 

 

 

posted @   codestacklinuxer  阅读(374)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示