Arm Mbed and Pelion Device Management support forum

mbedTLS + NUCLEO-F401RE + SIM800

Hello,
First of all thanks for providing mbedTLS.

I am trying to use it with bare metal STM32 Nucleo-F401RE and a SIM800 GSM modem for HTTPS GET/POST.

I will try to do a quick sum-up of where I am and where I am stuck. Also, I hope that this post helps others in similar position.

  • I am trying to make an HTTPS GET here.
  • So far, I am able to create an SSL context, and parse the public key, as well as root CA like so (please ignore the custom ugly prints. Also, the code is based on this example)
int ret, flags, len;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_pk_context pk;
mbedtls_x509_crt cacert;
mbedtls_net_context server_fd;

mbedtls_ssl_init(&ssl);
mbedtls_pk_init(&pk);
mbedtls_x509_crt_init(&cacert);
mbedtls_ssl_config_init(&conf);

custom_print("Parsing public key...\r\n");
ret = mbedtls_pk_parse_public_key(&pk, myPubKey, myPubKeyLen);
if (ret < 0) {
    sprintf(buf2, "mbedtls_pk_parse_public_key returned -0x%x\n\n", -ret);
    custom_print(buf2);
    memset(buf2, 0, sizeof(buf2));
}
custom_print("pubkey OK");

