Hi Sudha,
Following are my answers to your questions
Are the assumptions above correct.
No, This is not what I meant. What I mean is, that your send \ recv bio callbacks will call your platform’s network send receive. for custom_mbedtls_net_rcv_timeout
you will call select on one fd. Please look at the example mbedtls_net_rcv_timeout()
, mbedtls_net_rcv()
and mbedtls_net_send()
for reference. These example work on BSD sockets, and if your platform supports BSD socket API, you can use these callbacks with minimal change. The select on the group of FDs will happen on your application layer, in your main thread, after a TLS session has been established already. After select finishes, you will call in your main thread ( or a different thread, as you choose), mbedtls_ssl_write()
and mbedtls_ssl_read()
on each selected FD, separately. Note that mbedtls_ssl_write()
and mbedtls_ssl_read()
call internally the bio callbacks, so you can’t call these function within the callbacks.
In your last sentence, you have mentioned this will NOT require setting your own proprietary bio callback, that part was NOT clear to me. My interpretation is that this custom_mbedtls_net_rcv_timeout will be a custom(proprietary) callback function that will be passed, when calling mbedtls_ssl_set_bio.
This was assuming your platform supports the BSD sockets. If your platform has differnt functions for send \ receive to socket, you will have to have your own custom callbacks. These callbacks are called within the TLS handshake, and from the mbedtls_ssl_write()
and mbedtls_ssl_read()
functions.
Also when you say "call select() (outside the TLS stack), my assumption is that it will be outside the TLS stack, when select gets invoked from this custom_mbedtls_net_rcv_timeout callback function.
No, your functions should look something like the following:
int custom_mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
{
call platform socket write with the FD that is associated with the context
if would block return MBEDTLS_ERR_SSL_WANT_WRITE
handle errors.
return error_code or number of bytes written if succeeded
}
int custom_mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
{
cal platform socket read that is associated with the context
if would block return MBEDTLS_ERR_SSL_WANT_WRITE
handle errors.
return error_code or number of bytes readif succeeded
}
int custom_mbedtls_net_recv_timeout( void *ctx, unsigned char *buf,
size_t len, uint32_t timeout )
{
call platform select with the given timeout on the FD associated with the context
if timeout return MBEDTLS_ERR_SSL_TIMEOUT
return call from custom_mbedtls_net_recv
}
Your main thread:
For every tls connection you are about to negotiate:
call mbedtls_ssl_set_bio with the relevant paramters and callbacks
Once TLS handshake occurs ( probably in different thread, otherwise you will wait for previous handshake to finish until you start a new negotiation).
once you have TLS handshake, you can return to main thread,
You will then call select on all FDs you have that the handshake has finished
After that, call `mbedtls_ssl_write()` and `mbedtls_ssl_read()` , according to the needed functionality
If you can’t have multithread environment, you can consider doing the handshake as part of the select as well, but call mbedtls_ssl_handshake_step()
for every selected handshake ( until handshake is over ), with the associated SSL context, instead of calling mbedtls_ssl_handshake()
which does the whole handshake.
Another approach, for the handshake, is if you use non blocking sockets, and then the handshake will always return with MBEDTLS_ERR_SSL_WANT_WRITE
or MBEDTLS_ERR_SSL_WANT_READ
, and then whenever you get one of these errors, you return to select all the connected FDs, or to next FD with handshake
Note this wasn’t tested, and it might have some glitches, but I hope explained my main idea better.
Regards,
Ron