mbedTLS and MPLABx IDE - PIC32MX MCU

Hi. @roneld01

Do you mean on initial setup of MCU?

mbedtls_ssl_init( &ssl );
mbedtls_ssl_config_init( &conf );
mbedtls_x509_crt_init( &cacert );
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_entropy_init( &entropy );
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 ) ) != 0 ) {  }

Regards.

Now it is ok?

Yes, you can put it in the intial setup.
as for //TLS - CONNECTION SETUP , Note this should be done before you establish a TLS connection, not before every time you want to send/receive data to/from the server (Unless I misunderstood your sentence regarding this)

As for checking whether your code is ok, I am sorry but I cannot confirm, as we cannot be liable for your code, however in general it looks ok. You should compare with the sample application whether you missed anything else or not. and whether there are features you haven’t added.
Regards

1 Like

Yes, I understand like you said.

Now, I’m in doubt on how to implement:
mbedtls_net_send(void *ctx, const unsigned char buf, size_t len )
mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)

There is no implementation of these functions of the example ssl_client2. What do I need to do with ctx?

For example, supposing I want to send a string, some function of the lib would receive my original string, then encrypt it and then send it encrypted? Maybe there are some misleading of my part here.

Let me explain a little about how my system work.

I have the PIC32MX MCU connected to an ESP-01 wifi module using one Uart/Serial, and my goal is to connect to a Firebase server and send data to it, I will give an example.