custom_print("Parsing CA root...\r\n");
ret = mbedtls_x509_crt_parse(&cacert, myCert, myCertlen + 1);
if (ret < 0) {
    sprintf(buf2, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
    custom_print(buf2);
    memset(buf2, 0, sizeof(buf2));
}
custom_print("CA OK");

custom_print("Setting hostname for TLS session...\r\n");
/* Hostname set here should match CN in server certificate */
if ((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) {
    sprintf(buf2, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
    custom_print(buf2);
    memset(buf2, 0, sizeof(buf2));
}
custom_print("hostname OK");

custom_print("Setting up the SSL/TLS structure...");
if ((ret = mbedtls_ssl_config_defaults(&conf,
                                       MBEDTLS_SSL_IS_CLIENT,
                                       MBEDTLS_SSL_TRANSPORT_STREAM,
                                       MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
    sprintf(buf2, "mbedtls_ssl_config_defaults returned %d", -ret);
    custom_print(buf2);
    memset(buf2, 0, sizeof(buf2));
}
custom_print("SSL/TLS structure OK");

custom_print("Setting up SSL...");
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); /* bad bad */
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
    sprintf(buf2, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
    custom_print(buf2);
    memset(buf2, 0, sizeof(buf2));
}
custom_print("SSL setup OK");

So far, so good. At this point, I have already opened a TCP connection to the server initiated and waiting for data in my UART port via the appropriate AT commands (I have an IP, and I can perform requests OK), therefore I need to provide the custom functions for reading and writing from/to UART, like:

    mbedtls_ssl_set_bio(&ssl,
                        &server_fd,
                        UART_ssl_bridge_write(&server_fd, ssl_o_buffer, sizeof(ssl_o_buffer)),
                        UART_ssl_bridge_read(&server_fd, ssl_i_buffer, sizeof(ssl_i_buffer)),
                        NULL);

The corresponding crude prototypes are the following:

size_t UART_ssl_bridge_write(void *ctx, const unsigned char *buf, size_t len) {

    HAL_UART_Transmit_DMA(&huart6, buf, len);
    HAL_UART_Transmit(&huart2, buf, len, 1000);

    while (!UART6txComple) {/* wait for cmd to go, txCallbackCplt */
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
        HAL_Delay(100);
    }
    return len;

}

size_t UART_ssl_bridge_read(void *ctx, const unsigned char *buf, size_t len) {

    HAL_UART_DMAStop(&huart6);
    memset(buf, '\0', sizeof(buf));
    HAL_UART_Receive(&huart6, buf, len, 1000);

    return len - strlen(buf);

}

Both are implemented in a blocking manner. Then I call this:

    custom_print("Initialize handshake");
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            sprintf(buf2, "mbedtls_ssl_handshake returned -0x%x", -ret);
            custom_print(buf2);
            memset(buf2, 0, sizeof(buf2));
            goto exit;
        }
    }

And I get -0x7080 which is pretty bad, because even If i don’t initiate any connection from the modem I get the same error, meaning that I am missing something in between.
What I know I am missing is an entropy source, because my hardware does not have one. So I implemented a function to gather measurements from the internal ADC temp sensor; not so secure, but for my prototype it is enough.

uint32_t get_random_number(int timesToPoll) {

ADC->CCR |= ADC_CCR_TSVREFE;
ADC->CCR &= ~ADC_CCR_VBATE;

sConfig.Channel = ADC_CHANNEL_1;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
for (int i = 0; i < timesToPoll; i++) {
    HAL_ADC_Start(&hadc1);
    if (HAL_ADC_PollForConversion(&hadc1, 5) == HAL_OK)
        adcVal1 += HAL_ADC_GetValue(&hadc1);
    HAL_Delay(50);
}
return adcVal1; /* returns ADC_CHANNEL_1 value */

}

Questions:

  1. Although I am going through documentation on how to add an entropy source, I am obviously either too tired or I can’t grasp on how to add that function to the entropy pool and make use of it.
  2. What am I missing and instead of getting any response from the server, I am getting the same response either with or without my module connected to it? I even tried to go PPPoS to leverage sockets and so on but to be honest it is discouraging from scratch, at least for my level. I am currently not looking at full mbed OS implementation, which has a lot of functionality, but I cannot integrate with the rest of my code.

I also provide my config file for reference:

#ifndef MBEDTLS_CONFIG_H

#define MBEDTLS_CONFIG_H

/* System support */
#define MBEDTLS_HAVE_ASM

#define MBEDTLS_TEST_NULL_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_NO_PLATFORM_ENTROPY

#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_SSL_PROTO_SSL3
#define MBEDTLS_SSL_PROTO_TLS1
#define MBEDTLS_SSL_PROTO_TLS1_1
#define MBEDTLS_SSL_PROTO_TLS1_2

/* mbed TLS feature support */
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_CIPHER_PADDING_PKCS7
#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_ECDSA_DETERMINISTIC
#define MBEDTLS_PK_RSA_ALT_SUPPORT
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_PKCS1_V21
#define MBEDTLS_SELF_TEST
#define MBEDTLS_VERSION_FEATURES
#define MBEDTLS_X509_CHECK_KEY_USAGE
#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE

/* mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_GCM_C
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_VERSION_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_CRL_PARSE_C
#define MBEDTLS_CMAC_C
#define MBEDTLS_SSL_CACHE_C

#define MBEDTLS_MD5_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_MD_C
/* Miscellaneous options */
#define MBEDTLS_AES_ROM_TABLES

#include “check_config.h”

#endif /* MBEDTLS_CONFIG_H */

Any input would be really appreciated. Keep up the good work.
Dimitris

FAST EDIT
I was browsing the forum and came across this. I will review support’s responses because it looks like most of the issues there are similar to mine and PEBCAK. In the meantime, If you have any comments on my post, please feel free to provide any feedback. Thanks again.

Hi Dim,

I can’t offer you much help here, I’ve only used Ethernet and Wi-Fi for HTTPS.
But I can’t get anything working unless the platform target has at least 128k RAM.
The F401 was a no go for me.

See here;

https://os.mbed.com/teams/sandbox/code/http-example/

All the ST boards I have with 128k and more RAM work fine (F446, L476, F767 and H734 all work).
Could I suggest trying one of those first.

Unless Mbed have changed things recently where TLS handshaking is more RAM efficient.

Sorry I can’t be any more help.

Regards

Paul

Hello Paul and thank you very much for your input.
To be honest, I havent looked at RAM usage at all.
One question though, from the linked post I read:

Memory usage

Small requests where the body of the response is cached by the library (like the one found in main-http.cpp), require 4K of RAM. When the request is finished they require 1.5K of RAM, depending on the size of the response. This applies both to HTTP and HTTPS. If you need to handle requests that return a large response body, see ‘Dealing with large body’.

HTTPS requires additional memory: on FRDM-K64F about 50K of heap space (at its peak). This means that you cannot use HTTPS on devices with less than 128K of memory, asyou also need to reserve memory for the stack and network interface.

Implies that there is a network interface occupying memory (like lwIP or some network.c interface I suppose).

From my RAM at compilation (mind you, I have 2xUARTS, ADC, DMA, various interrupts and RTC enabled)

RAM> Used: 4144 B | Memory Region: 96 KB | %age used: 4.22%

So I am left with 96KB-4KB = 91KB. Say I perform an HTTPS request and I need 4K+1.5K+50K= 55.5K.
I am still left with pretty much ~35KB of RAM (using peak usage).
Do you have any indication that it is RAM related? Maybe any logs while you were trying TLS to see where it hangs? For what I know, that micro can run a bunch of algorithms, see some benchmarking results I got:


Easiest route would be of course to go buy an L476 (which damn is sexy with its hardware RNG and such).

Thanks again,
Dimitris

Hi Dimitris,

I did have another try with the F401 using my Firebase example and had the same result, error -3011 when trying to connect with TLS.
I may have a go with that example you tried, but the problem is Mbed is very security orientated and does highly recommend Targets with embedded TRNG capability.
TLS, SSL simply eats resources, so regarding your last comment to buy the L476,

Some hardware advice from someone who has just too many board’s;

Nucleo-F767 and H743 for the faster not so energy efficient projects.
https://www.mouser.es/ProductDetail/STMicroelectronics/NUCLEO-F767ZI?qs=7UaJ5Mrpeu0%2F%2BMRranB3%2Fw%3D%3D&gclid=Cj0KCQiAwP3yBRCkARIsAABGiPoi2EEjiOEfUiQmE9hduYMb1icB2YMycGcfEWRuU88rpItTYEIVhc8aAndMEALw_wcB

https://www.mouser.es/ProductDetail/STMicroelectronics/NUCLEO-H743ZI2?qs=%2Fha2pyFadugrM6hc1Mbv8J6kcSOzwPVb%2F0M6zGPHiePuuB4hJYiWzw%3D%3D

These are crazy fast for a micro-controller and very reasonably priced.

Nucleo-F446, smaller footprint board, no Ethernet perhaps better if you want to use external WIFI or GSM. A good alternative to the F401.
https://www.mouser.es/ProductDetail/STMicroelectronics/NUCLEO-F446RE?qs=%2Fha2pyFaduj0LE%2BzmDN2WNd7nDNNMR7%2Fr%2FThuKnpWrd0IvwHkOHrpg%3D%3D

Nucleo-L476 for a low energy alternative for the F401.

https://www.mouser.es/ProductDetail/STMicroelectronics/NUCLEO-L476RG?qs=PRtH0mD6DWbM6mRV5DKjBQ%3D%3D&vip=1&gclid=Cj0KCQiAwP3yBRCkARIsAABGiPo5eNOv4K6kFoaNth-RbMOx5gIdWLP6mibtKsZHk8dYF6EyHxxH6esaAlIJEALw_wcB

I tend to use Ethernet connection during development then move over and test with WIFI when I need to.
So my weapon of choice is the F767.

Keep this thread updated as you go, I do need a GSM solution at some point, but have never used mobile network data, and I’m happy to try out example code.

Regards

Paul

Thanks for your reply. I will post my approach once I finish the callbacks; even if it’s not gonna work on F401, porting to a more powerful micro with TRNG should be easy.

BR
Dimitris

Hi Dimitris,
As you can see, error -0x7080 is MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE which is returned by several locations, when a requested feature is not supported. Usually it is a configuration issue. This is not related to the platform, or the entropy source (though you do need an entropy source to the functionality).
I would suggest you look at the debug logs for you to understand where this error is returned, and then you could configure the relevant feature if possible.
Regards,
Mbed TLS Support
Ron

Hello Ron and thanks for the input.
Could you kindly provide some info on how to setup the debug output for non-stdio environment, say for a UART port? I see the

#include “mbedtls/debug.h”
.
.
#define DEBUG_LEVEL 1

combo on the library examples but it gets a bit complicated afterwards. Should I do something like:

/* mbedtls_config.h */
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS

and

/* platform.h */
#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
#define MBEDTLS_PLATFORM_STD_FPRINTF   custom_fprintf /**< Default fprintf to use  */
#endif

and

/* main.c */
static void my_debug( void *ctx, int level,
                      const char *file, int line,
                      const char *str ){
    ((void) level);

    mbedtls_custom_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );  /**< more like sprintf */
    fflush(  (FILE *) ctx  );
}
.   /* ****************** */
.   /* mbedTLS initialize */                     
.   /* ****************** */

mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );

