Since the only reference I have is an example code of bearSSL that is working in PC environment, in order to sort out the problem I am facing that the bearSSL server does not reply to client hello, I’ll have to look inside the source code of bearSSL. After some study, I found that the handshake (the process of negotiation about how the SSL will be implemented before actual SSL communication begin) is processed in the first call to br_sslio_read or br_sslio_write. Before actually pull the messages from the input buffer or put the messages into the output buffer, bearSSL will first check the status of the encryption engine, there are five in total:
i)BR_SSL_CLOSED : the engine is closed.
ii)BR_SSL_SENDREC : the engine is ready to send records to TCP layer.
iii)BR_SSL_RECVREC: the engine is ready to receive records from TCP layer.
iv)BR_SSL_SENDAPP: the engine is ready to write the messages that is to be encrypted into the bearSSL output buffer.
v)BR_SSL_RECVAPP: the engine is ready to read the decrypted messages from the bearSSL input buffer.
Hence instead of reading the decrypted messages which don’t exist yet, the first call to br_sslio_read will figure that the engine is at BR_SSL_RECVREC state, then the engine will read the records in TCP Rx Buffer which is the Client Hello. After parsing the content in Client Hello the engine will generate the corresponding Server Hello (which contain the selected SSL version number, cipher settings, server certificate…). Then the engine reaches BR_SSL_SENDREC state and put the Server Hello message into the TCP Tx Buffer via the low-level write function we provided in br_sslio_init(). Similar step continues as the handshake proceed (verify the certificate, exchange key…), until the handshake is done and the SSL encrypted messages from the client are received and decrypted. Hereafter the engine reaches the BR_SSL_RECVAPP state and br_sslio_read() return with the messages from the client in plaintext.
Here comes our problem: all these processes are done in a single function br_sslio_read(). This is not an issue for PC environment because the communication with TCP layer is dealt by the PC’s operating system simultaneously in some other thread whereas in the embedded environment it all has to be done by ourselves (with the help of Microchip Harmony of course). But we need to run the TCPIP_Stack_Task() in order to send (or receive) the packages in TCP_Tx_Buffer into the wire. Which is why our board server could not reply the Client Hello, the message of Server Hello is actually composed and sit in the TCP_Tx_Buffer already, but I could not run the TCPIP_Stack_Task() in the middle of br_sslio_read() to send it out into the wire, not with a single thread. Hence we stuck in br_sslio_read() as the bearSSL engine waiting for the reply from the client.
Then, I decided to run the bearSSL directly in the RED6 project (instead of the plain tcpip demo) where it has already set up the FreeRTOS operating system that runs multi-thread, here the TCPIP_Stack_Task() (included in System_Task) is run in a separate thread simultaneously. After migration of the code, I program the board and it reboots every time at the creation of CORS thread (yup). The problem happens to be the memory assign to CORS thread is not enough as bearSSL prohibited any dynamic memory allocation, we need at least 16709 byte of memory for bearSSL half-duplex mode I//O buffer (Maximum fragment size is 16kbyte, plus the overhead). The task stack is allocated from the FreeRTOS heap when the task is created, therefore it reboots there. Also, we have to make sure the total heap size of FreeRTOS is enough to accommodate all thread created. These setting are configurable in MHC. Program the board again, finally I see the first capture of bearSSL handshake with Wireshark. Don’t be too happy yet, I still see weird things happen, the br_sslio_write() function run and I observe SSL application data packages traveling from the board to PC via Wireshark yet the curl client reply “empty reply from server”…