MbedTLS for sks7g2

Hello

I am in the process of integrating MbedTLS, I could build the test application (using NetxBSD) but mbedtls fails with key validation functions. To mbedTLS with any server certificate and key should be validated at client first.  mbedTLS functions able to verify certificate and CA root certificate but key validation fails.

I think its due to stack size limitation. So my question is

  1. How to check default stack size?  For Thread stack space 1024 is default and can be changed in part of thread creation API.  My function calls to mebdTLS init is non threaded. i.e. before create any application thread I am calling mbedTLS init functions. just like below

       //mbedtls_platform_set_printf
       void tx_application_define_user (void *unused_memory)
       {
               first_unused_memory = unused_memory;
               
               mbedtls_platform_set_calloc_free(threadx_calloc, threadx_free);
               threadx_memory_pool_allocate();


               int mbed_init_err = init_mbedtls_test(); //this function for verify certification  of CA ROOT, X509, Public/Key RSA
               if (mbed_init_err == 0) {
                       tx_thread_resume(&bsd_thread);
               } else {
                    tx_thread_resume(&blinky_thread);
              }
      }

2. I have used "*unused_memory" starting address to allocate enough byte memory pool so mbedtls functions calloc/free can get the required member.  I have verified that wherever mbedtls API calls calloc/free get enough memory to operate.
 
3. Some of the functions has Nested function calls use local struct variables to functions and passing address to other functions.
 
4. Test application built with threax and Netx source as required for Netxbsd. Is possible to change default stack size of threax OS ? OR any compiler options to set or change stack space ?
 
 
Board : SKS7G2
SSP    : 1.2.1
IDE    : E2Studio Version: 5.4.0.018
 