Appreciate your response,
Regards

Hi Dimitris,
In the mbed-os-example-tls example you will see how the debug function is set.

It is better you don’t modify source files, for maintenance reasons.
I would configure MBEDTLS_PLATFORM_STD_FPRINTF to be the custom_fprintf outside the source code, however I think it would be simpler to configure MBEDTLS_PLATFORM_FPRINTF_ALT and then in your code call mbedtls_platform_set_fprintf with custom_fprintf as parameter.
Do you prefer to use fprintf rather than printf ?
Note that if you define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS, then the change you are considering to custom_fprintf in platform.h will not work, as it’s under the

#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)

However, since this is probably a configuration issue, I think it would be simpler if you first try using on your local machine using ssl_client2 sample application with your own configuration file.

Regards

Thank you for all the feedback. Unfortunately I have a day-job as well, so my response is slow.
As you suggested, I tried HTTP GET os.mbed.com and a resource from my host Win10, using default config.h:

C:\win-builds\projects\mbedtls-2.16.5>programs\ssl\ssl_client2 server_name=os.mbed.com server_port=443

  . Seeding the random number generator... ok
  . Loading the CA root certificate ...
  . os.mbed.com PEM certificate is: ...
-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
rqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----
 ok (0 skipped)
  . Loading the client cert. and key... ok
  . Connecting to tcp/os.mbed.com/443... ok
  . Setting up the SSL/TLS structure... ok
  . Performing the SSL/TLS handshake...
