czwartek, 4 listopada 2021

STM32 - H723ZG - TCP Client SSL

W tym poście chciałbym opisać sposób komunikacji pomiędzy układem STM32H7 działającym jako Client TCP z serwerem po SSL.

[Źródło: https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-nucleo-boards/nucleo-h753zi.html#overview]

Generowanie certyfikatów:


Obsługę generowania przykładowych certyfikatów opisałem w poście dotyczącym programu C# - TCP Client oraz TCP Server. Tutaj zasada jest identyczna. Natomiast do programu klienta umieszczonego w układzie STM32H7 nie będę wykorzystywał certyfikatu w formacie *.pfx tylko jako PEM.

Połączenie SSL

W związku z tym, że korzystamy z biblioteki MBEDTLS warto się zapoznać z połączeniem SSL. Ogólnie warto poznać temat przed jego wykonaniem, natomiast w tym przypadku jest dużo elementów konfiguracyjnych wewnątrz biblioteki. Programowanie nie jest tak proste jak w przypadku ustanowienia połączenia SSL np. w C#, gdzie jest wykorzystywana dużo bardziej rozbudowana biblioteka z mniejszą możliwością wygenerowania błędów.

Dokładny opis połączenie SSL można znaleźć pod tym linkiem oraz tutaj.

Komunikacja odbywa się w następujący sposób:

Client Hello - wysłanie startowej wiadomości od klienta do serwera. W przypadku opisywanego rozwiązania wiadomość będzie zawierała informację z obsługiwaną wersją TLS, wygenerowanymi losowymi informacjami, identyfikatorem sesji oraz metod szyfrowania oraz sposobu wymiany kluczy przez klienta.


Server Hello - serwer wysyła wybrany rodzaj komunikacji TLS, wygenerowane losowe dane, identyfikator sesji, wybrane algorytmy szyfrowania, metodę wymiany kluczy, funkcję do uzyskania wartości MAC. Dodatkowo przesyła certyfikat wraz z żądaniem pobrania certyfikatu klienta.


Po tej wiadomości następuje weryfikacja certyfikatu przez klienta.

Client Certyfikat - kolejnym elementem jest przesłanie certyfikatu klienta. 


Client Key Exchange - przesłanie kluczy klienta do serwera.


Certificate Verify  - dodatkowa informacja do weryfikacji certyfikatu.


Change Cipher Spec - wiadomości przesyłane pomiędzy klientem a serwerem. W wiadomości przesyłana jest informacja (wartość 1) o ustanowieniu wynegocjowanej sesji.


Po tych operacjach połączenie jest poprawnie ustanowione. Poniżej zrzut ekranu z przesłanymi danymi pomiędzy klientem a serwerem.


Program:


W projekcie wykorzystałem FREERTOS, LWIP oraz MBEDTLS.

Przy wykonywaniu połączenia należy pamiętać o wyłączeniu zapory, lub ustawieniu odpowiedniego wyjątku. W innym przypadku może nie udać się nawiązać połączenia pomiędzy klientem a serwerem.

Poniżej plik lwipopts.h z którego usunąłem komentarze. Plik ten jest generowany na podstawie ustawień przekazanych przez CubeMx:

  1. #ifndef __LWIPOPTS__H__
  2. #define __LWIPOPTS__H__
  3.  
  4. #include "main.h"
  5.  
  6. /*-----------------------------------------------------------------------------*/
  7. /* Current version of LwIP supported by CubeMx: 2.1.2 -*/
  8. /*-----------------------------------------------------------------------------*/
  9.  
  10. #ifdef __cplusplus
  11.  extern "C" {
  12. #endif
  13.  
  14. #define WITH_RTOS 1
  15. #define WITH_MBEDTLS 1
  16. #define CHECKSUM_BY_HARDWARE 1
  17. #define LWIP_DHCP 1
  18. #define ETH_RX_BUFFER_SIZE 2144
  19. #define LWIP_DNS 1
  20. #define MEM_ALIGNMENT 4
  21. #define LWIP_RAM_HEAP_POINTER 0x30004000
  22. #define LWIP_SUPPORT_CUSTOM_PBUF 1
  23. #define LWIP_ETHERNET 1
  24. #define LWIP_DNS_SECURE 7
  25. #define TCP_SND_QUEUELEN 9
  26. #define TCP_SNDLOWAT 1071
  27. #define TCP_SNDQUEUELOWAT 5
  28. #define TCP_WND_UPDATE_THRESHOLD 536
  29. #define LWIP_NETIF_LINK_CALLBACK 1
  30. #define TCPIP_THREAD_STACKSIZE 1024
  31. #define TCPIP_THREAD_PRIO osPriorityNormal
  32. #define TCPIP_MBOX_SIZE 6
  33. #define SLIPIF_THREAD_STACKSIZE 1024
  34. #define SLIPIF_THREAD_PRIO 3
  35. #define DEFAULT_THREAD_STACKSIZE 1024
  36. #define DEFAULT_THREAD_PRIO 3
  37. #define DEFAULT_UDP_RECVMBOX_SIZE 6
  38. #define DEFAULT_TCP_RECVMBOX_SIZE 6
  39. #define DEFAULT_ACCEPTMBOX_SIZE 6
  40. #define RECV_BUFSIZE_DEFAULT 2000000000
  41. #define LWIP_USE_EXTERNAL_MBEDTLS 1
  42. #define LWIP_STATS 0
  43. #define CHECKSUM_GEN_IP 0
  44. #define CHECKSUM_GEN_UDP 0
  45. #define CHECKSUM_GEN_ICMP6 0
  46. #define CHECKSUM_CHECK_IP 0
  47. #define CHECKSUM_CHECK_UDP 0
  48. #define CHECKSUM_CHECK_TCP 0
  49. #define CHECKSUM_CHECK_ICMP6 0
  50.  
  51. #ifdef __cplusplus
  52. }
  53. #endif
  54. #endif /*__LWIPOPTS__H__ */
 
Teraz parametry biblioteki MBEDTLS. Zostały one zapisane w wygenerowanym pliku mbedtls_config.h. Podobnie jak poprzednio z pliku usunąłem komentarze oraz nieuruchomione części biblioteki wszystkie dodatkowe informacje pojawią się w tym pliku po wygenerowaniu projektu.

  1. #ifndef MBEDTLS_CONFIG_H
  2. #define MBEDTLS_CONFIG_H
  3.  
  4. #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
  5. #define _CRT_SECURE_NO_DEPRECATE 1
  6. #endif
  7.  
  8. #define MBEDTLS_HAVE_ASM
  9. #define MBEDTLS_NO_UDBL_DIVISION
  10. #define MBEDTLS_HAVE_TIME
  11. #define MBEDTLS_PLATFORM_MEMORY
  12. #define MBEDTLS_ENTROPY_HARDWARE_ALT
  13. #define MBEDTLS_AES_ROM_TABLES
  14. #define MBEDTLS_CIPHER_MODE_CBC
  15. #define MBEDTLS_CIPHER_MODE_OFB
  16. #define MBEDTLS_CIPHER_MODE_XTS
  17. #define MBEDTLS_REMOVE_3DES_CIPHERSUITES
  18. #define MBEDTLS_ECP_DP_SECP256R1_ENABLED
  19. #define MBEDTLS_ECP_DP_SECP384R1_ENABLED
  20. #define MBEDTLS_ECP_DP_CURVE448_ENABLED
  21. #define MBEDTLS_ECP_NIST_OPTIM
  22. #define MBEDTLS_ECP_RESTARTABLE
  23. #define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
  24. #define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
  25. #define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
  26. #define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
  27. #define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
  28. #define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
  29. #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
  30. #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
  31. #define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
  32. #define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
  33. #define MBEDTLS_PK_PARSE_EC_EXTENDED
  34. #define MBEDTLS_NO_PLATFORM_ENTROPY
  35. #define MBEDTLS_ENTROPY_FORCE_SHA256
  36. #define MBEDTLS_PKCS1_V15
  37. #define MBEDTLS_PKCS1_V21
  38. #define MBEDTLS_SSL_RENEGOTIATION
  39. #define MBEDTLS_SSL_PROTO_TLS1_2
  40. #define MBEDTLS_SSL_SERVER_NAME_INDICATION
  41. #define MBEDTLS_AES_C
  42. #define MBEDTLS_ASN1_PARSE_C
  43. #define MBEDTLS_ASN1_WRITE_C
  44. #define MBEDTLS_BASE64_C
  45. #define MBEDTLS_BIGNUM_C
  46. #define MBEDTLS_BLOWFISH_C
  47. #define MBEDTLS_CAMELLIA_C
  48. #define MBEDTLS_CERTS_C
  49. #define MBEDTLS_CHACHA20_C
  50. #define MBEDTLS_CHACHAPOLY_C
  51. #define MBEDTLS_CIPHER_C
  52. #define MBEDTLS_CTR_DRBG_C
  53. #define MBEDTLS_DEBUG_C
  54. #define MBEDTLS_DES_C
  55. #define MBEDTLS_DHM_C
  56. #define MBEDTLS_ECDH_C
  57. #define MBEDTLS_ECDSA_C
  58. #define MBEDTLS_ECP_C
  59. #define MBEDTLS_ENTROPY_C
  60. #define MBEDTLS_GCM_C
  61. #define MBEDTLS_HKDF_C
  62. #define MBEDTLS_HMAC_DRBG_C
  63. #define MBEDTLS_MD_C
  64. #define MBEDTLS_MD5_C
  65. #define MBEDTLS_NET_C
  66. #define MBEDTLS_OID_C
  67. #define MBEDTLS_PEM_PARSE_C
  68. #define MBEDTLS_PK_C
  69. #define MBEDTLS_PK_PARSE_C
  70. #define MBEDTLS_PK_WRITE_C
  71. #define MBEDTLS_PKCS5_C
  72. #define MBEDTLS_PLATFORM_C
  73. #define MBEDTLS_POLY1305_C
  74. #define MBEDTLS_RSA_C
  75. #define MBEDTLS_SHA1_C
  76. #define MBEDTLS_SHA256_C
  77. #define MBEDTLS_SHA512_C
  78. #define MBEDTLS_SSL_CLI_C
  79. #define MBEDTLS_SSL_TLS_C
  80. #define MBEDTLS_X509_USE_C
  81. #define MBEDTLS_X509_CRT_PARSE_C
  82. #define MBEDTLS_X509_CRL_PARSE_C
  83. #define MBEDTLS_X509_CSR_PARSE_C
  84. #define MBEDTLS_X509_CREATE_C
  85. #define MBEDTLS_X509_CRT_WRITE_C
  86. #define MBEDTLS_X509_CSR_WRITE_C
  87.  
  88. #define MBEDTLS_MPI_WINDOW_SIZE          6
  89. #define MBEDTLS_MPI_MAX_SIZE           1024
  90.  
  91. #define MBEDTLS_ECP_MAX_BITS             384
  92. #define MBEDTLS_ECP_WINDOW_SIZE            2
  93. #define MBEDTLS_ECP_FIXED_POINT_OPTIM      0
  94.  
  95. #define MBEDTLS_ENTROPY_MAX_SOURCES                2
  96. #define MBEDTLS_PLATFORM_PRINTF_MACRO        printf
  97.  
  98. #define MBEDTLS_SSL_MAX_CONTENT_LEN             4096
  99. #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA
  100.  
  101. #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE
  102.  
  103. #if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE)
  104.     #include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE
  105. #endif
  106.  
  107. #if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE)
  108.     #include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE
  109. #elif defined(MBEDTLS_USER_CONFIG_FILE)
  110.     #include MBEDTLS_USER_CONFIG_FILE
  111. #endif
  112. #include "mbedtls/check_config.h"
  113.  
  114. #endif /* MBEDTLS_CONFIG_H */



Zgodnie z utworzonym certyfikatem należy ustawić odpowiedni rodzaj algorytmów do wykorzystywania podczas uwierzytelniania i wykonywania połączenia:

  1. //Domyślne wartości
  2. #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  3. //Zgodnie z certyfikatem parametr zmieniłem na
  4. #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA

Następnie należy pamiętać o ustawieniu MBED_MPI_MAX_SIZE na 1024.

W celu uruchomienia wątku klienta należy uruchomić następujący wątek:

  1. osThreadDef(sslTask, StartSSLClientTask, osPriorityIdle, 0, 2048);
  2. sslTaskHandle = osThreadCreate(osThread(sslTask), NULL);

Jak wspomniałem wcześniej certyfikaty należy umieścić bezpośrednio w programie:

  1. const char mbedtls_client_certificate[] =
  2.     "-----BEGIN CERTIFICATE-----\r\n"
  3.     "MIIFozCCA4ugAwIBAgIUOtz+OtV2UohNiHJcfGLtAI5JKbQwDQYJKoZIhvcNAQEL\r\n"
  4.     "BQAwYTELMAkGA1UEBhMCUEwxEzARBgNVBAgMCk1hbG9wb2xza2ExDzANBgNVBAcM\r\n"
  5.     "BktyYWtvdzENMAsGA1UECgwEVGVzdDEKMAgGA1UECwwBLTERMA8GA1UEAwwIdGVz\r\n"
  6.     "dF9zc2wwHhcNMjExMDA5MjIzMDQ1WhcNMzExMDA3MjIzMDQ1WjBhMQswCQYDVQQG\r\n"
  7.     "EwJQTDETMBEGA1UECAwKTWFsb3BvbHNrYTEPMA0GA1UEBwwGS3Jha293MQ0wCwYD\r\n"
  8.     "VQQKDARUZXN0MQowCAYDVQQLDAEtMREwDwYDVQQDDAh0ZXN0X3NzbDCCAiIwDQYJ\r\n"
  9.     "KoZIhvcNAQEBBQADggIPADCCAgoCggIBALRXn/DgCYVL+ffzEs7oAPi3L/qZvGWW\r\n"
  10.     "4bcX1OsIeAuPsMY523RA9feXYjEx44JYpYK5Q7UIilpPKD+mj4+JlhI+iEN42fRN\r\n"
  11.     "nGMb/WD/fBNeu7QZ2+9ujbuaa0TOjK8bEVOU2lhc7csNkm2k7/QieqNLJKm8EFQc\r\n"
  12.     "moDsRCTdSP1foYL1PkK+1NUs3iCnANYOM9t5XsVH4bZeS5ECvPjqJTTGCbw0dvMy\r\n"
  13.     "9VHbGW53XDltv29fTEYWkuW2CLO3dtBW7CWUTNJgoN8mRne7dLOmrNmD76yy+8aq\r\n"
  14.     "FVolAv0/SEHGOXGhPCXIjQyvZRtAI2fk5HhpVvTG1LP+Ypw3bhG7+x3Ga7kGAG6J\r\n"
  15.     "0lhIB92IcpZQmKGMPj7Z5qZrBzi3+IFhOlzRz+L+53Gz/Op9+DJ86GqlY/V91b5k\r\n"
  16.     "vkB1FQAnlqNMlBm3synXkg1zlL27x529cgZytrh9qBqtC1kZNop8z8nsnpyaf2M7\r\n"
  17.     "LSW+dpxt9H+C8Xx5C8LP4ppo2MeoeJmrFAejToWNTa7vpCXBuvqwg5bC8tM0C+sK\r\n"
  18.     "IGXStuRzm41xlRN2dSE/FsVsWwNg2gqGpo1lymmKZadUbrTqURo9v7jYHTEfbo7t\r\n"
  19.     "2/65bd69IK+3KsLPCiS2yVb1CGM+7rGbKXuo9d7Tmi+cWrnF5lABwEOMZfpdOScG\r\n"
  20.     "IudTyX3eMIdNAgMBAAGjUzBRMB0GA1UdDgQWBBRMkqUo7Y/zDV+DSbyCYqkJ3woX\r\n"
  21.     "VzAfBgNVHSMEGDAWgBRMkqUo7Y/zDV+DSbyCYqkJ3woXVzAPBgNVHRMBAf8EBTAD\r\n"
  22.     "AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAi1KP5PydFymqcKZ8b9HqkYso0xioJB7t2\r\n"
  23.     "hS/+DaNM+eABV3tQufP/s9XOG9XQ7lzi/38hN89sWfKZUNedEBOYZINRQIzZybeW\r\n"
  24.     "WOFmv5RpiDXJy3K7ad2WOHYFr84A5pkwZ0EXldinvZCNs0gwMfxU59EsfbYgm41p\r\n"
  25.     "Sw07HvRPMRhkJQKfciQmGp3/GGbc/UGUVosjraMf6jD5pRf/rWpHLbdvcSoqERZP\r\n"
  26.     "Di4grBVBo5P3rtUMn5j9yGZlqbW7+k54FfXgSh9SETOzMxPkeZ/URh2xBLABGYh6\r\n"
  27.     "nYo6i8nlOQJw7noE1s049S5DkOvkoSjHBN9/BtVH5HH1Q2o/sZ3+/FG5gEQ+6uzO\r\n"
  28.     "73iGqCt/eS58rPOG6RyQqeA/5PigWLRJotM8Fos6w1J283EdppaH/OTb8lxTN9YJ\r\n"
  29.     "i1VhrVD5JmN6v6DgLskQQtC5EQd7kEd/H/aMU+liMCL9Dm+Wb4NR6dyiBdrGP/F4\r\n"
  30.     "AAEUzIl0bQlapSqKvLOAcY83UaebGUI6veDSKvBdj0NeC/b9bn8ZwuXHdl/2bABl\r\n"
  31.     "8ChugcqXDzTOkqC5XDpJj4dzP77GSa57U4/JCe8akWlpMEQ8ww9cmHfzvpTaoC0h\r\n"
  32.     "YJa7cSKocEayGVzIZFzAuLzzpcIFZv9EDQYW7O3wa3B0iFMys0Jn8NDr5ggSBNaa\r\n"
  33.     "NIrzbeAz1g==\r\n"
  34.     "-----END CERTIFICATE-----\r\n";
  35.  
  36. const char mbedtls_certificate_key_pass[] = "test5432!";
  37.  
  38. const char mbedtls_certificate_key[] =
  39.         "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n"
  40.         "MIIJnDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQI4JcJ1wVIYmwCAggA\r\n"
  41.         "MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECEGidL7lbokwBIIJSPiJe/fnzl2X\r\n"
  42.         "NPI2YF/6r/Zy/+nfyWvluCqeAGzsIZUshmLM7JG237MWm0QQphFX0Wx8FUovcD2E\r\n"
  43.         "ti3KHeeRP5HLmPVPjfYMO60E1aHvoCmowTFi6mpIttbigSXDfoeDGVy7/yhUggey\r\n"
  44.         "+9zacVdqoVZDaCMWa1RwjznI1y0rcfJFOIJrhegu5q9AsFrWbvZ5ShO/J0TuRaGU\r\n"
  45.         "bJmY2N2YNfPfsoxmYwekHs+nlIeYOaCozUF9ccvkxlNOn1AeqIahZSYcYOg1b1YN\r\n"
  46.         "YMyg8F89q+QVIlx2shd5NBx+hhcsMjbIDeZuJulTJTxYo46Sqh2txpm7MYJQy14r\r\n"
  47.         "4EA7KvWJ4MeP5cWM1lxhY+yDgAbSy07hJ0Bi2+HJJ6qrvYzRZ6mBvahrEoSP1Wts\r\n"
  48.         "TK6sEry48O9EmXjWQsR91VxlB+XlsUpGdYcdey66GQwLG1NOwalPMCgLspUg0KLg\r\n"
  49.         "LQxlm5xMEot9Es95xngySexk6WnpIKpLzCyecx290zheGxibO0ihxSNsq1IOZomn\r\n"
  50.         "1NlxC8JAB5QdYX8JUq7Q+909yniaHbUTxgek97CTun+1jNO07HSbXfhEOBdaqEFL\r\n"
  51.         "KcksrenRZp3eRo8brlu85fbjinWPWPZgsh8BsL2/ob4OrNM/cmlXN+TmOj1LS1HO\r\n"
  52.         "AR4LN/jJ8xPluoq38JwILubu42l+Ocjjclhsyv3d6xStvbujgGghVTC5xv+7Ticq\r\n"
  53.         "NnEXH5eJtZmjpEpbXlhwufxkil2ARurVDLhvK0t4WAXDZLXlz3O4LBy1nlIt8D4/\r\n"
  54.         "zpIt8NPKvLHwzL8MpxX9nJ9w5CBwMRfw3/WwinRHLjQsz+T9KKunVwDZ+BfuSvai\r\n"
  55.         "kv+S1Qh8qZLU4YRQQUO/nTiJZ9h6gG9f7v07aCXkJA6+REg/J5x50FaK5qJg28ga\r\n"
  56.         "7P2WT+GTZoHyCjh79qr8aWBjueeJiRXv1dAO6lgfCyyxSwRPIGoVV5BhdB2drGYu\r\n"
  57.         "691CpZplBWyxDA448NxU1csFRodQOczgtlgpyZAAVeGW0PHKszgOZMXRLXp0mU2e\r\n"
  58.         "gjxOKkhsbpYO8GHEoy+Bw8pnw1b5n350qog3Ip6IEDjYI3zje6kKT4O6DoNHCq/y\r\n"
  59.         "KemxEYixlzInBxhWDLWxhbWoVWRCH+UUtxbsFQqiWX61CTktR3kP+Frqc7XOiIMo\r\n"
  60.         "OV2Tq+YQ/QIEEc9h4FoK84Ok8r7voCcDtkbiLUC6EFHsqDgtJ7tbzCTGuzgw8IX/\r\n"
  61.         "jCN382vQqwMCy338RSTzXxeHgAFopOQHBE44ZwEpP6StNUsif/0T0j2a7kyFslnA\r\n"
  62.         "SHkh5BMSxOQwv5xe8sGjzHlZ8j+R9taKRkcyLJ24GpTmXF/dD/v0US5NTmesWSjD\r\n"
  63.         "Nm6G1UIw9Un5qd0JhGXSjrEYUfq4BmzH0tU5uxEEsc+fjJzr9/8osY2kMBXkpRhf\r\n"
  64.         "nJj7XRkTX9987y34ZZKkeDMkD55fQ9SUyj2WMFzYvbZEK1bDQ9KhCkZEl8Vl3Dj0\r\n"
  65.         "HtotyG2187DPE16y0bvfvhrZ5e2gYGkASvHOubHetmOclyH8CSyZRmLNsXJuv+C8\r\n"
  66.         "KEN4Hf490ibL7CocMxTR94lFE3feuqIVk78c2CVY4ebzbUOTSc/S9rGvRXy+XT4i\r\n"
  67.         "o3FvPhE4muODu6A4sesSgX1DRMOIinfDpOwc6mpVr6BG/RS1Spo4Hvzxq8vrbKvo\r\n"
  68.         "wS3KP8EX2PITdY9vzz+Cswe3klaz1ad9RxFCKiXbtAAs7z8ryIClyKIOtoBwBhjE\r\n"
  69.         "s788NW5mInYHQ05/ax+MhvvrW+BZ+K4/Cp7fy5Smfh42igPyoArw0aGZZSxqO6Mo\r\n"
  70.         "qg9eA54o0udb7ZsgSeZMvuJS0tvrxkuggqr9AqPaD9CBTKhuKhOXEGw0GkeoNcfO\r\n"
  71.         "1tVUx/nFZ3T/eGfV8XPj4K1KomeiHhNE4o+b9jphJ9C4XrABG4Zp6sB29huBtIE9\r\n"
  72.         "tZ0Yh87xfLQuzbRxSxTJpPOf3wBQeQBzxfrGGFsa3Y7C/BJRQIzQBAj5F/+WrCUf\r\n"
  73.         "QgmScFwC4CdNhC2FzyGjYf4YPE5aWwYgPSNbvFB6FiwbOjWrr5modaIDrv/iUlRb\r\n"
  74.         "S1eE9zpOtmJt1ilyAIanMHzN0GmPyVbwU3aOetEPlSYBgkQ0CEMRlwpAxcNUyUbQ\r\n"
  75.         "CxeAvKPb++0QrI1bV1gHNvbIUDr3L5R4KSWNQL9jrEXRIxZdkGR8/UrMjcEevsdv\r\n"
  76.         "zRAoC/osMOyF8Om7Tu/xDcKwQZHatz7RpJ+FrBtAuJUn8fALCZQjG8GienrNs88Q\r\n"
  77.         "LTopETOsZu9kBglTTWSBoIfjBmn/rzvl4fnXtvRz/ZcN56X3u9UC1+Qiv2jk3dQz\r\n"
  78.         "1pAUwhQCBnBabiSPy+MzBcu6gBKAVWNRaRk7zfkgyRDn3vz2JAX7vApfXEBMglef\r\n"
  79.         "2aA7NBY0nfW7C2ls565UQwrn7xEqbSw27kDeZrlwJlCOQWO6IFI62QKIvV5H/9O+\r\n"
  80.         "tFJZMqVge6j7sYfFXjulhNDKpSz+QW2H99NYg5h50uKAU71/mLLxzerIfCE2Z/W2\r\n"
  81.         "8/kLuljPBbRsbE9CFalWj0qos5U97vBMSLCUXaDQYPhI7yQcEBY4N1PQBMMe3c1u\r\n"
  82.         "uxyuHrXfo1pvPm26Ung/7/nbmbwtspvmUCRwEU/TTyDeilfh+V0hbj+gQRoJnLl3\r\n"
  83.         "PvC3useEuYzYhJAE3fL0sosfTgQKYLf9sh6HZSKv+TJzDTR3xN9QU0396OhVcuO5\r\n"
  84.         "5sfiQkhHY8OWVs/QBZYhmRN32MTfLvpjzxx+Ln/rAAUV594BG9fvgLmD0djOoRwc\r\n"
  85.         "7SD3doWoZYa3qwG/xlJGLT1FyD7/6abpyDBo63VSDBJy3OouTzkHr6H07sPUEpnC\r\n"
  86.         "SMCeYPfXMi1oHRBpxbBRbQ6VaV6E3rgfuHFb72/Wky+yUH+ZtwkOIGEYqrKTIkDv\r\n"
  87.         "DqVVwCkDVoYTaJ2BNRi/w7vUlEtelhDSvEhtD7LpwLoGpN7d0sXsnXDBLCI1AZoH\r\n"
  88.         "JZ2jMFj3L8HeCdfZtzfy/W01qZmaqTy18NXNfE5S3dTPAyrsfl+40jRK4YMOBGFS\r\n"
  89.         "EghSVUn9li41zGbLpHif34T/Xif+tFXo57G+y8oI2PRni6i+qtFN+ehW1LPpAFax\r\n"
  90.         "7CHOoz1jeqy/cbdJV9om4v0XpRS63lU+udmYd0wFsxDlUdzPKcBTP2evOFu36u2w\r\n"
  91.         "5e/ibghY4Lc8gQtcLXtOKQ==\r\n"
  92.         "-----END ENCRYPTED PRIVATE KEY-----\r\n"
  93.  
  94. const size_t mbedtls_client_certificate_len = strlen(mbedtls_client_certificate);
  95. const size_t mbedtls_certificate_key_len = sizeof(mbedtls_certificate_key);
  96. const size_t mbedtls_certificate_key_pass_len = strlen(mbedtls_certificate_key_pass);

Na początku wątku obsługującego połączenie SSL należy zainicjalizować zmienne  RNG oraz wszystkie struktury obsługujące wykonywane połączenie:

  1. static void Initialize_SessionData(void)
  2. {
  3.       mbedtls_net_init(&server_fd);
  4.       mbedtls_ssl_init(&ssl);
  5.       mbedtls_ssl_config_init(&conf);
  6.       mbedtls_x509_crt_init(&cacert);
  7.       mbedtls_ctr_drbg_init(&ctr_drbg);
  8.       mbedtls_pk_init(&pkey);
  9.       mbedtls_entropy_init(&entropy);
  10. }

  1. static int Drbg_Seed(void)
  2. {
  3.     int opStatus = 0;
  4.     if((opStatus = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*) pers, strlen(pers))) != 0) {
  5.         mbedtls_printf(" failed\r\n   ! mbedtls_ctr_drbg_seed returned %d\r\n ", opStatus);
  6.         return opStatus;
  7.     }
  8.     return opStatus;
  9. }