Thanks
Mariya
  • Hello Mariya,

    The mbed library will use the stack of the thread its functions are called from. The main stack size is 4k (specified on the BSP tab) and it's only used during initialization. ISRs will use currently active process stack.

    Use of first_unused_memory pointer is discouraged - in a robust embedded system non-function data should be statically allocated. Creating something like "CHAR mem_pool[4096] BSP_VARIABLE_ALIGN(8); and passing pointer to mem_pool would be much better than solely relying on the pointer provided in the initialization.

    All local data is placed on stack, unless specified as static or const. You should ensure that stack size for TLS caller is sufficiently large. You can use very high values for each thread (i.e. 32k) to begin with and then use RTOS Resources (Renesas Views -> Partner OS) to investigate stack usage after application has run for a while.

    ThreadX does not have its own stack (unless "timer in the ISR" is disabled, then it will allocate some stack for the timer thread) - PendSV handler and tx_thread_schedule (which handle context management) are operating on an active thread stack.

    Regards
  • In reply to Renesas Karol:

    Thanks Karol

    I will make the changes related with memory. is any reason first_unused_memory passed main function ?
    Looks like in future this might be deprecated.

    I could resolve my mbedTLS issue without stack memory changes.

    Looks like there may be bug with mbedTLS code for this platform Renesas SSP/Threadx.
    Same certificate, code works on Windows.

    So I bypassed key validation function for now and trying to check TLS handshake sequence with AWS IoT.
    If not success then I going to revisit mbedtls and check their support forum.

    Thanks
    Mariya
  • In reply to Mariya K:

    Not sure if I should hop on this thread...
    I'm currently evaluating the usage of mbedTLS myself. What steps where needed to compile it into a program for Synergy MPUs in e² Studio? The mbedTLS project supports make/cmake/yotta and Visual C++ builds by default.
    Can we compile it statically somehow and then link it? Can I directly include the sources in my project? What environment variables does one need to set? I suppose there are a lot of interfacing functions or implementations of some unix-like functions I need to wrap to the Synergy platform (see here: tls.mbed.org/.../what-external-dependencies-does-mbedtls-rely-on), but right now I'm mostly wondering about how to set up the project to actually compile it.
  • In reply to ChrisS:

    I have made some progress, I changed all includes inside mbedTLS to point to the correct paths and disabled the feature flags which seemed inappropriate. I included only library and include directories in the build process.

    The project is actually compiling but I expect that most code is not getting linked as I don't use it anywhere yet. I'm now trying to copy some code from example programs to get the linker to include atleast some parts of the mbedTLS code to see if there are linking errors. If this works I'll look into the platform adaption.

    Mariya, do you have any platform adaption code you can share?
  • In reply to ChrisS:

    And one more progress report, I modified net_sockets.h in mbedTLS to use the NetX Duo BSE sockets implementation. It was necessary to compile ThreadX and NetX from source and to set a few options (see X-Ware manuals). Changed a few headers and modified calls to fnctl().
  • In reply to ChrisS:

    Hi ChrisS,

    I actually explored mbedTLS several months ago and could successfully make it work on the S7G2 Starter Kit. But we finally decided to use the NetX Duo TLS stack that was made available with SSP 1.3.0.

    Here are some key points I remember from our experience in porting mbedTLS to the S7G2:

    1- We simply added mbedTLS source files to our e2 Studio project, and added "/mbedtls-2.5.1/include" folder to the project include paths.

    1- Make sure to use quite big stacks for the thread that will be running the mbedTLS stack. We used 32kB stacks.

    2- Carefully review the mbedTLS config file (mbedtls-2.5.1/include/mbedtls/config.h) and adapt it to your need, only enabling what you need. If you use the default one, it is really heavy on CPU memory resources.  I attached the config file we used ourselves.

    3- mbedTLS needs dynamic memory allocation calloc()/free() functions. If you keep default settings, this will end up in your BSP Heap Size if I remember, so make sure to allocate a big amount of memory there with your Synergy Configurator (e.g. 0x10000). On our side, we instead decided to use a ThreadX Byte Pool and use mbedtls_platform_set_calloc_free() to use our own malloc() / free() functions.

    4- You will need to initialize the mbedTLS entropy function to use. On our side, we implemented the function mbedtls_hardware_poll() with the help of the TRNG module available in the SSP. Don't forget to define MBEDTLS_ENTROPY_HARDWARE_ALT in your config file and call mbedtls_entropy_init() before. Here is how our code looked like:

    int mbedtls_hardware_poll( void *data, unsigned char *output, size_t len, size_t *olen )
    {
        uint32_t buffer[8];
        size_t copySize, i = 0U;

        while (i < len)
        {
            UTILS_CHECK_ERROR(g_rng.p_api->read(g_rng.p_ctrl, buffer, UTILS_ARRAY_LENGTH(buffer)));
            copySize = len - i;
            if (copySize > sizeof(buffer))
                copySize = sizeof(buffer);
            memcpy(&output[i], buffer, copySize);
            i += copySize;
        }

        if (olen != NULL)
            *olen = len;
        return 0;
    }

    5- You need to adapt net_sockets(). As you did, we used the NetX Duo BSD sockets implementation. I attached our net_sockets.c file we used.

    6- I don't know if this issue was fixed in latest SSP releases, but take a look to make sure.

    7- Finally, here is how our test function looked like in our app:

    static void testMbedTls(Handle H)
    {
        const char *pers = "ssl_client1";
        int ret, len;
        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, clicert;
        mbedtls_pk_context pkey;
        uint32_t flags;

        /*
         * 0. Initialize the RNG and the session data
         */
        mbedtls_net_init( &server_fd );
        mbedtls_ssl_init( &ssl );
        mbedtls_ssl_config_init( &conf );
        mbedtls_x509_crt_init( &cacert );
        mbedtls_x509_crt_init( &clicert );
        mbedtls_ctr_drbg_init( &ctr_drbg );
        mbedtls_pk_init(&pkey);

        mbedtls_entropy_init( &entropy );
        if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                                   (const unsigned char *) pers,
                                   strlen( pers ) ) ) != 0 )
        {
            log_messagef(LOG_PRINTF, "http: drbg_seed failed: %d" CRLF, ret );
        }

        if (ret == 0)
        {
            /*
             * 0. Initialize certificates
             */
            log_message(LOG_PRINTF, "http: Loading the CA root certificate ..." CRLF);

            ret = mbedtls_x509_crt_parse( &cacert, gCertifNdb, gCertifNdbLen );
            if( ret != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_x509_crt_parse returned -0x%x" CRLF, -ret );
            }
        }

        if (ret == 0)
        {
            log_message(LOG_PRINTF, "http: Loading our own certificate ..." CRLF);

            ret = mbedtls_x509_crt_parse( &clicert, gCertifClient, gCertifClientLen );
            if( ret != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_x509_crt_parse returned -0x%x" CRLF, -ret );
            }
        }

        if (ret == 0)
        {
            log_message(LOG_PRINTF, "http: Loading private key ..." CRLF);

            ret = mbedtls_pk_parse_key( &pkey, gPrivateKeyClient, gPrivateKeyClientLen, "nmdspw", strlen("nmdspw") );
            if( ret != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_pk_parse_key returned -0x%x" CRLF, -ret );
            }
        }

        if (ret == 0)
        {
            /*
             * 1. Start the connection
             */
            log_messagef(LOG_PRINTF, "http: Connecting to tcp/%s/%s..." CRLF, HTTP_SERVER_TEST, HTTPS_SERVER_PORT_STR );

            if( ( ret = mbedtls_net_connect( &server_fd, HTTP_SERVER_TEST,
                                             HTTPS_SERVER_PORT_STR, MBEDTLS_NET_PROTO_TCP ) ) != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_net_connect returned %d\n\n", ret );
            }
        }

        if (ret == 0)
        {
            /*
             * 2. Setup stuff
             */
            log_message(LOG_PRINTF, "http: Setting up the SSL/TLS structure..." CRLF);

            if( ( ret = mbedtls_ssl_config_defaults( &conf,
                            MBEDTLS_SSL_IS_CLIENT,
                            MBEDTLS_SSL_TRANSPORT_STREAM,
                            MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_config_defaults returned %d" CRLF, ret );
            }
        }

        if (ret == 0)
        {
            if ( ( ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey) ) != 0)
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_conf_own_cert returned %d" CRLF, ret );
        }

        if (ret == 0)
        {
            mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
            mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
            mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
        //    mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );

            if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_setup returned %d\n\n", ret );
            }
        }

        if (ret == 0)
        {
            if( ( ret = mbedtls_ssl_set_hostname( &ssl, "SPI3 Central Server Leaf" ) ) != 0 )
            {
                log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_set_hostname returned %d\n\n", ret );
            }
            else
                mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
        }

        if (ret == 0)
        {
            /*
             * 4. Handshake
             */
            log_message(LOG_PRINTF, "http: Performing the SSL/TLS handshake..." CRLF);

            while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
            {
                if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
                {
                    log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_handshake returned -0x%x" CRLF, -ret );
                    break;
                }
                tx_thread_sleep (1);
            }
        }

        if (ret == 0)
        {
            /*
             * 5. Verify the server certificate
             */
            log_message(LOG_PRINTF, "http: Verifying peer X.509 certificate..." CRLF);

            /* In real life, we probably want to bail out when ret != 0 */
            if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 )
            {
                log_message(LOG_PRINTF, "http: FAILED mbedtls_ssl_get_verify_result failed" CRLF );

                mbedtls_x509_crt_verify_info( (char*)H->buffer, BUFFER_SIZE, "  ! ", flags );

                log_messagef(LOG_PRINTF, "http: %s" CRLF, H->buffer);
            }
        }

        if (ret == 0)
        {
            /*
             * 3. Write the GET request
             */
            log_message(LOG_PRINTF, "http: Write to server:"  CRLF);

            len = snprintf( (char *) H->buffer, BUFFER_SIZE, "%s%s%s%s", gGetRequest, gGetRequestAuthToken, H->b64, gCrlfCrlf);
            ASSERT(len >= 0);
            while( ( ret = mbedtls_ssl_write( &ssl, H->buffer, (size_t)len ) ) <= 0 )
            {
                if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
                {
                    log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_write returned %d" CRLF, ret );
                    break;
                }
                tx_thread_sleep (1);
            }

            len = ret;
            log_messagef(LOG_PRINTF, "http: %d bytes written" CRLF, len );
            ret = !(ret > 0);
        }

        if (ret == 0)
        {
            /*
             * 7. Read the HTTP response
             */
            log_message(LOG_PRINTF, "http: Read from server:" CRLF );

            do
            {
                int i;

                len = BUFFER_SIZE - 1;
                memset( H->buffer, 0, BUFFER_SIZE );
                ret = mbedtls_ssl_read( &ssl, H->buffer, (size_t)len );

                if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE )
                {
                    tx_thread_sleep (1);
                    continue;
                }

                if( ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY )
                    break;

                if( ret < 0 )
                {
                    log_messagef(LOG_PRINTF, "http: FAILED mbedtls_ssl_read returned %d" CRLF, ret );
                    break;
                }

                if( ret == 0 )
                {
                    log_message(LOG_PRINTF, "http: EOF" CRLF );
                    break;
                }

                len = ret;
                //log_messagef(LOG_PRINTF, "http: %d bytes read %u" CMON_ENDL, len, (unsigned int)strlen((const char*)H->buffer));

                for (i = 0; i < len; i += LOG_BUFFER_SIZE_MAX)
                {
                    log_messagef(LOG_PRINTF, "%s", (const char*)&H->buffer[i]);
                }

            }
            while( 1 );

            mbedtls_ssl_close_notify( &ssl );
        }

        mbedtls_net_free( &server_fd );

        mbedtls_x509_crt_free( &clicert );
        mbedtls_x509_crt_free( &cacert );
        mbedtls_pk_free( &pkey );
        mbedtls_ssl_free( &ssl );
        mbedtls_ssl_config_free( &conf );
        mbedtls_ctr_drbg_free( &ctr_drbg );
        mbedtls_entropy_free( &entropy );

    }

    2671.mbedtls_files.zip

    I hope this helps.

    Franck

  • In reply to Franck:

    Dear Franck,

    thank you very much for your detailed response! I think this will prove to be quite helpful.
    I'm currently still debugging some socket related issues I need to sort out first.

    You're right that it can be quite heavy on memory requirements. This is actually the biggest problem I'm seeing once I sorted out the functional problems. Right now it takes about 200-250 kB with my somewhat unoptimized config.h and a test based on the ssl_client2.c demo application.
  • In reply to ChrisS:

    Actually the problems I'm seeing might even be caused by the bug about endianess you linked to. I'll have to check this out tomorrow.
  • In reply to ChrisS:

    I managed to connect to a small python HTTPS server now. The problem with the network/host byte order conversion macros still persists for the little endian mode. Using your config and some test code based off ssl_client2.c, this library takes around 100 kB. I will have to perform adjustments because we will need to use TLS 1.2 and the specific algorithms we will use aren't clear yet. I will also try to enable hardware acceleration using the crypto engine where possible.