Verify requested for (Depth 2):
cert. version     : 3
serial number     : 06:6C:9F:CF:99:BF:8C:0A:39:E2:F0:78:8A:43:E6:96:36:5B:CA
issuer name       : C=US, O=Amazon, CN=Amazon Root CA 1
subject name      : C=US, O=Amazon, CN=Amazon Root CA 1
issued  on        : 2015-05-26 00:00:00
expires on        : 2038-01-17 00:00:00
signed using      : RSA with SHA-256
RSA key size      : 2048 bits
basic constraints : CA=true
key usage         : Digital Signature, Key Cert Sign, CRL Sign
  This certificate has no flags

Verify requested for (Depth 1):
cert. version     : 3
serial number     : 06:7F:94:57:85:87:E8:AC:77:DE:B2:53:32:5B:BC:99:8B:56:0D
issuer name       : C=US, O=Amazon, CN=Amazon Root CA 1
subject name      : C=US, O=Amazon, OU=Server CA 1B, CN=Amazon
issued  on        : 2015-10-22 00:00:00
expires on        : 2025-10-19 00:00:00
signed using      : RSA with SHA-256
RSA key size      : 2048 bits
basic constraints : CA=true, max_pathlen=0
key usage         : Digital Signature, Key Cert Sign, CRL Sign
  This certificate has no flags