Następnie obsługa certyfikatu:

  1. ret = mbedtls_pk_parse_key( &pkey,
  2.         (const unsigned char*)mbedtls_certificate_key,
  3.         mbedtls_certificate_key_len,
  4.         (const unsigned char*)mbedtls_certificate_key_pass,
  5.         mbedtls_certificate_key_pass_len);
  6.  
  7.  
  8. if(ret < 0) {
  9.     mbedtls_printf("mbedtls_pk_parse_key failed returned -0x%x\r\n \r\n ", (unsigned int) -ret);
  10. }
  11.  
  12. ret = mbedtls_x509_crt_parse(&cacert,
  13.           (const unsigned char*)mbedtls_client_certificate,
  14.           mbedtls_client_certificate_len + 1);
  15.  
  16. if(ret < 0)
  17. {
  18.     mbedtls_printf("mbedtls_x509_crt_parse returned -0x%x\r\n \r\n ", (unsigned int) -ret);
  19.     goto exit;
  20. }
  21.  
  22. ret = mbedtls_ssl_conf_own_cert(&conf, &cacert, &pkey);
  23. if(ret < 0) {
  24.     mbedtls_printf("mbedtls_ssl_conf_own_cert returned -0x%x\r\n \r\n ", (unsigned int) -ret);
  25. }

