Arm Mbed OS support forum

mbedTLS and MPLABx IDE - PIC32MX MCU

Hi. @roneld01 and @acpie360
I have implemented a random number generator from RF noise on my board. And it is working.
I can increase the size of my buffer from 16 to 32 bytes (or even 64 if needed), in order every time I need a seed there will be 32 bytes ready to be read from that buffer. A question, the values of the individual bytes of the random data can range from 0 to 255? Or do these bytes need to be characters only?

@roneld01 Thanks so much for your help until here.

Would mbedtls_hardware_poll look like this? What should happen when “len > *olen” , whats the commomly used values for len? Can it be limited to 32?

EDIT: Or maybe like this… Never write more than len bytes, and limit on 32.

Regards.

Numbers should do. I am pretty sure they don’t have to be ASCII characters.

1 Like

HI @abomin3v3l
As mentioned correctly by @acpie360 , The random buffer is a binary byte buffer, which means every byte is a buffer should have a value from 0 to 255. This is not a string

olen is the size of the actual buffer filled, and since len is the size of the buffer given as input, olen cannot exceed the length of len, but it can not be larger than what your platform can actually generate. So, your second example the correct one.

What should happen when “len > *olen” , whats the commomly used values for len?

As you can see here, the default maximal threashold value is 32. However, the value MBEDTLS_ENTROPY_MAX_GATHER ( default 128 is requested, but this is configurable) is given as len. But, if the threshold is reached or got enough entropy (can be maximal 64 bytes), then no more collection. So, if you can set the collection to 64 bytes, it would be best.
Regards

1 Like

@roneld01 Thanks.
I think the first part is finished, the initial setup called before main loop.

mbedtls_hardware_poll() ended to be:

Then I can remove this:
02

And added mbedtls_entropy_func():
Please check the comment.
03

Changed TRNG buffer to 64 bytes, circular store and reads.
After this, 12KB of flash memory usage became free.

Regards.

Hi @roneld01

On the picture below, should I not use ‘2’? If yes, what is the correct sequence? 1-3 or 3-1?
On SERVER_NAME, I will use “abomin3v3l-3e161.firebaseio.com”, do I need to put “https://” in front?
Compiler says “undefined reference to `mbedtls_net_connect’”

On the picture below, compiler says “undefined reference to `mbedtls_x509_crt_parse_file’”
CERT

And I did not understood how to use that funcion:

And a final observation: I have MBEDTLS_FS_IO define commented on my config.h and MBEDTLS_NET_C also commented.

On the declaration: const char *cafile = “/path/to/trusted-ca-list.pem”;
Should I use, for instance, in place of “/path/to/trusted-ca-list.pem” use the content of c00.pem?

Thanks very much and regards.

Hi @abomin3v3l

And added mbedtls_entropy_func()

Mbed Crypto already supplies this function as part of Mbed TLS. This function gathers all the entropy, and conditions it into a proper seed. This is not what you did in your implementation. Please don’t replace it unless you have a very good reason. If you replace it for some reason, you actually don’t need mbedtls_hardware_poll().

Compiler says “undefined reference to `mbedtls_net_connect’”

That’s because you have ‘MBEDTLS_NET_C’ undefined. You will need to use your own connection method to your socket, like you did in “2”

On SERVER_NAME, I will use “abomin3v3l-3e161.firebaseio.com”, do I need to put “https://” in front?

There is a difference between SERVER_NAME and SERVER_ADDR. The server name is the host name, which is also checked in the certificate. Only the name, without the protocol prefix should be set. The server_addr is the address which you connect to in your transport layer. If you can connect only with that, then this is fine, otherwise, add the prefix.

On the picture below, compiler says “undefined reference to `mbedtls_x509_crt_parse_file’”

This is because you have MBEDTLS_FS_IO undefined. If you don’t have IO functionality, you should use mbedtls_x509_crt_parse() on your CA certificate which you have in a buffer.

And I did not understood how to use that function:

As shown in the example, the chain parameter is a pointer to a mbedtls_x509_crt struct which will hold the parsed information. The path parameter is a string of the path of your certificate file

On the declaration: const char *cafile = “/path/to/trusted-ca-list.pem”;
Should I use, for instance, in place of “/path/to/trusted-ca-list.pem” use the content of c00.pem?

If you are using a file, then the cafile should point to the path, not the content. If you don’t have IO , then your deceleration should be ‘const char cafile[] = content of c00.pem’ as shown in the test certificate example. (For a simpler example, you can look at the Mbed-OS client example application), however it is C++ style String

Regards

1 Like

Hi @roneld01, I really appreciate your help.

Now it is compiling, and I think I just need to implement mbedtls_net_send and mbedtls_net_recv. I created a function called TLSCLose, which will be called when any error occur on rx/tx functions and also to close the communication with the server.

As I know, before sending and receiving encrypted packets we need to make a little setup before. Check my current setup below, is that sufficient? Is there something ele missing?

