233 lines
7.3 KiB
C
233 lines
7.3 KiB
C
#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 <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#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;
|
|
} |