Пример #1
0
/* 发送数据
 * * 返回: < 0 错误,0 成功,1 需要重读,2 需要重写
 */
int32 ssl_io::send()
{
    assert( "io send fd invalid",_fd > 0 );

    if ( !_handshake ) return do_handshake();

    size_t bytes = _send->data_size();
    assert( "io send without data",bytes > 0 );
    int32 len = SSL_write( X_SSL( _ssl_ctx ),_send->data_pointer(),bytes );
    if ( expect_true(len > 0) )
    {
        _send->subtract( len );
        return ((size_t)len) == bytes ? 0 : 2;
    }

    int32 ecode = SSL_get_error( X_SSL( _ssl_ctx ),len );
    if ( SSL_ERROR_WANT_WRITE == ecode ) return 2;

    // 非主动断开,打印错误日志
    if ( (SSL_ERROR_ZERO_RETURN == ecode)
        || (SSL_ERROR_SYSCALL == ecode && 0 == errno) )
    {
        return -1;
    }

    SSL_ERROR( "ssl io send" );
    return -1;
}
Пример #2
0
// 返回: < 0 错误,0 成功,1 需要重读,2 需要重写
int32 ssl_io::do_handshake()
{
    int32 ecode = SSL_do_handshake( X_SSL( _ssl_ctx ) );
    if ( 1 == ecode )
    {
        _handshake = true;
        // 可能上层在握手期间发送了一些数据,握手成功要检查一下
        return _send->data_size() > 0 ? 2 : 0;
    }

    /* Caveat: Any TLS/SSL I/O function can lead to either of 
     * SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. In particular, SSL_read() 
     * or SSL_peek() may want to write data and SSL_write() may want to read 
     * data. This is mainly because TLS/SSL handshakes may occur at any time 
     * during the protocol (initiated by either the client or the server); 
     * SSL_read(), SSL_peek(), and SSL_write() will handle any pending 
     * handshakes.
     */
    ecode = SSL_get_error( X_SSL( _ssl_ctx ),ecode );
    if (  SSL_ERROR_WANT_READ == ecode ) return 1;
    if ( SSL_ERROR_WANT_WRITE == ecode ) return 2;

    // error
    SSL_ERROR( "ssl io do handshake:" );

    return -1;
}
Пример #3
0
/* 接收数据
 * * 返回: < 0 错误,0 成功,1 需要重读,2 需要重写
 */