Verify requested for (Depth 0):
cert. version     : 3
serial number     : 0F:70:19:FD:F1:73:D0:E6:DF:CF:C9:31:AD:90:2A:26
issuer name       : C=US, O=Amazon, OU=Server CA 1B, CN=Amazon
subject name      : CN=*.mbed.com
issued  on        : 2019-05-09 00:00:00
expires on        : 2020-06-09 12:00:00
signed using      : RSA with SHA-256
RSA key size      : 2048 bits
basic constraints : CA=false
subject alt name  : *.mbed.com, *.core.mbed.com, *.internal.mbed.com, *.pelion.com, *.mbed.org, mbed.com, core.mbed.com, internal.mbed.com, pelion.com, mbed.org
key usage         : Digital Signature, Key Encipherment
ext key usage     : TLS Web Server Authentication, TLS Web Client Authentication
  This certificate has no flags
 ok
    [ Protocol is TLSv1.2 ]
    [ Ciphersuite is TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 ]
    [ Record expansion is 29 ]
    [ Maximum fragment length is 16384 ]
  . Verifying peer X.509 certificate... ok
  . Peer certificate information    ...
      cert. version     : 3
      serial number     : 0F:70:19:FD:F1:73:D0:E6:DF:CF:C9:31:AD:90:2A:26
      issuer name       : C=US, O=Amazon, OU=Server CA 1B, CN=Amazon
      subject name      : CN=*.mbed.com
      issued  on        : 2019-05-09 00:00:00
      expires on        : 2020-06-09 12:00:00
      signed using      : RSA with SHA-256
      RSA key size      : 2048 bits
      basic constraints : CA=false
      subject alt name  : *.mbed.com, *.core.mbed.com, *.internal.mbed.com, *.pelion.com, *.mbed.org, mbed.com, core.mbed.com, internal.mbed.com, pelion.com, mbed.org
      key usage         : Digital Signature, Key Encipherment
      ext key usage     : TLS Web Server Authentication, TLS Web Client Authentication

  > Write to server: 76 bytes written in 1 fragments

GET /media/uploads/mbed_official/hello.txt HTTP/1.0
Host: os.mbed.com



  < Read from server: 366 bytes read

HTTP/1.1 200 OK
Date: Thu, 05 Mar 2020 18:30:10 GMT
Content-Type: text/plain
Content-Length: 14
Connection: close
Last-Modified: Sat, 17 Nov 2018 12:02:53 GMT
ETag: "5bf0036d-e"
Expires: Fri, 06 Mar 2020 04:30:10 GMT
Cache-Control: max-age=36000
Accept-Ranges: bytes
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Hello world!
  . Closing the connection... done
  + Press Enter to exit this program.

For testing on my hardware later on, and until I have an entropy source, I defined

#define MBEDTLS_TEST_NULL_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#define MBEDTLS_NO_PLATFORM_ENTROPY

and got same 200 OK on the host.
Now, when I tried loading that Frankenstein config I had created, it just hanged at
mbedtls_printf( " . Setting up the SSL/TLS structure..." );
I have to revise the config I created.

EDIT

this

/*
 * 0. Initialize the RNG and the session data
 */
custom_print("\n  . Seeding the random number generator...");
mbedtls_entropy_init(&entropy);
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
                                 &entropy, (const unsigned char *) pers,
                                 strlen(pers))) != 0) {
    sprintf(buf, " failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n",
            -ret);
    custom_print(buf);
}
custom_print(" ok\n");

works OK on host, returns -0x34 on stm32, both with

#define MBEDTLS_ENTROPY_C
#define MBEDTLS_TEST_NULL_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#define MBEDTLS_NO_PLATFORM_ENTROPY

Any ideas?

Later on, I wrote a minimal program to HTTPS GET and works OK on the host with the default config.
Now, for the fun part of porting it to the micro; Ron, what’s your opinion about RAM usage? Would it be worth the effort to port to F401RE, or as suggested above I should look for a more resource-capable solution?

Thanks again,
Dimitris

HI Dimitris,

Unfortunately I have a day-job as well, so my response is slow.

That’s fine, just answer at your own pace:)

Now, when I tried loading that Frankenstein config I had created, it just hanged at
mbedtls_printf( " . Setting up the SSL/TLS structure..." );

Have you checked with a debugger where it hanged? It would assist you on understanding why. However, since as you stated, it now works, it might be a memory issue, which caused the error to happen during handshake. Otherwise, if you are using exactly same configuration as the failed one(except perhaps platform specific configuration ), there isn’t a reasonable reason why you got the SSL Feature Unavailable error.
AS for error -0x34 on your stm32, you will see it is MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
Which means the entropy function has failed.

I have just looked at your entropy source function, that you described in your original post (get_random_number) and it doesn’t have the proper prototype, as defined for mbedtls_entropy_f_source_ptr.