To open a websocket with the database, the MCU send string “AT+CIPSTART="TCP","abomin3v3l-3e161.firebaseio.com",443\r\n” (or it can be “AT+CIPSTART=“TCP”,“https://abomin3v3l-3e161.firebaseio.com”,443”, this will result the same) to ESP-01 module, then ESP responds “CONNECTED\r\nOK\r\n”. At this point the connection is stablished and I can send the HTTP content (header+data), but as Googles’s Firebase requires HTTPS, I need to send that data encrypted, I think here is where mbedTLS will operate.

I am simulating write to my database with Postman and it is working, and the content of my test-packet is:

PUT /January.json?auth=DZSQwLoNWAneWA9BcEfAgnelmY965pq98HF4pITU HTTP/1.1
Host: eletronica-ab6b1.firebaseio.com
Content-Type: application/json

{"name":"jeferson"}

I want to send the same content to the database, but using the MCU.

After the websocket is open with the server, if I want to send the text above, as it has 166 bytes, I need to send to the ESP-01 module:

(a) “AT+CIPSEND=166”
(b) send the content, 166 bytes, and it will be sent out to the server.

When I want to finish the websocket, I can send “AT+CIPCLOSE” to the ESP-01 module then the websocket will be closed.

When the server reply, the ESP receive them and send these packets entirely to PIC32MX via Uart, which will store every packet received in a circular buffer.

So I’m in doubt on how to write mbedtls_net_send (and also mbedtls_net_rcv). It is not clear for me on how the TLS will receive a raw packet, encrypt, and send it encrypted using the functions to be implemented.

And as I said, maybe there are some misleading from my part about these things yet.

Thanks very much and regards.

HI @abomin3v3l

Note that Mbed TLS does the TLS handshake, and then the encryption. Once the data is encrypted, it sends it through the send callback.
The recv callback will read the encrypted data from the transport layer, and copy it to its output buffer, where the library itself will decrypt it.
In your case, your callbacks should wrap the calls to AT commands.
Note: If your modem supports TLS, then it means it can handle the TLS negotiation by itself, and send the data encrypted. However, if you are using Mbed TLS for the TLS negotiation, then you shouldn’t use the TLS feature of thew modem.
Regards

1 Like

Hi @roneld01, thanks.
I was aware of these things.

My doubt still persists. I understood that when mbedTLS wants to send data it will use the send callback. But how is done to actually transmit a packet in the application? How to tell to mbedTLS that I want to send a given raw string? So that the lib will receive that string, encrypt and send using send callback, and do the negotiation before if required.

Regards.

HI @abomin3v3l
This is exactly what you need to do in you callbacks

Your recv callback should look like this:

read the encrypted data from the transport layer into the output buffer (using AT commands)
Your send callback should look like this:
write the encrypted data to the transport layer( using AT commands)

The encryption part is already done as in the TLS library. In abstract flow:
mbedtls_ssl_write:

get plain data to send as buf parameter
encrypt data
call f_send callback with the encrypted data as buf parameter

mbedtls_ssl_read:

callf_recv callback with encrypted data to buf parameter
decreypt data and copy it to the buf parameter of mbedtls_ssl_read

You need to implement the part where you read \ send the encrypted data with AT command and copy to \from the buf parameter

Once you set these callbacks, Mbed TLS will know to use these callbacks within its API, to send\recv the encrypted data
Regards

1 Like

@roneld01 thanks very much.
I understood your explanation. How to encrypt/decrypt data? Which functions of the lib to use?

Regards.

Hi @abomin3v3l
You don’t encrypt and decrypt the data. The library does it for you. This is the purpose of the TLS stack - it handles all the TLS related parts.
All you need to do is to call mbedtls_ssl_write() to send data, and mbedtls_ssl_read() to receive data, as shown in the example
Regards

1 Like

Hi @roneld01.

Sorry for my misunderstanding. I was confusing mbedtls_ssl_write with the send callback.
Transmit is ok, now my doubt is about the receiving callback.

Please tell me if the following is correct:
Every byte the MCU receives from the wifi module is put in a buffer that I will call here as buf_a (receives individual bytes via Uart interrupts). Supposing the MCU has received 130 bytes of response, then buf_a is holding 130 bytes at this point. Then, the next time mbedtls_net_recv be called, inside this function I will write 130 bytes from buf_a to ‘buf’ inside mbedtls_net_recv. Write no more than ‘len’ bytes to this buffer, and finally return the number of bytes that were written to buf. Can be like this?

I was checking ssl_client1.c example, where is shown steps 4. Handshake and 5. Verify the server certificate. I have not implemented these steps in my code.

Regards.

Hi @abomin3v3l

Supposing the MCU has received 130 bytes of response, then buf_a is holding 130 bytes at this point. Then, the next time mbedtls_net_recv be called, inside this function I will write 130 bytes from buf_a to ‘buf’ inside mbedtls_net_recv . Write no more than ‘len’ bytes to this buffer, and finally return the number of bytes that were written to buf. Can be like this?

Yes. Assuming your sockets are blocking, and not event driven, and single threaded, then this is the general thing that should happen, as shown in mbedtls_net_recv. If possible, you chould consider writing from the MCU directly to buf , and avoid n additional memcpy().

As for not implementating steps 4, and 5, although mbedtls_ssl_read() does the TLS handshake if not done yet (and also mbedtls_ssl_write()), I would recomend you explicitely call mbedtls_ssl_handshake() as shown in step 4, and step 5, is mostly to know why server certification failed, if at all. and you should fail the connectionfor security reasons, if the server is not trusted, as shown in the example.
Regards

If the MCU receives x number of bytes, it should put them into a FIFO buffer. The receive callback function first checks the FIFO to see if the buffer contains any data. If the buffer has no data, return MBEDTLS_ERR_SSL_WANT_READ. If the buffer has data but less than what the caller is asking, return the caller what you have. If the buffer has more data than the caller is asking, only return the number of bytes the caller is asking.

The way mbedTLS processes incoming data is to first ask for 5 bytes to see if it has a valid SSL record header. If a record header is valid, it then knows how many bytes to expect. For example, if the record header indicates the payload is 1000 bytes. TLS would ask for 1000 bytes. If your FIFO only has 100 bytes at the time, you’ll send 100 bytes back. TLS then asks for 900 bytes the next time, so on and so forth, until it gets all 1000 bytes. This completes the receiving of a SSL record.

Hope this makes sense to you.

2 Likes

Thanks for some very useful information, I’m also using a PIC32MX for my project and my modem has an automatic ntp time set. Using this function I convert the date/time from the modem into unix time and use that to seed my copy of glibc’s getentropy. xc32 already has a prototype for time in time.h, I just defined my own time() around that prototype. So just in case it’s useful:
#include “ssl_entropy.h”
//#include “gsm.h”

uint8_t entbuf[256];
unsigned int seed;
#define epoch_year 1970

/* Write LENGTH bytes of randomness starting at BUFFER. Return 0 on

  • success and -1 on failure. */
    int getentropy (void buffer, size_t length)
    {
    seed = tls_getseed();
    /
    The interface is documented to return EIO for buffer lengths
    • longer than 256 bytes.  */
      
if (length > 256)
{

// __set_errno (EIO);
return -1;
}
//void srand(unsigned int seed);
srand(seed);

/* Try to fill the buffer completely.  Even with the 256 byte limit
 *     above, we might still receive an EINTR error (when blocking
 *     during boot).  */
unsigned int x;
void *end = buffer + length;
int *buff2 = buffer;

while (buffer < length)
{
    x = rand();
    *buff2 = x;
    buff2++;
    buffer++;
	/* Try again in case of a short read.  */
;
}
return 0;

}
unsigned int tls_getseed(void)
{
seed = time(NULL);
return seed;
}

time_t time(time_t *tloc)
{
//We only return a time_t integer not a tloc
if(tloc != NULL)
{
return -1;
}
gsm_msg((uint8_t
)clockr);
gsm_receive(2,entbuf);

time_t result;

unsigned int actyear;
unsigned int months;
unsigned int leapdays;
unsigned int days;
unsigned int seconds;
unsigned int mday;
unsigned int hours;
unsigned int minutes;
unsigned int secs;

actyear = (((entbuf[8] & 0x0F) * 10) + (entbuf[9] & 0x0F) + 2000);
months = ((entbuf[11] & 0x0F) * 10) + (entbuf[12] & 0x0F) - 1;// Month, where 0 = jan
mday = ((entbuf[14] & 0x0F) * 10) + (entbuf[15] & 0x0F);// Day of the month
hours = ((entbuf[17] & 0x0F) * 10) + (entbuf[18] & 0x0F);
minutes = ((entbuf[20] & 0x0F) * 10) + (entbuf[21] & 0x0F);
secs = ((entbuf[23] & 0x0F) * 10) + (entbuf[24] & 0x0F);

leapdays = (actyear - 1968) / 4;
days = ((actyear - 1970) * 365) + (months * 30) + leapdays + mday + 1;//Where do I loose the 1 day?
seconds = days * 86400;
seconds = seconds + (hours * 60 * 60) + (minutes * 60) + secs;
result = (time_t)seconds;
return result;

}