Mbed TLS is now part of TrustedFirmware.org.

Why Different write and read styles


Jan 6, 2018 09:06
phani

In ssl_client2.c while doing a DTLS, write api is called like this,


 do ret = mbedtls_ssl_write( &ssl, buf, len );
        while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
               ret == MBEDTLS_ERR_SSL_WANT_WRITE );

But a TLS write is called like this..


for( written = 0, frags = 0; written < len; written += ret, frags++ )
        {
            while( ( ret = mbedtls_ssl_write( &ssl, buf + written, len - written ) )
                           <= 0 )//if any error c0de is returned (including WANT_WRITE/READ)..
            {
                if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
                    ret != MBEDTLS_ERR_SSL_WANT_WRITE )
                {
                    mbedtls_printf( " failed\n  ! mbedtls_ssl_write returned -0x%x\n\n", -ret );
                    goto exit;
                }
            }
        }

why is it that in a DTLS call, parameters are not updated like in TLS write? whats the difference here?

And for read api too,


if( opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM )
    {
        mbedtls_printf(" &&&&&&&& outside read 0x%x\n", buf);

        do
        {
            len = sizeof( buf ) - 1;
            memset( buf, 0, sizeof( buf ) );
            ret = mbedtls_ssl_read( &ssl, buf, len );
            if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
               ret == MBEDTLS_ERR_SSL_WANT_WRITE )
                continue;**

            if( ret <= 0 )
            {
                switch( ret )
                {
                    case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
                        mbedtls_printf( " connection was closed gracefully\n" );
                        ret = 0;
                        goto close_notify;

                    case 0:
                    case MBEDTLS_ERR_NET_CONN_RESET://connection lost
                        mbedtls_printf( " connection was reset by peer\n" );
                        ret = 0;
                        goto reconnect;

                    default:
                        mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", -ret );
                        goto exit;
                }
            }

            len = ret;
            buf[len] = '\0';
            mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf );

            /* End of message should be detected according to the syntax of the
             * application protocol (eg HTTP), just use a dummy test here. */
            if( ret > 0 && buf[len-1] == '\n' )
            {
                ret = 0;
                break;
            }
        }
        while( 1 );
    }
    else /* Not stream, so datagram */
    {
        len = sizeof( buf ) - 1;
        memset( buf, 0, sizeof( buf ) );

        do ret = mbedtls_ssl_read( &ssl, buf, len );
        while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
               ret == MBEDTLS_ERR_SSL_WANT_WRITE );

        if( ret <= 0 )
        {
            switch( ret )
            {
                case MBEDTLS_ERR_SSL_TIMEOUT:
                    mbedtls_printf( " timeout\n" );
                    if( retry_left-- > 0 )
                        goto send_request;
                    goto exit;

                case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
                    mbedtls_printf( " connection was closed gracefully\n" );
                    ret = 0;
                    goto close_notify;

                default:
                    mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", -ret );
                    goto exit;
            }
        }

        len = ret;
        buf[len] = '\0';
        mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf );
        ret = 0;
    }

I see only the handling of errors being different in the above code snippet.The read api itself could have been done in a single loop right?

 
Jan 7, 2018 08:56
Ron Eldor

Hi phani,
The sample applications are for reference only, and it is the user's responsibility to handle the error codes of mbedtls_ssl_read() and mbedtls_ssl_write().
I remind you that DTLS is used over unreliable connections, such as UDP, while TLS is used over reliable connections, such as TCP.
This means, that when you send messages in TLS, you know for sure that the packets were sent, and you can send the next packets.
On DTLS, on the other-hand, when you send packets, you aren't guaranteed that they were sent, hence, the different handling in writing the packets.
On the read code snippet, I believe you are correct, and the read api could have been done in a single loop.
Regards,
Mbed TLS Team member
Ron

 
Jan 7, 2018 11:04
phani

Isnt it that write too can be written in a single loop, because DTLS write is looping if WANT_WRITE/READ is returned, which the TLS write too is doing for the same ERROR CODES.

You said that different handling in TLS/DTLS write is due to the reason that in DTLS we have no guarantee that the packets reached the server... But we cant do anything about this right ? RFC-6347 says - "DTLS only uses retransmission for handshake and not dataflow"

Then why the need to handle them separately if there is no retrasmission ?