Following the documentation on how to add an entropy source article, you should implement get_random_number with the proper prototype, returning 0 for success, or error on failure, and add it as source via mbedtls_entropy_add_source().
I couldn’t find in your example how you added this source.

Ron, what’s your opinion about RAM usage? Would it be worth the effort to port to F401RE, or as suggested above I should look for a more resource-capable solution?

It is very much dependent on what features you need. I would suggest you read this article
Regards

Hello,
I started from scratch and cannot replicate the hang so there’s that. Entropy is OK from the entropy source function. As a summary:

  • For entropy source I wrote a function

int get_random_number (void)

which polls the ADC and returns one integer. Afterwards, as mbedtls_entropy_f_source_ptr
dictates, I wrote

int adc_poll_entropy(void *data, unsigned char *output, size_t len,
                     size_t *olen){
    uint16_t i = 0;
    while (i < 65 && i < len) {
        *(output + i) = get_random_number;
        i++;
    }
    *olen = i;
    return 0;       /* returns OK */
}

which to the entropy function seems OK when I feed it with

mbedtls_entropy_add_source(&entropy, adc_poll_entropy, NULL, 0, MBEDTLS_ENTROPY_SOURCE_STRONG);

/*
 * 0. Initialize the RNG and the session data
 */
custom_print("\n  . Seeding the random number generator...");
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
                                 &entropy, NULL,
                                 0)) != 0) {
    sprintf(buf, " failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n",
            -ret);
    custom_print(buf);
} else
    custom_print("\n  > mbedtls_ctr_drbg_seed OK\n");

Then, I load CA root cert OK

/*
 * 1.1. Load the trusted CA
 */
custom_print("\n  . Loading CA root cert");
ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_ca_crt, mbedtls_test_ca_crt_len);
if (ret < 0) {
    sprintf(buf, " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n",
            -ret);
    custom_print(buf);
} else
    custom_print("\n  > mbedtls_x509_crt_parse OK\n");

and next milestone would be the network interface.

/*
 * 2. Start the connection
*/
mbedtls_net_init(&server_fd);
custom_print("Connecting to server");

if ((ret = mbedtls_net_connect(&server_fd, WEB_SERVER, "443",
                               MBEDTLS_NET_PROTO_TCP)) != 0) {
    custom_sprint("mbedtls_net_connect returned -%x", -ret);
}
custom_print("\n-> Connected ");

/*
 * 3. Setup stuff
 */
custom_print("\n  . Setting hostname...");
if ((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) {
    custom_sprint(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n",
                   ret);
}

custom_print("\n  . Setting up the SSL/TLS structure...");
if ((ret = mbedtls_ssl_config_defaults(&conf,
                                       MBEDTLS_SSL_IS_CLIENT,
                                       MBEDTLS_SSL_TRANSPORT_STREAM,
                                       MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
    custom_sprint(" failed\n  ! mbedtls_ssl_config_defaults returned -0x%x\n\n",
                   -ret);
}


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);

if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
    sprintf(buf, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
    custom_print(buf);
}

mbedtls_ssl_set_bio(&ssl, &server_fd, my_send, my_recv, NULL);

As far as I have read the docs, 2. Start the connection should be replaced with my corresponding AT commands that open a TCP socket waiting for IO in my UART, correct?

3. Setup stuff should work as is, while my_send and my_recv should be something (crudely) like:

static int my_send(void *ctx, const unsigned char *buf, size_t len) {
    HAL_UART_Transmit(&huart6, buf, len, 1000);
    return len;
}

static int my_recv(void *ctx, unsigned char *buf, size_t len) {
    HAL_UART_Receive(&huart6, buf, len, 1000);
    return len;
}

If all is setup correctly, these:

/*
 * 4. Handshake
 */
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
    if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
        ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
        custom_sprint(" failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n",
                       -ret);
        break;
    }
}

/*
 * 5. Verify the server certificate
 */
custom_print("\nVerifying peer X.509 certificate...");
mbedtls_printf(" ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
               mbedtls_ssl_get_version(&ssl),
               mbedtls_ssl_get_ciphersuite(&ssl));

should work plug & play?
What’s the function of

