Arm Mbed and Pelion Device Management support forum

mbedTLS and MPLABx IDE - PIC32MX MCU

I’m using mbedTLS source files included in my MPLABx project where I use a PIC32MX processor.
I have included the paths for the lib on the project properties of MPLABx.

In order to make an initial compilation, I had to do some alterations, described below.

(1) I have commented these defines on config.h:
MBEDTLS_NO_PLATFORM_ENTROPY
MBEDTLS_NET_C

(2) On net_sockets.c, changed this define value:
#define _POSIX_C_SOURCE 200112L
was changed to:
#define _POSIX_C_SOURCE 199506L

(3) On the MPLABx IDE, went to properties of project, then xc32-gcc compiler properties and placed an additional option for it: -D_POSIX_C_SOURCE=199506L

(4) I had to comment these 3 init functions:

After compile, the flash memory usage increased around 50KB, and I think this is ok for me.

Others:

( A ) This is what happen when I try to compile with line “1” (of the picture) uncommented:
–> undefined reference to `mbedtls_net_init’
When I click on the function “mbedtls_net_init” on main, the cursor goes to its prototype on net_sockets.h, and I can see this function is present on net_sockets.c (its a 1 line function).

( B ) when I try to compile with line “2” uncommented:
–> undefined reference to `mbedtls_entropy_init’
Same case as above. Goes to prototype when click on the function.

( C ) when I try to compile with line “3” uncommented:
–> ‘pers’ undeclared (first use in this function)
What this argument ‘pers’ mean?
I’m imagining I can pass some real random numbers to this function? and the quantity? I have always 12 bytes of random values obtained from RF noise available in a circular buffer. Am I correct? If not, what is the ‘pers’ parameter?

My config.h file was config-mini-tls1_1.h originally.

OBS: My intention is to stablish connection as a TLS/HTTPS client only, no need to act as a webserver.
I would like to receive some orientation to continue from that point.

Regards,
Jeferson.

Hi @abomin3v3l ,

A) Since you commented MBEDTLS_NET_C, then you don’t have mbedtls_net_init() built in your project, as you can see here. net_sockets.c suppolies a BSD like socket module. If your platform doesn’t supply this socket API, then you will need to implement your own bio callbacks for your code. You don’t need to use the mbedtls_net_xxx API, but you will need to supply the bio callbacks for send and receive to mbedtls_ssl_set_bio()

B) Do you have MBEDTLS_ENTROPY_C defined? Note that in cryptography, randomness is a key feature, as a root of trust, and you will need some entropy to supply a seed for your drbg.

B) pers is personalization string, as defined in NIST 800-90A. It is optional and you can be NULL.

Regards,
Mbed TLS Support
Ron

1 Like

Ok, so I will leave “mbedtls_net_init” and “mbedtls_net_xxx” functions commented. Yes, I want to pass the receive and send callbacks to the bio. I want to ask, what does “bio” stands for? And also another question, what should be the prototype of send/receive callbacks? They are functions to send/receive individual bytes? Or vectors? Or something else?

MBEDTLS_ENTROPY_C was commented, so I defined it again on config.h. And the IDE is showed this:
–> #error “Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h” This is related to entropy_poll.c:55

Then I commented MBEDTLS_ENTROPY_C again and defined MBEDTLS_NO_PLATFORM_ENTROPY on config.h. The IDE showed this:
–> undefined reference to `mbedtls_entropy_init’

–> undefined reference to `mbedtls_entropy_func’

Regards.

Hi @abomin3v3l

what should be the prototype of send/receive callbacks? They are functions to send/receive individual bytes? Or vectors? Or something else?

The prototype of the send receive callbacks is defined here and here. These are functions for sending and receiving the data over your transport layer.

error “Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h” This is related to entropy_poll.c:55

You need to define your own entropy function. If your platform has a trng, then you should add your TRNG source. If there isn’t a TRNG in your system, then you should consider using the NV seed feature

Regards

1 Like

Hi @roneld01
For example, on the setups before stablish a connection, one line of code should be this:
mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );

(1) Check if I’m correct:
I would create send/receive callbacks, in my application, like that:

int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len )
AND
int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)

If I’m correct, what should I use as input argument for “*ctx”? Is it “&ctr_drbg” or “&ssl”?

(2) I’m not understanding well on how do I will define the entropy. I have defined "MBEDTLS_NO_PLATFORM_ENTROPY " on config.h just for a test, I don’t know what entropy define to declare. Also, I have a 16-byte buffer containing random numbers, and all these 16 values change each 100ms (around this). I do obtain these numbers from radio-frequency noise. They are pretty random. How do I add my TRNG source?

Thanks and regards.

Hi @abomin3v3l

  1. The prototype of your callbacks is as you showed, but you can name them as you wish ( it is prefered for better readbality) .

If I’m correct, what should I use as input argument for “*ctx”? Is it “&ctr_drbg” or “&ssl”?

Neither, this is an opaque context for yout bio callbacks, that will have whatever data you need for your callbacks. For example, in the Mbed TLS example, it is a wrapper for the socket fd.

  1. If you have MBEDTLS_NO_PLATFORM_ENTROPY , since Mbed TLS doesn’t have a built-in entropy for your platform, for test purposes only you can try setting the unsewcure definition of MBEDTLS_TEST_NULL_ENTROPY. However, if your platform have some entropy source based on your radio-frequency, you can write a wrapper function, as defined in the article I referenced for adding a TRNG source, and as defined here by defining MBEDTLS_ENTROPY_HARDWARE_ALT

Regards

Hi @roneld01

You said:

currently, I have these defines on my config.h:
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT

(1) Does his look ok for you?

(2) When I try to compile, I get to following error:
entropy.c:161: undefined reference to `mbedtls_hardware_poll’
Ok, I know that “mbedtls_hardware_poll” should be a function in my application, and the prototype of this function is:
int mbedtls_hardware_poll ( void *data, unsigned char *output, size_t len, size_t *olen );
I would like to know what is the meaning of each argument? Could you give an example?

Which other tutorials, DOCs, examples I can read to have a guide for my application, considering that my hardware can supply true random numbers to mbedTLS lib?

EDIT: Declaring the function "mbedtls_hardware_poll " on main.c, doing a simple “retorn 0;” inside it, the code compiled, but I need to know the meaning of each parameter.

Regards.

The article I mentioned in previous post, about defining MBEDTLS_ENTROPY_HARDWARE_ALT also mentions:

  • For hardware entropy implementation, implement mbedtls_hardware_poll() in any file that is being compiled as part of the library.

As you mentioned, you should implement a function 'mbedtls_hardware_poll()` in your code, that will wraps a call to your platform TRNG source.
The parameters:

  • data = shouldn’t be used. It is a context for some of the entropy sources, and for the hardware_poll it is NULL
  • output - the output buffer to write the random data to
  • len - The requested length of entropy requested ( usually the size of output)
  • olen - The actual length of buffer filled. (In your case it should probably be the maximum of 16 bytes and the len). Note that if the value is changed ecevery 100 ms, calling this API twice ( in case you need 32 bytes of entropy) in less than 100 ms, might result in a bad entropy seed, as you will receive a duplicate of two identical values.
    Regards

I don’t think Microchip’s PIC32MX family has TRNG and hardware Crypto Engine but the MZ family does.

You’ll have to come up with your own version of random number generator and tie it into mbedTLS using the mbedtls_entropy_add_source() API call.

1 Like

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