diff --git a/CMakeLists.txt b/CMakeLists.txt index 097f17b..dc3b759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.10) -project("MbedTLS Integration Example") +project("MbedTLS Integration Examples") add_subdirectory(mbedtls) -add_subdirectory(httpbin/c) -add_subdirectory(wikipedia/c) \ No newline at end of file +add_subdirectory(httpbin) +add_subdirectory(wikipedia) +add_subdirectory(iconfinder) \ No newline at end of file diff --git a/README.md b/README.md index 86028b7..c07de07 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Uses Mbed TLS 4.0 Public APIs: - [httpbin](https://httpbin.org/) - [Wikipedia](https://en.wikipedia.org/) - +- [Iconfinder](https://docs.freepik.com/introduction) ## Build Steps 1. **Clone the repository:** ```bash - git clone https://git.kolibrios.org/DIlkhush00/Mbed-TLS-Integration-Examples.git + git clone --recursive https://git.kolibrios.org/DIlkhush00/Mbed-TLS-Integration-Examples.git ``` 2. **Build:** ```bash diff --git a/httpbin/c/CMakeLists.txt b/httpbin/CMakeLists.txt similarity index 100% rename from httpbin/c/CMakeLists.txt rename to httpbin/CMakeLists.txt diff --git a/httpbin/c/main.c b/httpbin/main.c similarity index 100% rename from httpbin/c/main.c rename to httpbin/main.c diff --git a/iconfinder/CMakeLists.txt b/iconfinder/CMakeLists.txt new file mode 100644 index 0000000..765d0e6 --- /dev/null +++ b/iconfinder/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(iconfinder_c main.c) + +target_link_libraries(iconfinder_c + PRIVATE + mbedtls +) + +target_include_directories(iconfinder_c + PRIVATE + ${MBEDTLS_SOURCE_DIR}/include +) diff --git a/iconfinder/main.c b/iconfinder/main.c new file mode 100644 index 0000000..91da47f --- /dev/null +++ b/iconfinder/main.c @@ -0,0 +1,233 @@ +#include "mbedtls/platform.h" +#include "mbedtls/build_info.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/ssl.h" +#include "mbedtls/debug.h" +#include "mbedtls/error.h" +#include "mbedtls/x509_crt.h" + +#include +#include +#include + +#define SERVER_PORT "443" +#define SERVER_NAME "api.freepik.com" +#define GET_REQUEST "GET /v1/icons?order=relevance&term=cat HTTP/1.1\r\n" \ + "x-freepik-api-key: YOUR_API_KEY_HERE\r\n" \ + "Host: api.freepik.com\r\n" \ + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36\r\n" \ + "Accept: application/json\r\n" \ + "Accept-Language: en-US,en;q=0.9\r\n" \ + "Accept-Encoding: identity\r\n" \ + "Connection: close\r\n\r\n" + +#define DEBUG_LEVEL 0 +#define CA_CERT_PATH "/etc/ssl/certs/ca-certificates.crt" // most distros use this path for CA certs, adjust if needed + +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); +} + +int main(void) { + int ret; + ssize_t bytes_read; + unsigned char buf[1024]; + + mbedtls_net_context server_fd; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt cacert; + + mbedtls_printf("Initializing TLS structures..."); + fflush(stdout); + + mbedtls_net_init(&server_fd); + mbedtls_ssl_init(&ssl); + mbedtls_ssl_config_init(&conf); + mbedtls_x509_crt_init(&cacert); + + mbedtls_printf(" ok\n"); + + mbedtls_printf("Initializing PSA Crypto..."); + fflush(stdout); + + psa_status_t psa_status = psa_crypto_init(); + if (psa_status != PSA_SUCCESS) { + mbedtls_printf(" failed\n ! psa_crypto_init failed: %d\n\n", (int)psa_status); + ret = -1; + goto exit; + } + + mbedtls_printf(" ok\n"); + + mbedtls_printf("Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT); + fflush(stdout); + + if ((ret = mbedtls_net_connect(&server_fd, SERVER_NAME, + SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) { + mbedtls_printf(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret); + goto exit; + } + + if ((ret = mbedtls_net_set_block(&server_fd)) != 0) { + mbedtls_printf(" failed\n ! mbedtls_net_set_block returned %d\n\n", ret); + goto exit; + } + + mbedtls_printf(" ok\n"); + + mbedtls_printf("Configuring SSL/TLS..."); + fflush(stdout); + + if ((ret = mbedtls_ssl_config_defaults(&conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret); + goto exit; + } + + mbedtls_printf("Loading CA certificate from %s...", CA_CERT_PATH); + fflush(stdout); + + ret = mbedtls_x509_crt_parse_file(&cacert, CA_CERT_PATH); + if (ret != 0) { + mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse_file returned -0x%x\n", -ret); + goto exit; + } + mbedtls_printf(" ok\n"); + + mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); + mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + + // mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE); // no good for prod + + mbedtls_debug_set_threshold(DEBUG_LEVEL); + mbedtls_ssl_conf_dbg(&conf, my_debug, stdout); + + mbedtls_printf(" ok\n"); + + mbedtls_printf("Setting up SSL context..."); + fflush(stdout); + + if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { + mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret); + goto exit; + } + + // Sets SNI (important for servers hosting multiple domains on the same IP) + if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) { + mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); + goto exit; + } + + mbedtls_printf(" ok\n"); + + mbedtls_printf("Binding socket to TLS..."); + fflush(stdout); + + mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + mbedtls_printf(" ok\n"); + + mbedtls_printf("Performing TLS handshake..."); + fflush(stdout); + + while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret); + goto exit; + } + } + + mbedtls_printf(" ok\n"); + mbedtls_printf("TLS version: %s\n", mbedtls_ssl_get_version(&ssl)); + mbedtls_printf("Cipher: %s\n\n", mbedtls_ssl_get_ciphersuite(&ssl)); + + + mbedtls_printf("Sending HTTP request..."); + fflush(stdout); + + size_t request_len = strlen(GET_REQUEST); + if ((ret = mbedtls_ssl_write(&ssl, (const unsigned char*)GET_REQUEST, request_len)) < 0) { + mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); + goto exit; + } + + mbedtls_printf(" ok (%d bytes)\n", ret); + + mbedtls_printf("Receiving response:\n\n"); + + int res_recv = 0; + int retry = 0; + int delay = 100; // milli seconds + int msg = 0; + + while (1) { + bytes_read = mbedtls_ssl_read(&ssl, buf, sizeof(buf) - 1); + + if (bytes_read > 0) { + buf[bytes_read] = '\0'; + mbedtls_printf("%s", (char *)buf); + res_recv = 1; + retry = 0; + delay = 100; + } else if (bytes_read == 0) { + break; + } else if (bytes_read == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) { + // TLS 1.3 post-handshake message - it's pretty common so you can skip and continue + msg++; + if (msg < 10) { + usleep(100000); + continue; + } else { + mbedtls_printf("\n ! Too many post-handshake messages, giving up\n"); + break; + } + } else if (bytes_read == MBEDTLS_ERR_SSL_WANT_READ || bytes_read == MBEDTLS_ERR_SSL_WANT_WRITE) { + // try again... don't give up! + if (retry < 100) { + usleep(delay * 1000); // milli to micro + retry++; + if (delay < 5000) + delay *= 2; + continue; + } else { + mbedtls_printf("\n ! SSL_WANT_READ timeout after %d retries\n", retry); + break; + } + } else { + // an actual error + unsigned char error_buffer[256]; + mbedtls_strerror(bytes_read, (char *)error_buffer, sizeof(error_buffer)); + mbedtls_printf("\n ! mbedtls_ssl_read error (%d): %s\n", (int)bytes_read, error_buffer); + break; + } + } + + if (res_recv) { + mbedtls_printf("\n\nConnection closed by server, all data received successfully.\n"); + } else { + mbedtls_printf("\n\nNo data received from server.\n"); + } + + + +exit: + mbedtls_printf("\n\nClosing TLS connection..."); + fflush(stdout); + + mbedtls_ssl_close_notify(&ssl); + mbedtls_net_free(&server_fd); + mbedtls_ssl_free(&ssl); + mbedtls_ssl_config_free(&conf); + mbedtls_x509_crt_free(&cacert); + + mbedtls_printf(" ok\n\n"); + + return ret; +} \ No newline at end of file diff --git a/wikipedia/c/CMakeLists.txt b/wikipedia/CMakeLists.txt similarity index 100% rename from wikipedia/c/CMakeLists.txt rename to wikipedia/CMakeLists.txt diff --git a/wikipedia/c/main.c b/wikipedia/main.c similarity index 100% rename from wikipedia/c/main.c rename to wikipedia/main.c