As I currently use bare-metal programming style, I will need to implement read/write functions in a way they never stucks the program flux.

Regards,
Jeferson

Hi @abomin3v3l

You are missing the entropy initialization and setup, however I am assuming it is before this code segment.
Please look at the ssl client example for the ssl configuration functions that are used, as it is dependent on what your needs in your client are.

Do you call after that mbedtls_ssl_setup()?

As for your comment:

DO I NEED THIS IF I’M CLIENT ONLY?

yes, you do. This should be the root certificate of the CA that signed your server certificate. This should be a trusted certificated, that you can set in your client, when the server sends it certificate, it is verified against your trusted certificate, to confirm the server is trusted.

If you are using baremetal, I am assuming you have RAM limitations, so I would suggest you use DER format certificates instead of PEM.

Regards

1 Like

You shouldn’t copy a PEM formatted cert and paste the content directly into a C style string. You need to add ‘\n’ at the end of each line or the parser will fail.

const unsigned char some_root_ca[] =
"-----BEGIN CERTIFICATE-----\n\
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n\
...
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n\
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n\
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n\
-----END CERTIFICATE-----";
1 Like

@acpie360 Thanks very much for note this. “\n”? or maybe “\r\n”? or maybe both will work?

@roneld01
Thanks, I have added mbedtls_ssl_setup.

Now, regarding mbedTLS, I have the following in my project:

mbedtls_net_context server_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;
int mbedtls_hardware_poll (void *data, unsigned char *output, size_t len, size_t *olen) 
{
    data = NULL;                
    
    uint16_t i = 0;
    
    //supply up to 64 numbers, and a maximum of 'len' bytes (requested)
    while (i < ManchesterRandomNumberQty && i < len) 
    {
        *(output+i) = ManchesterReadRandomNumber(DECOD_MANCHESTER());
        i++;
    }
    
    *olen = i;
    return 0;
}
void my_debug ( void *ctx, int level, const char *file, int line, const char *str ) 
{ 
    //((void) level); 
    fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str ); fflush( (FILE *) ctx ); 
}
void TLSClose (void) 
{
    mbedtls_ssl_free( &ssl );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_ssl_config_free( &conf );
    mbedtls_entropy_free( &entropy );    
}
int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len ) 
{
   
}
int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) 
{
    
}

These are called one time at MCU startup:

mbedtls_ssl_init( &ssl );
mbedtls_ssl_config_init( &conf );
mbedtls_x509_crt_init( &cacert );
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_entropy_init( &entropy );

And before sending/receive data to/from the server:

//------------------------------------------------------------------------
        //TLS - CONNECTION SETUP
        if( ( ret = mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { }
        mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_REQUIRED );
        mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
        if( ( ret = mbedtls_ssl_set_hostname( &ssl, "abomin3v3l-3e161.firebaseio.com" ) ) != 0 ) {  }
        mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
        //------------------------------------------------------------------------

        
        //------------------------------------------------------------------------
        //TLS - SERVER CERTIFICATE AUTHORITY
        const char cafile[] = "-----BEGIN CERTIFICATE-----MIIBpTCCAUugAwIBAgIJAPygloXKk6BwMAoGCCqGSM49BAMCMC8xCzAJBgNVBAYTAlVLMREwDwYDVQQKDAhtYmVkIFRMUzENMAsGA1UEAwwEQ0EwMDAeFw0xNzA2MjIxMTUwMzJaFw0yNzA2MjMxMTUwMzJaMC8xCzAJBgNVBAYTAlVLMREwDwYDVQQKDAhtYmVkIFRMUzENMAsGA1UEAwwEQ0EwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFW41/qAwAPpy+Txdc7PKmzZsq9CPiujKU4vpF1ekXnGx2HP420QobwBVVWhkzRmLwdboH2j65dcCKjQ7mv/dxKjUDBOMB0GA1UdDgQWBBQlFYvU5WboI4fcdPoiQs8/fPHZrTAfBgNVHSMEGDAWgBQlFYvU5WboI4fcdPoiQs8/fPHZrTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQC7iRcVzwMyfVK5imirJ7MqJQ04euH4CLOtIZ+SNfaERAIgSU0MWFDosVEIpg8YMqIHeF7Mg4ZyH6+fGazJgVLttUY=-----END CERTIFICATE-----"; 
        
        mbedtls_x509_crt_init( &cacert );
        if( ( ret = mbedtls_x509_crt_parse( &cacert, cafile, strlen(cafile)+1 ) ) != 0 ) { }
        mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
        //------------------------------------------------------------------------


        mbedtls_ssl_setup(&ssl, &conf);

I just need to implement rx/tx functions now? Do you see something else missing?

Regards.

Hi @abomin3v3l

“\n”? or maybe “\r\n”? or maybe both will work?

I woudl used \r\n , for portability between systems, however I blieve both should work.

Do you see something else missing?

You are missing the seeding of your drbg function. Please follow all the steps in the example.

Regards

1 Like

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.