int32 ssl_io::recv()
{
    assert( "io recv fd invalid",_fd > 0 );

    if ( !_handshake ) return do_handshake();

    if ( !_recv->reserved() ) return -1; /* no more memory */

    // ERR_clear_error
    uint32 size = _recv->buff_size();
    int32 len = SSL_read( X_SSL( _ssl_ctx ),_recv->buff_pointer(),size );
    if ( expect_true(len > 0) )
    {
        _recv->increase( len );
        return 0;
    }

    int32 ecode = SSL_get_error( X_SSL( _ssl_ctx ),len );
    if ( SSL_ERROR_WANT_READ == ecode ) return 1;

    /* https://www.openssl.org/docs/manmaster/man3/SSL_read.html
     * SSL连接关闭时,要先关闭SSL协议,再关闭socket。当一个连接直接关闭时,SSL并不能明确
     * 区分开来。SSL_ERROR_ZERO_RETURN仅仅是表示SSL协议层关闭,连接并没有关闭(你可以把一
     * 个SSL连接转化为一个非SSL连接,参考SSL_shutdown)。正常关闭下,SSL_read先收到一个
     * SSL_ERROR_ZERO_RETURN转换为普通连接,然后read再收到一个0。如果直接关闭,则SSL返回
     * 0,SSL_get_error检测到syscall错误(即read返回0),这时errno为0,SSL_get_error并返
     * 回0。
     */

    // 非主动断开,打印错误日志
    // 在实际测试中,chrome会直接断开链接,而firefox则会关闭SSL */
    if ( (SSL_ERROR_ZERO_RETURN == ecode)
        || (SSL_ERROR_SYSCALL == ecode && 0 == errno) )
    {
        return -1;
    }

    SSL_ERROR( "ssl io recv" );
    return -1;
}
Пример #4
0
Файл: tlsIO.c Проект: fahkri/tls
static int
TlsOutputProc(ClientData instanceData,	/* Socket state. */
              CONST char *buf,		/* The data buffer. */
              int toWrite,		/* How many bytes to write? */
              int *errorCodePtr)	/* Where to store error code. */
{
    State *statePtr = (State *) instanceData;
    int written, err;

    *errorCodePtr = 0;

    dprintf(stderr,"\nBIO_write(0x%x, %d)", (unsigned int) statePtr, toWrite);

    if (statePtr->flags & TLS_TCL_CALLBACK) {
       /* don't process any bytes while verify callback is running */
       written = -1;
       *errorCodePtr = EAGAIN;
       goto output;
    }

    if (!SSL_is_init_finished(statePtr->ssl)) {
	written = Tls_WaitForConnect(statePtr, errorCodePtr);
	if (written <= 0) {
	    goto output;
	}
    }
    if (statePtr->flags & TLS_TCL_INIT) {
	statePtr->flags &= ~(TLS_TCL_INIT);
    }
    if (toWrite == 0) {
	dprintf(stderr, "zero-write\n");
	BIO_flush(statePtr->bio);
	written = 0;
	goto output;
    } else {
	/*
	 * We need to clear the SSL error stack now because we sometimes reach
	 * this function with leftover errors in the stack.  If BIO_write
	 * returns -1 and intends EAGAIN, there is a leftover error, it will be
	 * misconstrued as an error, not EAGAIN.
	 *
	 * Alternatively, we may want to handle the <0 return codes from
	 * BIO_write specially (as advised in the RSA docs).  TLS's lower level
	 * BIO functions play with the retry flags though, and this seems to
	 * work correctly.  Similar fix in TlsInputProc. - hobbs
	 */
	ERR_clear_error();
	written = BIO_write(statePtr->bio, buf, toWrite);
	dprintf(stderr,"\nBIO_write(0x%x, %d) -> [%d]",
		(unsigned int) statePtr, toWrite, written);
    }
    if (written <= 0) {
	switch ((err = SSL_get_error(statePtr->ssl, written))) {
	    case SSL_ERROR_NONE:
		if (written < 0) {
		    written = 0;
		}
		break;
	    case SSL_ERROR_WANT_WRITE:
		dprintf(stderr," write W BLOCK");
		break;
	    case SSL_ERROR_WANT_READ:
		dprintf(stderr," write R BLOCK");
		break;
	    case SSL_ERROR_WANT_X509_LOOKUP:
		dprintf(stderr," write X BLOCK");
		break;
	    case SSL_ERROR_ZERO_RETURN:
		dprintf(stderr," closed\n");
		written = 0;
		break;
	    case SSL_ERROR_SYSCALL:
		*errorCodePtr = Tcl_GetErrno();
		dprintf(stderr," [%d] syscall errr: %d",
			written, *errorCodePtr);
		written = -1;
		break;
	    case SSL_ERROR_SSL:
		Tls_Error(statePtr, SSL_ERROR(statePtr->ssl, written));
		*errorCodePtr = ECONNABORTED;
		written = -1;
		break;
	    default:
		dprintf(stderr," unknown err: %d\n", err);
		break;
	}
    }
    output:
    dprintf(stderr, "\nOutput(%d) -> %d", toWrite, written);
    return written;
}
Пример #5
0
Файл: tlsIO.c Проект: fahkri/tls
static int
TlsInputProc(ClientData instanceData,	/* Socket state. */
	char *buf,			/* Where to store data read. */
	int bufSize,			/* How much space is available
					 * in the buffer? */
	int *errorCodePtr)		/* Where to store error code. */
{
    State *statePtr = (State *) instanceData;
    int bytesRead;			/* How many bytes were read? */

    *errorCodePtr = 0;

    dprintf(stderr,"\nBIO_read(%d)", bufSize);

    if (statePtr->flags & TLS_TCL_CALLBACK) {
       /* don't process any bytes while verify callback is running */
       bytesRead = 0;
       goto input;
    }

    if (!SSL_is_init_finished(statePtr->ssl)) {
	bytesRead = Tls_WaitForConnect(statePtr, errorCodePtr);
	if (bytesRead <= 0) {
	    goto input;
	}
    }
    if (statePtr->flags & TLS_TCL_INIT) {
	statePtr->flags &= ~(TLS_TCL_INIT);
    }
    /*
     * We need to clear the SSL error stack now because we sometimes reach
     * this function with leftover errors in the stack.  If BIO_read
     * returns -1 and intends EAGAIN, there is a leftover error, it will be
     * misconstrued as an error, not EAGAIN.
     *
     * Alternatively, we may want to handle the <0 return codes from
     * BIO_read specially (as advised in the RSA docs).  TLS's lower level BIO
     * functions play with the retry flags though, and this seems to work
     * correctly.  Similar fix in TlsOutputProc. - hobbs
     */
    ERR_clear_error();
    bytesRead = BIO_read(statePtr->bio, buf, bufSize);
    dprintf(stderr,"\nBIO_read -> %d", bytesRead);

    if (bytesRead < 0) {
	int err = SSL_get_error(statePtr->ssl, bytesRead);

	if (err == SSL_ERROR_SSL) {
	    Tls_Error(statePtr, SSL_ERROR(statePtr->ssl, bytesRead));
	    *errorCodePtr = ECONNABORTED;
	} else if (BIO_should_retry(statePtr->bio)) {
	    dprintf(stderr,"RE! ");
	    *errorCodePtr = EAGAIN;
	} else {
	    *errorCodePtr = Tcl_GetErrno();
	    if (*errorCodePtr == ECONNRESET) {
		/* Soft EOF */
		*errorCodePtr = 0;
		bytesRead = 0;
	    }
	}
    }
    input:
    dprintf(stderr, "\nInput(%d) -> %d [%d]", bufSize, bytesRead, *errorCodePtr);
    return bytesRead;
}