Na samym początku należy wprowadzić klucz do certyfikatu, następnie przechodzę do obsługi certyfikatu. 

  1. static int InitializeCertificate(void)
  2. {
  3.     int opStatus = 0;
  4.  
  5.     fflush( stdout);
  6.  
  7.     opStatus = mbedtls_pk_parse_key( &pkey,
  8.               (const unsigned char*)mbedtls_certificate_key,
  9.               mbedtls_certificate_key_len,
  10.               (const unsigned char*)mbedtls_certificate_key_pass,
  11.               mbedtls_certificate_key_pass_len);
  12.  
  13.     if(opStatus < 0) {
  14.         mbedtls_printf("ERROR - mbedtls_pk_parse_key returned -0x%x\r\n \r\n ", (unsigned int) -opStatus);
  15.         return opStatus;
  16.     }
  17.  
  18.     opStatus = mbedtls_x509_crt_parse(&cacert, (const unsigned char*)mbedtls_client_certificate, mbedtls_client_certificate_len + 1);
  19.  
  20.     if(opStatus < 0) {
  21.         mbedtls_printf("ERROR - mbedtls_x509_crt_parse returned -0x%x\r\n \r\n ", (unsigned int) -opStatus);
  22.         return opStatus;
  23.     }
  24.  
  25.     opStatus = mbedtls_ssl_conf_own_cert(&conf, &cacert, &pkey);
  26.     if(opStatus < 0) {
  27.           mbedtls_printf("ERROR - mbedtls_ssl_conf_own_cert returned -0x%x\r\n \r\n ", (unsigned int) -opStatus);
  28.           return opStatus;
  29.     }
  30.     return opStatus;
  31. }