/*
 * 6. Write the GET request
 */
custom_print("  > Write to server:");
int written_bytes = 0;
do {
    ret = mbedtls_ssl_write(&ssl,
                            (const unsigned char *) REQUEST + written_bytes,
                            strlen(REQUEST) - written_bytes);
    if (ret >= 0) {
        custom_sprint("%d bytes written\n", ret);
        written_bytes += ret;
    } else if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_WANT_READ) {
        custom_sprint("mbedtls_ssl_write returned -0x%x", -ret);
        break;
    }
} while (written_bytes < strlen(REQUEST));

mbedtls_ssl_write or a corresponding mbedtls_ssl_read? Or what’s the difference between a mbedtls_ssl_send_t function and mbedtls_ssl_write function? If the library handles the callbacks internally, shouldn’t I be calling something else to utilize my custom my_send and my_recv via the library?

Thanks a lot for your input.
Regards

Hi Dim,
Thank you for your information.

2. Start the connection should be replaced with my corresponding AT commands that open a TCP socket waiting for IO in my UART, correct?

Correct. If there is any setup for the AT commands transport layer.

If all is setup correctly, these: … should work plug & play?

Yes, it should, unless there is some platform specific issues such as memory and stdio.

What’s the function of mbedtls_ssl_write or a corresponding mbedtls_ssl_read ? Or what’s the difference between a mbedtls_ssl_send_t function and mbedtls_ssl_write function? If the library handles the callbacks internally, shouldn’t I be calling something else to utilize my custom my_send and my_recv via the library?

After you do a successful TLS handshake between the peers, you send \ recv application data between them. mbedtls_ssl_write() and a corresponding mbedtls_ssl_read() are the the public API that you call to send\recv data to\from the peer. Internally, they encrypt \ decrypt the data with the TLS session key, and call the callbacks you have set.

Regards

Hi,

After you do a successful TLS handshake between the peers, you send \ recv application data between them. mbedtls_ssl_write() and a corresponding mbedtls_ssl_read() are the the public API that you call to send\recv data to\from the peer. Internally, they encrypt \ decrypt the data with the TLS session key, and call the callbacks you have set.

OK, it is perfectly clear, thanks.
I am afraid I hit the roadblock Paul warned me regarding ram usage. I am getting an error 0x7200 from mbedtls_ssl_handshake(&ssl).

Looking back at other users had similar issues and your response, I am stripping down the config.h per the mini-TLS 1.2 example and your article suggestion.

Another thing I noticed:

static int my_send(void *ctx, const unsigned char *buf, size_t len) {
    HAL_UART_Transmit(&huart6, buf, len, 0xffff);

    custom_print(len);
    return len;
}

static int my_recv(void *ctx, unsigned char *buf, size_t len) {
    UART6rxComple = false;   /* is true when UART IDLE interrupt */
    HAL_UART_Receive_DMA(&huart6, (uint8_t *) buf, len);
    while (!UART6rxComple) { /* HACKS */ }
    HAL_UART_DMAStop(&huart6);  /* no more data in UART, stop DMA */

    custom_print(len);
    return len;
}

During handshaking, I am printing len for both send and recv, and it is populated, something like 1kb (i think, i am currently trying to enable the debug feature with UART and i will retest) for sending and 5 bytes(!) for recv. I will try to increase the MCU-modem baudrate or maybe somehow give the modem some time to spit out data because I suspect that there is something asynchronously messing up the recv buffer contents. For anyone else’s reference, I am utilizing an IDLE line interrupt from the UART to catch end of data receive, with volatile bool UART6rxComple toggling inside the IRQ IDLE callback. I can confirm that this modem, even for plain HTTP GET requests somehow transmits in UART the received data in chunks, e.g. one server response triggers two IDLE line interrupts.
I will write back further results.

Have a nice week,
Dimitris

edit: Let me add that until now, about 50% of my time with wrong configurations both on my host PC and on STM32, were because cmake cashes something (idk what) causing a new configuration to not load after compilations, expect if I also edit the source file as well or if I clear the cache

The 1 KB is probably what you have configured as the MBEDTLS_SSL_MAX_CONTENT_LEN. Or, this is the size of what you want to write.

