Tym razem chciałem umieścić tutaj aktualizację dotyczącą komunikacji TLS. Program testowałem na płytce z układem STM32H725.
Zajmę się tutaj poprawą wcześniej udostępnionej komunikacji SSL. Tak aby połączenie oraz jego ponowne nawiązywanie było bardziej stabilne.
Zacznijmy od potrzebnych definicji:
- #define MBEDTLS_SSL_PROTO_TLS1_2 //Obsługa TLS1.2
- #define MBEDTLS_CTR_DRBG_C //Uruchomienie generatora liczb losowych
- #define MBEDTLS_ENTROPY_C //Źródło entropii dla DRBG
- #define MBEDTLS_NET_C
- #define MBEDTLS_SSL_CLI_C //Włączony tryb klienta
- #define MBEDTLS_SSL_SRV_C //Włączony tryb serwera
- #define MBEDTLS_SSL_TLS_C
- #define MBEDTLS_X509_USE_C
- #define MBEDTLS_X509_CRT_PARSE_C //Parsowanie certyfikatów X.509
Należy także zdefiniować dozwolone szyfry. Tak aby połączenie korzystało z możliwie najnowszych:
- #define MBEDTLS_SSL_CIPHERSUITES \
- MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, \
- MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, \
- MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, \
- MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, \
- MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, \
- MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
Ta lista będzie przedstawiana w podczas handshak'a. Serwer wybierze jeden z nich do komunikacji. Warto także pamiętać, że nowsze szyfry z reguły potrzebują mniej miejsca w pamięci na ich wykonanie.
Dobrze to przechodzimy do nawiązywania sesji komunikacyjnej. Rozpoczynamy od inicjalizacji danych:
- static void Initialize_SessionData(void)
- {
- //Przygotowanie gniazda TCP
- mbedtls_net_init(&server_fd);
- //Inicjalizacja pustego kontekstu TLS
- mbedtls_ssl_init(&ssl);\
- //Inicjalizacja obiektu konfig handshake i szyfrowania
- mbedtls_ssl_config_init(&conf);
- //przygotowanie struktur certyfikatów
- mbedtls_x509_crt_init(&cacert);
- mbedtls_x509_crt_init(&server_cert);
- //Przygotowanie generatora liczb losowych oraz strukture klucze prywatnego
- mbedtls_ctr_drbg_init(&ctr_drbg);
- mbedtls_pk_init(&pkey);
- mbedtls_entropy_init(&entropy);
- }
Powyżej przygotowywane są wszystkie obiekty mbedTLS.
Teraz przygotowywany jest seed dla generatora losowego.
- static int Drbg_Seed(void)
- {
- int opStatus = 0;
- if((opStatus = mbedtls_ctr_drbg_seed(&ctr_drbg,
- mbedtls_entropy_func,
- &entropy,
- (const unsigned char*) pers,
- strlen(pers))) != 0) {
- return opStatus;
- }
- return opStatus;
- }
Łączone jest DRBG z źródłem entropii. W parametrze pers przekazywany jest tzw. prejonizacyjny string. Jest to dodatkowy identyfikator dla instancji generatora. Musi to być poprawnie zainicjalizowane i uruchomione aby handshake mógł przejść bez problemów. Na podstawie wygenerowanych danych tworzone są losowe dane do kluczy sesji. Dzięki temu bezpieczeństwo sesji nie opiera się na stałych danych.
Następnym krokiem jest załadowanie certyfikatów.
- static int InitializeCertificate(void)
- {
- int opStatus = 0;
- opStatus = mbedtls_pk_parse_key(
- &pkey,
- (const unsigned char *)mbedtls_certificate_key,
- mbedtls_certificate_key_len + 1,
- (const unsigned char *)mbedtls_certificate_key_pass,
- mbedtls_certificate_key_pass_len
- );
- if (opStatus < 0) return opStatus;
- opStatus = mbedtls_x509_crt_parse(
- &cacert,
- (const unsigned char *)mbedtls_client_certificate,
- mbedtls_client_certificate_len + 1
- );
- if (opStatus < 0) return opStatus;
- opStatus = mbedtls_x509_crt_parse(
- &server_cert,
- (const unsigned char *)mbedtls_server_certificate,
- strlen(mbedtls_server_certificate) + 1
- );
- if (opStatus < 0) return opStatus;
- opStatus = mbedtls_pk_check_pair(&cacert.pk, &pkey);
- if (opStatus < 0) return opStatus;
- return 0;
Funkcja mbedtls_pl_parse_key parsuje klucz prywatny klienta z formatu PEM. Następnie w kolejnej funkcji jest on ładowany. Dalej przetwarzany jest certyfikat serwera. Na końcu sprawdzana jest poprawność klucza prywatnego z certyfikatem klienta.
Ponieważ do projektu wykorzystane zostały dwa certyfikaty, To komunikacja może się odbywać w tzw. mTLS. Gdzie zarówno serwer jak i klient muszą przedstawić swój certyfikat. Oczywiście aby to faktycznie zadziałało to serwer musi wymagać od klienta tego certyfikatu. Bez niego uwierzytelnia się tylko serwer. Takie połączenie określa się jako TLS.
Poniżej funkcja konfigurująca połączenie po TLS 1.2.
- static uint8_t LoadDefaultConfiguration(void)
- {
- int opStatus = 0;
- if((opStatus = mbedtls_ssl_config_defaults(&conf,
- MBEDTLS_SSL_IS_CLIENT,
- MBEDTLS_SSL_TRANSPORT_STREAM,
- MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
- return opStatus;
- }
- return opStatus;
- }
Parametr MBEDTLS_SSL_TRANSPORT_STREAM działa nad strumieniem TCP. Dla projektu wykorzystującego DTLS należy użyć protokołu UDP:
- #define MBEDTLS_SSL_TRANSPORT_STREAM 0 /*!< TLS */
- #define MBEDTLS_SSL_TRANSPORT_DATAGRAM 1 /*!< DTLS */
Połączenie zaczyna się od TCP. Po jego ustanowieniu biblioteka mbedTLS dokłada do niego wartstwę TLS. Pozwala to na zaszyfrowanie strumienia danych.
- static uint8_t ConnectionSSL_Configuration(void)
- {
- int opStatus = 0;
- mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
- mbedtls_ssl_conf_ca_chain(&conf, &server_cert, NULL);
- mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
- mbedtls_ssl_conf_min_version(&conf,
- MBEDTLS_SSL_MAJOR_VERSION_3,
- MBEDTLS_SSL_MINOR_VERSION_3);
- mbedtls_ssl_conf_max_version(&conf,
- MBEDTLS_SSL_MAJOR_VERSION_3,
- MBEDTLS_SSL_MINOR_VERSION_3);
- mbedtls_ssl_conf_read_timeout(&conf, 10000);
- opStatus = mbedtls_ssl_conf_own_cert(&conf, &cacert, &pkey);
- if (opStatus < 0) return opStatus;
- opStatus = mbedtls_ssl_setup(&ssl, &conf);
- if (opStatus != 0) return opStatus;
- return 0;
- }
Walidacja certyfikatu serwera obejmuje sprawdzenie jego poprawności czy zgodności z oczekiwanym hostem. Funkcja mbedtls_ssl_set_hostname() ustawia nazwę, z którą biblioteka porównuje dane certyfikatu.
Przy pełnym i poprawnym certyfikacie warto zmienić opcję MBEDTLS_SSL_VERIFY_OPTIONAL na MBEDTLS_SSL_VERIFY_REQUIRED.
Funkcje zastosowane powyżej wykonują następujące zadania:
- mbedtls_ssl_config_defaults - przygotowuje bazową konfiguracje klienta SSL przez TCP
- mbedtls_ssl_conf_authmode - ustawienie polityki weryfikacji certyfikatu serwera.
- mbedtls_ssl_conf_ca_chain - przekazujemy który certyfikat będzie wykorzystywany do weryfikacji.
- mbedtls_ssl_conf_rng - podłącza generator liczb losowych.
- mbedtls_ssl_conf_min_version (max_version) - ustawia wersję TLS na 1.2.
- mbedtls_ssl_conf_own_cert - podpięcie certyfikatu i klucza klienta.
- mbedtls_ssl_setup - podłączenie sesji ssl z certyfikatem.
TLS 1.2. ciągle jest popularnym protokołem w systemach wbudowanych. Głównie ze względu na szerokie wsparcie i dobre biblioteki. Handshake w nim jest także bardziej rozbudowany niż w wersji 1.3. Przekłada się to na większą liczbę kroków w negocjacji czyli dłuższy czas potrzebny do zestawienia połączenia.
Podłączenie transportu i handshak'a:
- static uint8_t SetHostname_BioCallbacks(void)
- {
- int opStatus = 0;
- //ustawia nazwe hosta do weryfikacji certyfikatu.
- if((opStatus = mbedtls_ssl_set_hostname(&ssl, "name")) != 0) {
- return opStatus;
- }
- //laczy TLS z gniazdem TCP oraz `send` i `recv`.
- mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
- return opStatus;
- }
Teraz pora na handshake:
- static int Handshake_timeout(uint32_t timeout_ms)
- {
- int ret;
- TickType_t start = xTaskGetTickCount();
- TickType_t timeout_ticks = pdMS_TO_TICKS(timeout_ms);
- //wykonanie wszystkie kroki negocjacji TLS.
- while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
- {
- //tutaj bez bledów krytycznych tylko konieczność,
- //ponownego wywolania.
- if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
- ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
- ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
- {
- if ((xTaskGetTickCount() - start) > timeout_ticks)
- return MBEDTLS_ERR_SSL_TIMEOUT;
- osDelay(2);
- continue;
- }
- return ret;
- }
- return 0;
- }
W tej funkcji dodatkowo jest zaimplementowany timeout, party o tick FreeRTOS. Tak aby handshake nie wisiał w nieskończoność z powodu błędów.
Dla standardowego scenariusza TLS 1.2 wymiana pakietów wygląda następująco:
- ClientHello - klient wysyła wersję TLS, listę ciphersuite, dane losowe.
- ServerHello - serwer przekazuje wybrane wersje protokołu i ciphersuite.
- Certificate - serwer przesyła swój certyfikat X.509
- ServerKeyExchange - serwer przekazuje dane potrzebne do wymiany klucza.
- ServerHelloDone - koniec odpowiedzi od serwera.
- ClientKeyExchange - przesyłanie danych do ustanowienia sesji oraz certyfikat klienta jeśli jest wymaganay.
- ChangeCipherSpec - przejście na klucze sesyjne,
- Finished - potwierdzenie poprawnej negocjacji.
Ten etap jest konieczny. Są na nim uzgadniane parametry sesji. Dopiero po jego poprawnym zakończeniu aplikacje mogą przejść do wymiany danych użytkowników.
Zapis i odczyt danych odbywa się przez następujące funkcje:
- ret = mbedtls_ssl_write(&ssl, frameToSend + sent, numberOfDataToSend - sent);
- ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);
Operują one oczywiście na warstwie TLS. Czyli dane są odczyta szyfrowane/odszyfrowane i przekazywane dalej.
Ważnym elementem jest sterowanie stanem sesji TLS. Jest ono niezależne od stanu samego TCP. Do takich operacji wykorzystuje się alerty. Jednym z nich jest close_notify. Odpowiada on za kontrolowane zamknięcie kanału szyfrowanego. Czyli nie tylko należy zamknąć socket ale także wysłać odpowiedni alert:
- do {
- ret = mbedtls_ssl_close_notify(&ssl);
- } while(ret == MBEDTLS_ERR_SSL_WANT_WRITE);
- mbedtls_ssl_session_reset(&ssl);
- mbedtls_net_free(&server_fd);
Dzięki takiemu zakończeniu sesji wiadomo, że druga strona musi zamknąć połączenie oraz, że nie doszło do żadnego błędu.
Należ także zadbać o czyszczenie danych sesji TLS oraz przygotowaniu danych do kolejnego handshaka.
- ret = mbedtls_ssl_session_reset(&ssl);
- if (ret != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_session_reset returned %d\r\n \r\n ", ret);
- // twardy reset ssl jeśli reset sesji nie wyszedł
- mbedtls_ssl_free(&ssl);
- mbedtls_ssl_init(&ssl);
- // setup ponownie z już skonfigurowanym conf
- ret = mbedtls_ssl_setup(&ssl, &conf);
- if (ret != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_setup(re) returned %d\r\n \r\n ", ret);
- mbedtls_net_free(&server_fd);
- osDelay(30000);
- continue;
- }
- // hostname trzeba ponownie po re-init ssl
- ret = mbedtls_ssl_set_hostname(&ssl, "name");
- if (ret != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_set_hostname(re) returned %d\r\n \r\n ", ret);
- mbedtls_net_free(&server_fd);
- osDelay(30000);
- continue;
- }
- }
Powyżej widać, że dodatkowo czyszczone są wewnętrzne stany TLS. Tak aby kolejny hanshake mógł zacząć od zera i odziedziczył żadnych danych z poprzedniej sesji
Kolejnym nie mniej istotnym elementem jest obsługa stanów pośrednich zwracanych przez TLS.
- //Wysyłanie danych
- while (sent < numberOfDataToSend)
- {
- ret = mbedtls_ssl_write(&ssl,
- frameToSend + sent,
- numberOfDataToSend - sent);
- if (ret > 0)
- {
- sent += (uint16_t)ret;
- continue;
- }
- if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
- ret == MBEDTLS_ERR_SSL_WANT_WRITE)
- {
- osDelay(2);
- continue;
- }
- return -1;
- }
- //Odczyt danych
- ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);
- if (ret == MBEDTLS_ERR_SSL_TIMEOUT)
- {
- sslReadTimeoutCounter++;
- if (sslReadTimeoutCounter >= 7)
- {
- break;
- }
- osDelay(10);
- continue;
- }
Cyklicznie ponawiane są operacje odczytu, zapisu oraz handshake w zależności od stanu i timeout'u.
Dla całej konfiguracji należy pamiętać, że TLS oprócz samego miejsca na biblioteki mbedTLS potrzebuje mieć jeszcze przydzielone miejsce do buforów, certyfikatów, kluczy, stanu sesji czy wymiany danych w handshak'u.
W celu weryfikacji ile miejsca jest zajętych i jeśli się wywala to na których elementach warto korzystać z funkcji debugowania:
- static void my_debug(void *ctx, int level, const char *file, int line, const char *str)
- {
- ((void) level);
- mbedtls_fprintf((FILE*) ctx, "%s:%04d: %s", file, line, str);
- fflush((FILE*) ctx);
- }
- //Podłączenie funkcji debug
- mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
Do określenia zajętości pamięci dobrze sprawdzi się coś takiego:
- //Bufor odbiorczy
- char buf[3072] = {0x00};
- oraz diagnostykę wolnej pamięci:
- printf("[SSL][HEAP] free=%u min=%u\r\n",
- (unsigned)xPortGetFreeHeapSize(),
- (unsigned)xPortGetMinimumEverFreeHeapSize());
- //Monitorowanie stosu
- static void PrintTaskWatermark(const char *tag)
- {
- printf("[STACK] %s watermark=%u\r\n",
- tag, (unsigned)uxTaskGetStackHighWaterMark(NULL));
- }
Główna funkcja uruchamiająca TLS oraz przetwarzająca dane wygląda następująco:
- #define DEBUG_CLIENT_TASK
- void StartSSLClientTask(void const *argument)
- {
- int ret = 1;
- int len = 0;
- //Semafor ustawiony po uruchomieniu LWIP
- while (xSemaphoreTake(sslTaskSemaphore, portMAX_DELAY) == 0) {
- osDelay(3000);
- }
- #ifdef DEBUG_CLIENT_TASK
- printf("[StartSSLClientTask] SSL START\r\n");
- PrintTaskWatermark("ssl start");
- fflush(stdout);
- #endif
- Get_Port_String_Data(&serverPort[0]);
- Get_Server_Ip_String_Data(&serverIp[0]);
- Get_Board_Ip_String_Data(&boardIp[0]);
- #if defined(MBEDTLS_DEBUG_C)
- mbedtls_debug_set_threshold(DEBUG_LEVEL);
- #endif
- Initialize_SessionData();
- ret = Drbg_Seed();
- if (ret != 0) { goto exit_task; }
- #ifdef DEBUG_CLIENT_TASK
- PrintTaskWatermark("after Drbg_Seed");
- #endif
- ret = InitializeCertificate();
- if (ret != 0) { goto exit_task; }
- #ifdef DEBUG_CLIENT_TASK
- PrintTaskWatermark("after InitializeCertificate");
- #endif
- ValidateIpAddress();
- mbedtls_printf_mac("MBEDTLS LDC\r\n");
- if (LoadDefaultConfiguration() != 0) { goto exit_task; }
- #ifdef DEBUG_CLIENT_TASK
- PrintTaskWatermark("after LoadDefaultConfiguration");
- #endif
- if (ConnectionSSL_Configuration() != 0) { goto exit_task; }
- #ifdef DEBUG_CLIENT_TASK
- PrintTaskWatermark("after ConnectionSSL_Configuration");
- #endif
- if ((ret = mbedtls_ssl_set_hostname(&ssl, "name")) != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_set_hostname returned %d\r\n \r\n ", ret);
- goto exit_task;
- }
- while (1)
- {
- //nowy socket
- mbedtls_net_init(&server_fd);
- #ifdef DEBUG_CLIENT_TASK
- mbedtls_printf_mac("ConnectToServer\r\n");
- #endif
- ConnectingToServerFlag = 1;
- if (ConnectToServerTcp() != 0) {
- mbedtls_printf_mac("ConnectToServerTcp failed\r\n");
- osDelay(5000);
- continue;
- }
- #ifdef DEBUG_CLIENT_TASK
- mbedtls_printf_mac("ConnectOK\r\n");
- #endif
- sslTaskTimerCounter = 1;
- ret = mbedtls_ssl_session_reset(&ssl);
- if (ret != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_session_reset returned %d\r\n \r\n ", ret);
- mbedtls_ssl_free(&ssl);
- mbedtls_ssl_init(&ssl);
- ret = mbedtls_ssl_setup(&ssl, &conf);
- if (ret != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_setup(re) returned %d\r\n \r\n ", ret);
- mbedtls_net_free(&server_fd);
- osDelay(30000);
- continue;
- }
- ret = mbedtls_ssl_set_hostname(&ssl, "rcpkd");
- if (ret != 0) {
- mbedtls_printf_mac("ERROR - mbedtls_ssl_set_hostname(re) returned %d\r\n \r\n ", ret);
- mbedtls_net_free(&server_fd);
- osDelay(30000);
- continue;
- }
- }
- //Po każdym zerwaniu połączenia czy reset należy przypiąć nowe BIO
- mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
- handshakeTimeoutCount = 0;
- HandshakeStart = 2;
- #ifdef DEBUG_CLIENT_TASK
- mbedtls_printf_mac("HS Start\r\n");
- #endif
- #ifdef DEBUG_CLIENT_TASK
- PrintTaskWatermark("before handshake");
- #endif
- ret = Handshake_timeout(20000); // 20s
- #ifdef DEBUG_CLIENT_TASK
- PrintTaskWatermark("after handshake");
- #endif
- if (ret != 0) {
- HandshakeStart = 0;
- handshakeTimeoutCount = 0;
- goto cleanup_session;
- }
- ConnectingToServerFlag = 0;
- HandshakeStart = 1;
- handshakeTimeoutCount = 0;
- #ifdef DEBUG_CLIENT_TASK
- mbedtls_printf_mac("[StartSSLClientTask] HAND\r\n");
- #endif
- VarifyCertificate();
- #ifdef DEBUG_CLIENT_TASK
- mbedtls_printf_mac("[StartSSLClientTask] VERCERT\r\n");
- #endif
- #ifdef DEBUG_CLIENT_TASK
- printf("[StartSSLClientTask] before auth cmd\r\n");
- printf("[StartSSLClientTask][HEAP] free=%u min=%u\r\n",
- (unsigned)xPortGetFreeHeapSize(),
- (unsigned)xPortGetMinimumEverFreeHeapSize());
- #endif
- PrepareAndSendAuthenticationCommandToServer();
- #ifdef DEBUG_CLIENT_TASK
- printf("[StartSSLClientTask] after auth cmd\r\n");
- printf("[StartSSLClientTask][HEAP] free=%u min=%u\r\n",
- (unsigned)xPortGetFreeHeapSize(),
- (unsigned)xPortGetMinimumEverFreeHeapSize());
- #endif
- while (1)
- {
- len = sizeof(buf) - 1;
- memset(buf, 0, sizeof(buf));
- #ifdef DEBUG_CLIENT_TASK
- printf("[StartSSLClientTask] before first read\r\n");
- printf("[StartSSLClientTask][HEAP] free=%u min=%u\r\n",
- (unsigned)xPortGetFreeHeapSize(),
- (unsigned)xPortGetMinimumEverFreeHeapSize());
- #endif
- ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);
- #ifdef DEBUG_CLIENT_TASK
- printf("[SSL] read ret=%d\r\n", ret);
- #endif
- if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
- ret == MBEDTLS_ERR_SSL_WANT_WRITE)
- {
- osDelay(10);
- continue;
- }
- if (ret == MBEDTLS_ERR_SSL_TIMEOUT)
- {
- sslReadTimeoutCounter++;
- printf("[SSL] read timeout count=%u\r\n", sslReadTimeoutCounter);
- if (sslReadTimeoutCounter >= 7)
- {
- printf("[SSL] too many read timeouts -> reconnect\r\n");
- break;
- }
- osDelay(10);
- continue;
- }
- if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
- {
- osDelay(10);
- continue;
- }
- //Poprawne zamknięcie połączenia przez serwer
- if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
- {
- break;
- }
- if (ret < 0)
- {
- printf("SSL read error: %d\n", ret); // prawdziwy błąd
- break;
- }
- if (ret == 0)
- {
- // EOF / TCP close
- break;
- }
- counterSSLTimeout = 0;
- sslTaskTimerCounter = 1;
- sslReadTimeoutCounter = 0;
- Analize_Msg(buf, ret);
- }
- //Cleanup oraz reconnect
- cleanup_session:
- mbedtls_printf_mac("close session...\r\n \r\n ");
- do {
- ret = mbedtls_ssl_close_notify(&ssl);
- } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
- (void)mbedtls_ssl_session_reset(&ssl);
- mbedtls_net_free(&server_fd);
- flagSSLTask = 0;
- osDelay(20000);
- continue;
- }
- exit_task:
- mbedtls_printf_mac("error on mbedtls...\r\n \r\n ");
- mbedtls_net_free(&server_fd);
- mbedtls_x509_crt_free(&cacert);
- mbedtls_x509_crt_free(&server_cert);
- mbedtls_ssl_free(&ssl);
- mbedtls_ssl_config_free(&conf);
- mbedtls_ctr_drbg_free(&ctr_drbg);
- mbedtls_entropy_free(&entropy);
- #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
- mbedtls_memory_buffer_alloc_free();
- #endif
- SSLClient_FreeMemmory();
- mbedtls_printf_mac("Task delete\r\n \r\n ");
- vTaskDelete(NULL);
- }
Powyższa implementacja pokazuje dosyć stabilne zestawienie i utrzymanie połączenia TLS 1.2 w systemach wbudowanych, które bazują na bibliotece mbedTLS.