Następny element oczekuje na uzyskanie połączenia:

  1. static void ValidateIpAddress(void)
  2. {
  3.     while(1)
  4.     {
  5.         if(gnetif.ip_addr.addr == 0 || gnetif.netmask.addr == 0 || gnetif.gw.addr == 0)
  6.         {
  7.           osDelay(1000);
  8.           continue;
  9.         }
  10.         else
  11.         {
  12.           printf("DHCP/Static IP O.K.\r\n ");
  13.           break;
  14.         }
  15.     }
  16. }

Następnie przechodzę do nawiązania połączenia po TCP:

  1. static void ConnectToServerTcp(void)
  2. {
  3.     int opStatus = 0;
  4.  
  5.     while(1)
  6.     {
  7.       if((opStatus = mbedtls_net_connect(&server_fd, SERVER_NAME, SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) == 0)
  8.       {
  9.         mbedtls_printf("mbedtls_net_connect OK\r\n ");
  10.         break;
  11.       }
  12.       else
  13.       {
  14.         mbedtls_printf(" failed\r\n   ! mbedtls_net_connect returned %d\r\n \r\n ", opStatus);
  15.         osDelay(100);
  16.       }
  17.     }
  18. }

Kolejnym elementem jest załadowanie domyślnej konfiguracji dla biblioteki mbedtls:

  1. static uint8_t LoadDefaultConfiguration(void)
  2. {
  3.     int opStatus = 0;
  4.  
  5.      if((opStatus = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
  6.     {
  7.       mbedtls_printf("ERROR - mbedtls_ssl_config_defaults returned %d\r\n \r\n ", opStatus);
  8.       return opStatus;
  9.     }
  10.  
  11.     return opStatus;
  12. }

Konfiguracja połączenia SSL:

  1. static uint8_t ConnectionSSL_Configuration(void)
  2. {
  3.     int opStatus = 0;
  4.  
  5.     mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
  6.     mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
  7.     mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
  8.     mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
  9.  
  10.     if((opStatus = mbedtls_ssl_setup(&ssl, &conf)) != 0)
  11.     {
  12.       mbedtls_printf("ERROR - mbedtls_ssl_setup returned %d\r\n \r\n ", opStatus);
  13.       return opStatus;
  14.     }
  15.  
  16.     return opStatus;
  17. }

Ustawienie nazwy serwera, do którego będziemy się łączyć. Ta informacja znajduje się w przygotowywanym certyfikacie. Drugim elementem jest ustawienie wywołań zwrotnych dla nadawania, odbierania.

  1. static uint8_t SetHostname_BioCallbacks(void)
  2. {
  3.     int opStatus = 0;
  4.  
  5.     if((opStatus = mbedtls_ssl_set_hostname(&ssl, "server_name")) != 0)
  6.     {
  7.       mbedtls_printf("ERROR - mbedtls_ssl_set_hostname returned %d\r\n \r\n ", opStatus);
  8.       return opStatus;
  9.     }
  10.  
  11.     mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
  12.     return opStatus;
  13. }

W następnym kroku rozpoczynam procedurę handshake gdzie są negocjowane parametry połączenia pomiędzy klientem oraz serwerem.

  1. static uint8_t Handshake(void)
  2. {
  3.     int opStatus = 0;
  4.  
  5.     while((opStatus = mbedtls_ssl_handshake(&ssl)) != 0)
  6.     {
  7.       if(opStatus != MBEDTLS_ERR_SSL_WANT_READ && opStatus != MBEDTLS_ERR_SSL_WANT_WRITE)
  8.       {
  9.         mbedtls_printf("ERROR - mbedtls_ssl_handshake returned -0x%x\r\n \r\n ", opStatus);
  10.         return opStatus;
  11.       }
  12.     }
  13.  
  14.     return opStatus;
  15. }

Lista kroków zdefiniowana podczas procedury komunikacji wykonywana jest w funkcji mbedtls_ssl_handshake_client_step(mbedtls_ssl_context *ssl);

  1. switch( ssl->state )
  2. {
  3.     case MBEDTLS_SSL_HELLO_REQUEST:
  4.         ssl->state = MBEDTLS_SSL_CLIENT_HELLO;
  5.         break;
  6.     case MBEDTLS_SSL_CLIENT_HELLO:
  7.         ret = ssl_write_client_hello( ssl );
  8.         break;
  9.     case MBEDTLS_SSL_SERVER_HELLO:
  10.         ret = ssl_parse_server_hello( ssl );
  11.         break;
  12.     case MBEDTLS_SSL_SERVER_CERTIFICATE:
  13.         ret = mbedtls_ssl_parse_certificate( ssl );
  14.         break;
  15.     case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
  16.         ret = ssl_parse_server_key_exchange( ssl );
  17.         break;
  18.     case MBEDTLS_SSL_CERTIFICATE_REQUEST:
  19.         ret = ssl_parse_certificate_request( ssl );
  20.         break;
  21.     case MBEDTLS_SSL_SERVER_HELLO_DONE:
  22.         ret = ssl_parse_server_hello_done( ssl );
  23.         break;
  24.     case MBEDTLS_SSL_CLIENT_CERTIFICATE:
  25.         ret = mbedtls_ssl_write_certificate( ssl );
  26.         break;
  27.     case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
  28.         ret = ssl_write_client_key_exchange( ssl );
  29.         break;
  30.     case MBEDTLS_SSL_CERTIFICATE_VERIFY:
  31.         ret = ssl_write_certificate_verify( ssl );
  32.         break;
  33.     case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
  34.         ret = mbedtls_ssl_write_change_cipher_spec( ssl );
  35.         break;
  36.     case MBEDTLS_SSL_CLIENT_FINISHED:
  37.         ret = mbedtls_ssl_write_finished( ssl );
  38.         break;
  39.     #if defined(MBEDTLS_SSL_SESSION_TICKETS)
  40.     case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET:
  41.         ret = ssl_parse_new_session_ticket( ssl );
  42.         break;
  43.     #endif
  44.     case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
  45.         ret = mbedtls_ssl_parse_change_cipher_spec( ssl );
  46.         break;
  47.     case MBEDTLS_SSL_SERVER_FINISHED:
  48.         ret = mbedtls_ssl_parse_finished( ssl );
  49.         break;
  50.     case MBEDTLS_SSL_FLUSH_BUFFERS:
  51.         ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP;
  52.         break;
  53.     case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
  54.         mbedtls_ssl_handshake_wrapup( ssl );
  55.         break;
  56.     default:
  57.         MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
  58.         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
  59. }

Po poprawnym wykonaniu połączeniu następuje wysłanie testowej wiadomości do serwera.

  1. static int SendTestMsg(void)
  2. {
  3.     int opStatus = 0;
  4.     int msgLenToSend = 0;
  5.  
  6.     //buf is global buffer
  7.     msgLenToSend = sprintf((char*)buf, "testmsg,123,76\r");
  8.  
  9.     while((opStatus = mbedtls_ssl_write(&ssl, buf, msgLenToSend)) <= 0)
  10.     {
  11.       if(opStatus != MBEDTLS_ERR_SSL_WANT_READ && opStatus != MBEDTLS_ERR_SSL_WANT_WRITE)
  12.       {
  13.         mbedtls_printf("ERROR - mbedtls_ssl_write returned %d\n\n", opStatus);
  14.         return -1;
  15.       }
  16.     }
  17.     return msgLenToSend;
  18. }

Kolejnym elementem jest odbieranie i wysyłanie danych:

  1. mbedtls_printf("\r\n Read/write data from/to server:\r\n ");
  2. fflush( stdout);
  3.  
  4. do {
  5.     if(ReadWriteData() < 0) { break; }
  6. } while(1);
  7.  
  8. static int ReadWriteData(void)
  9. {
  10.     int msgLen = 0;
  11.     int opStatus = 0;
  12.  
  13.     msgLen = sizeof(buf) - 1;
  14.     memset(buf, 0, sizeof(buf));
  15.  
  16.     opStatus = mbedtls_ssl_read(&ssl, buf, msgLen);
  17.  
  18.     if(opStatus == MBEDTLS_ERR_SSL_WANT_READ || opStatus == MBEDTLS_ERR_SSL_WANT_WRITE) {
  19.         mbedtls_printf("write/read ok");
  20.         fflush( stdout);
  21.     }
  22.     if(opStatus == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
  23.         return -1;
  24.     }
  25.  
  26.     if(opStatus < 0) {
  27.       mbedtls_printf("ERROR - mbedtls_ssl_read returned %d\r\n \r\n ", opStatus);
  28.       return -1;
  29.     }
  30.  
  31.     if(opStatus == 0) {
  32.       mbedtls_printf("ret == 0 return %d\r\n \r\n ", opStatus);
  33.       return -1;
  34.     }
  35.  
  36.     if(opStatus > 0) {
  37.         msgLen = opStatus;
  38.         mbedtls_printf(" %d bytes read\n\n %s", msgLen, (char*)buf);
  39.         fflush( stdout);    //Bez fflush wysyla z bufora wczesniej odebrana wiadomosc.
  40.  
  41.         if(msgLen > 0) {
  42.             while((opStatus = mbedtls_ssl_write(&ssl, buf, msgLen)) <= 0)
  43.             {
  44.                 if(opStatus != MBEDTLS_ERR_SSL_WANT_READ && opStatus != MBEDTLS_ERR_SSL_WANT_WRITE)
  45.                 {
  46.                   mbedtls_printf("ERROR - mbedtls_ssl_write returned %d\r\n \r\n ", opStatus);
  47.                 }
  48.             }
  49.         }
  50.     }
  51.  
  52.     return 0;
  53. }

W celu poprawnego otrzymywania danych wysyłanych na UART podczas procedury wykonywania połączenia  oraz sprawdzania otrzymywanych informacji należy zastosować funkcję fflush. Jest ona konieczna ponieważ wiadomości przesyłane przez mbedtls_printf korzysta z funkcji printf. FFLUSH pozwala na opróżnienie bufora z danymi gromadzonymi przez funkcję printf.

Dodatkowo w celu ograniczenia zużycia pamięci oraz przyśpieszenia działania programu, jeśli będzie to konieczne, należy zastąpić funkcję printf własnoręcznie przygotowaną funkcją działającą bezpośrednio na interfejsie UART.

Cała funkcja nawiązująca połączenie po SSL wygląda następująco:

  1. void StartSSLClientTask(void const *argument)
  2. {
  3.     int ret = 1;
  4.  
  5.     #if defined(MBEDTLS_DEBUG_C)
  6.     mbedtls_debug_set_threshold(DEBUG_LEVEL);
  7.     #endif
  8.  
  9.     Initialize_SessionData();
  10.     ret = Drbg_Seed();
  11.  
  12.     if(ret != 0) {
  13.         mbedtls_printf("ERROR\r\n");
  14.         goto exit;
  15.     }
  16.  
  17.     ret = InitializeCertificate();
  18.     if(ret != 0) {
  19.         mbedtls_printf("ERROR\r\n");
  20.         goto exit;
  21.     }
  22.  
  23.     ValidateIpAddress();
  24.  
  25.   while(1)
  26.   {
  27.     /* Start the connection  */
  28.     mbedtls_printf("  . Connecting to tcp/%s/%s...\r\n ", SERVER_NAME, SERVER_PORT);
  29.     fflush( stdout);
  30.  
  31.     ConnectToServerTcp();
  32.  
  33.     mbedtls_printf("  . Setting up the SSL/TLS structure...\r\n ");
  34.     fflush( stdout);
  35.  
  36.     if(LoadDefaultConfiguration() != 0) { goto exit; }
  37.     if(ConnectionSSL_Configuration() != 0) { goto exit; }
  38.     if(SetHostname_BioCallbacks() != 0) { goto exit; }
  39.     SetHostname_BioCallbacks();
  40.  
  41.     if(Handshake() != 0) { goto exit; }
  42.  
  43.     VarifyCertificate();
  44.  
  45.     mbedtls_printf("\r\n Write data to server:\r\n ");
  46.     fflush( stdout);
  47.  
  48.     if(SendTestMsg() < 0) { goto exit; }
  49.  
  50.     mbedtls_printf("\r\n Read/write data from/to server:\r\n ");
  51.     fflush( stdout);
  52.  
  53.     do {
  54.         if(ReadWriteData() < 0) { break; }
  55.     } while(1);
  56.  
  57.     /* Close session */
  58.     do {
  59.       mbedtls_ssl_close_notify(&ssl);
  60.     } while(ret == MBEDTLS_ERR_SSL_WANT_WRITE);
  61.  
  62.     ret = mbedtls_ssl_session_reset(&ssl);
  63.     if(ret != 0)
  64.     {
  65.       mbedtls_printf("ERROR - mbedtls_ssl_session_reset returned %d\r\n \r\n ", ret);
  66.       break;
  67.     }
  68.  
  69.     mbedtls_net_free(&server_fd);
  70.     mbedtls_printf("xPortGetFreeHeapSize: %d\r\n \r\n ", xPortGetFreeHeapSize());
  71.     osDelay(5000);
  72.   }
  73.  
  74.   exit:
  75.   mbedtls_printf("ERROR on mbedtls...\r\n \r\n ");
  76.  
  77.   ClearData();
  78.  
  79. #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
  80.   mbedtls_memory_buffer_alloc_free();
  81. #endif
  82.  
  83.   vTaskDelete(NULL);
  84. }

Program będzie generował błąd x509_verify_cert() -0x2700. Po ustawieniu flag debugowania na 4 okaże się, że błąd wynika bezpośrednio w funkcji:

  1. int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt,
  2.                      mbedtls_x509_crt *trust_ca,
  3.                      mbedtls_x509_crl *ca_crl,
  4.                      const mbedtls_x509_crt_profile *profile,
  5.                      const char *cn, uint32_t *flags,
  6.                      int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
  7.                      void *p_vrfy,
  8.                      mbedtls_x509_crt_restart_ctx *rs_ctx )
  9. {
  10.     int ret;
  11.     mbedtls_pk_type_t pk_type;
  12.     mbedtls_x509_crt_verify_chain ver_chain;
  13.     uint32_t ee_flags;
  14.  
  15.     *flags = 0;
  16.     ee_flags = 0;
  17.     x509_crt_verify_chain_reset( &ver_chain );
  18.  
  19.     if( profile == NULL )
  20.     {
  21.         ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
  22.         goto exit;
  23.     }
  24.  
  25.     /* check name if requested */
  26.     if( cn != NULL )
  27.         x509_crt_verify_name( crt, cn, &ee_flags );
  28.  
  29.     /* Check the type and size of the key */
  30.     pk_type = mbedtls_pk_get_type( &crt->pk );
  31.  
  32.     if( x509_profile_check_pk_alg( profile, pk_type ) != 0 )
  33.         ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
  34.  
  35.     if( x509_profile_check_key( profile, &crt->pk ) != 0 )
  36.         ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
  37.  
  38.     /* Check the chain */
  39.     ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile,
  40.                                  &ver_chain, rs_ctx );
  41.  
  42.     if( ret != 0 )
  43.         goto exit;
  44.  
  45.     /* Merge end-entity flags */
  46.     ver_chain.items[0].flags |= ee_flags;
  47.  
  48.     /* Build final flags, calling callback on the way if any */
  49.     ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy );
  50.  
  51. exit:
  52. #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
  53.     if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
  54.         mbedtls_x509_crt_restart_free( rs_ctx );
  55. #endif
  56.  
  57.     /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
  58.      * the SSL module for authmode optional, but non-zero return from the
  59.      * callback means a fatal error so it shouldn't be ignored */
  60.     if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED )
  61.         ret = MBEDTLS_ERR_X509_FATAL_ERROR;
  62.  
  63.     if( ret != 0 )
  64.     {
  65.         *flags = (uint32_t) -1;
  66.         return( ret );
  67.     }
  68.  
  69.     if( *flags != 0 )
  70.         return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED );
  71.  
  72.     return( 0 );
  73. }

Przedostatnia instrukcja warunkowa ustawia wartość zmiennej flags na 8. Oznacza ona, że certyfikat nie jest podpisany przez odpowiednie instytucje. Jest to całkowicie normalny błąd w przypadku korzystania z własnoręcznie wygenerowanych certyfikatów.

Po wysłaniu czasem jednego czasem kilku pakietów pojawia się błąd:

../Middlewares/Third_Party/mbedTLS/library/ssl_tls.c:1794: => decrypt buf
../Middlewares/Third_Party/mbedTLS/library/ssl_tls.c:4256: ssl_decrypt_buf() returned -29056 (-0x7180)

Może on oczywiście wynikać z kilku czynników. W moim przypadku wynikał on z ustawienia za małego bufora RX. Zmiana parametru ETH_RX_BUFFER_SIZE na 2144 rozwiązała problem.

Pełny projekt wraz z certyfikatami można pobrać z dysku Google pod tym linkiem.