The 55 Bytes is the TLS header length. It makes sense you read 5 bytes. However, you should be reading the whole message after reading this header, which is bigger. Do you recv only 5 bytes?

I am moving to the libary’s debug so I can do proper logging and I will get back to you, I just need some time to port this to UART.

My updates on this:

Regarding callback send and recv functions and SIM800, I implemented this for send:

static int my_send(void *ctx, const unsigned char *buf, size_t len) {
    int ret;

    send_socket_len(len);
    send_to_tcp(buf, len);

    ret = len;    /* will populate */
    return( ret );
}

where send_socket_len issues the corresponding AT commands for sending data via TCP and send_to_tcp(len) is actually sending the data to UART after modem is prompting for data (">")

bool send_to_tcp(uint8_t *cmd, size_t len) {
    HAL_UART_Transmit(&huart6, cmd, len, 0xffff);
    return true;
}

I will later post the recv but I got the point.

Question here:
What happens if the hardware medium or the network has a size limitation per message?

Regarding using the debug interface
I (almost) give up on using a custom debug fuction. I cannot find what’s causing it not to work at all. For example, I enable debug in my configuration like: #define MBEDTLS_DEBUG_C
and following the ssl_client2 library example I declare:

static void my_debug( void *ctx, int level,
                      const char *file, int line,
                      const char *str )
{
(void)ctx;

    const char *p, *basename;
    char buf[512];

    HAL_GPIO_TogglePin(GPIOA, DEBUG_LED);    /* never runs*/

    /* Extract basename from file */
    for (p = basename = file; *p != '\0'; p++) {
        if (*p == '/' || *p == '\\')
            basename = p + 1;
    }

    sprintf(buf, "%s:%d: |%d| %s\r", basename, line, level, str);
    HAL_UART_Transmit(USB_UART, buf, strlen(buf), 0xffff);

}

For consistency, I declared

static void my_debug( void *ctx, int level,
                      const char *file, int line,
                      const char *str )
{
    const char *p, *basename;
    char buf[512];

    mbedtls_printf("\r\n   In DEBUG");

    /* Extract basename from file */
    for (p = basename = file; *p != '\0'; p++) {
        if (*p == '/' || *p == '\\')
            basename = p + 1;
    }

    sprintf(buf, "%s:%d: |%d| %s\r", basename, line, level, str);
    mbedtls_printf(buf);
}

in the same code at my host PC.
Configuration is the same, excluding platform-specific staff.

Finally, in my code I call mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
Host PC debug works OK, and I also see my custom message (" In DEBUG") but on STM32 no debug output and no debug LED blinks. In short, program never calls my_debug.
I understand it has something to do with configuration or platform specific staff, that’s why I also defined NULL instead of stdout for the debugger, both in host and in STM.
Any ideas? That would really help me with moving on with SSL handshaking…

Best,
Dimitris

Hi @euphoriadamage

What happens if the hardware medium or the network has a size limitation per message?

I believe this article should answer your question. In short, you should limit the length of your in\out messages to the size of your transport layer limitation.

In short, program never calls my_debug .
I understand it has something to do with configuration or platform specific staff, that’s why I also defined NULL instead of stdout for the debugger, both in host and in STM.
Any ideas?

I am assuming the value sent to mbedtls_debug_set_threshold() is same for both cases. Is this correct? If not, the the defualt debug level is 0, which means that the debug function will not be called.
Regards

Thanks for the article, exactly that.
Now for the mbedtls_debug_set_threshold(), I call it like mbedtls_debug_set_threshold(4), As I said above, it prints debug messages normally on host pc but fails on STM.
I was wondering if there is something obvious that I am missing.

Regards

The only thing I can think of is perhaps your my)debug function on your platform doesn’t do what you think it does. Have you tried a simple hello world application?
Can you use gdb on your platform?

I’ll figure this out.
I just noticed, the autogenerated mbedTLS file ssl.h from STM32CubeMX does not contain:

#define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000 /**< A cryptographic operation is in progress. Try again later. */

while the corresponding ssl.h I got from github does. Should I post this on Github?