diff --git a/README.md b/README.md index ccab566..235ff40 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ App|Description [picow_tcp_client](pico_w/wifi/tcp_client) | A simple TCP client. You can run [python_test_tcp_server.py](pico_w/wifi/python_test_tcp/python_test_tcp_server.py) for it to connect to. [picow_tcp_server](pico_w/wifi/tcp_server) | A simple TCP server. You can use [python_test_tcp_client.py](pico_w//wifi/python_test_tcp/python_test_tcp_client.py) to connect to it. [picow_tls_client](pico_w/wifi/tls_client) | Demonstrates how to make a HTTPS request using TLS. +[picow_tls_verify](pico_w/wifi/tls_client) | Demonstrates how to make a HTTPS request using TLS with certificate verification. [picow_wifi_scan](pico_w/wifi/wifi_scan) | Scans for WiFi networks and prints the results. [picow_udp_beacon](pico_w/wifi/udp_beacon) | A simple UDP transmitter. diff --git a/pico_w/wifi/tls_client/CMakeLists.txt b/pico_w/wifi/tls_client/CMakeLists.txt index 3ec9e68..166a986 100644 --- a/pico_w/wifi/tls_client/CMakeLists.txt +++ b/pico_w/wifi/tls_client/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(picow_tls_client_background picow_tls_client.c + tls_common.c ) target_compile_definitions(picow_tls_client_background PRIVATE WIFI_SSID=\"${WIFI_SSID}\" @@ -19,6 +20,7 @@ pico_add_extra_outputs(picow_tls_client_background) add_executable(picow_tls_client_poll picow_tls_client.c + tls_common.c ) target_compile_definitions(picow_tls_client_poll PRIVATE WIFI_SSID=\"${WIFI_SSID}\" @@ -36,6 +38,30 @@ target_link_libraries(picow_tls_client_poll ) pico_add_extra_outputs(picow_tls_client_poll) +# This version verifies the tls connection with a certificate +add_executable(picow_tls_verify_background + tls_verify.c + tls_common.c + ) +target_compile_definitions(picow_tls_verify_background PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" + # By default verification is optional (MBEDTLS_SSL_VERIFY_OPTIONAL) + # Make it required for this test + ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED + ) +target_include_directories(picow_tls_verify_background PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts + ) +target_link_libraries(picow_tls_verify_background + pico_cyw43_arch_lwip_threadsafe_background + pico_lwip_mbedtls + pico_mbedtls + pico_stdlib + ) +pico_add_extra_outputs(picow_tls_verify_background) + # Ignore warnings from lwip code set_source_files_properties( ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c diff --git a/pico_w/wifi/tls_client/mbedtls_config.h b/pico_w/wifi/tls_client/mbedtls_config.h index dae3395..0ceab1a 100644 --- a/pico_w/wifi/tls_client/mbedtls_config.h +++ b/pico_w/wifi/tls_client/mbedtls_config.h @@ -61,3 +61,6 @@ #define MBEDTLS_ECDSA_C #define MBEDTLS_ASN1_WRITE_C +// The following is needed to parse a certificate +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_BASE64_C diff --git a/pico_w/wifi/tls_client/picow_tls_client.c b/pico_w/wifi/tls_client/picow_tls_client.c index d1576e6..9a375b1 100644 --- a/pico_w/wifi/tls_client/picow_tls_client.c +++ b/pico_w/wifi/tls_client/picow_tls_client.c @@ -4,15 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include - #include "pico/stdlib.h" #include "pico/cyw43_arch.h" -#include "lwip/pbuf.h" -#include "lwip/altcp_tcp.h" -#include "lwip/altcp_tls.h" -#include "lwip/dns.h" #define TLS_CLIENT_SERVER "worldtimeapi.org" #define TLS_CLIENT_HTTP_REQUEST "GET /api/ip HTTP/1.1\r\n" \ @@ -21,204 +14,7 @@ "\r\n" #define TLS_CLIENT_TIMEOUT_SECS 15 - -typedef struct TLS_CLIENT_T_ { - struct altcp_pcb *pcb; - bool complete; -} TLS_CLIENT_T; - -static struct altcp_tls_config *tls_config = NULL; - -static err_t tls_client_close(void *arg) { - TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; - err_t err = ERR_OK; - - state->complete = true; - if (state->pcb != NULL) { - altcp_arg(state->pcb, NULL); - altcp_poll(state->pcb, NULL, 0); - altcp_recv(state->pcb, NULL); - altcp_err(state->pcb, NULL); - err = altcp_close(state->pcb); - if (err != ERR_OK) { - printf("close failed %d, calling abort\n", err); - altcp_abort(state->pcb); - err = ERR_ABRT; - } - state->pcb = NULL; - } - return err; -} - -static err_t tls_client_connected(void *arg, struct altcp_pcb *pcb, err_t err) { - TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; - if (err != ERR_OK) { - printf("connect failed %d\n", err); - return tls_client_close(state); - } - - printf("connected to server, sending request\n"); - err = altcp_write(state->pcb, TLS_CLIENT_HTTP_REQUEST, strlen(TLS_CLIENT_HTTP_REQUEST), TCP_WRITE_FLAG_COPY); - if (err != ERR_OK) { - printf("error writing data, err=%d", err); - return tls_client_close(state); - } - - return ERR_OK; -} - -static err_t tls_client_poll(void *arg, struct altcp_pcb *pcb) { - printf("timed out"); - return tls_client_close(arg); -} - -static void tls_client_err(void *arg, err_t err) { - TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; - printf("tls_client_err %d\n", err); - state->pcb = NULL; /* pcb freed by lwip when _err function is called */ -} - -static err_t tls_client_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err) { - TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; - if (!p) { - printf("connection closed\n"); - return tls_client_close(state); - } - - if (p->tot_len > 0) { - /* For simplicity this examples creates a buffer on stack the size of the data pending here, - and copies all the data to it in one go. - Do be aware that the amount of data can potentially be a bit large (TLS record size can be 16 KB), - so you may want to use a smaller fixed size buffer and copy the data to it using a loop, if memory is a concern */ - char buf[p->tot_len + 1]; - - pbuf_copy_partial(p, buf, p->tot_len, 0); - buf[p->tot_len] = 0; - - printf("***\nnew data received from server:\n***\n\n%s\n", buf); - - altcp_recved(pcb, p->tot_len); - } - pbuf_free(p); - - return ERR_OK; -} - -static void tls_client_connect_to_server_ip(const ip_addr_t *ipaddr, TLS_CLIENT_T *state) -{ - err_t err; - u16_t port = 443; - - printf("connecting to server IP %s port %d\n", ipaddr_ntoa(ipaddr), port); - err = altcp_connect(state->pcb, ipaddr, port, tls_client_connected); - if (err != ERR_OK) - { - fprintf(stderr, "error initiating connect, err=%d\n", err); - tls_client_close(state); - } -} - -static void tls_client_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg) -{ - if (ipaddr) - { - printf("DNS resolving complete\n"); - tls_client_connect_to_server_ip(ipaddr, (TLS_CLIENT_T *) arg); - } - else - { - printf("error resolving hostname %s\n", hostname); - tls_client_close(arg); - } -} - - -static bool tls_client_open(const char *hostname, void *arg) { - err_t err; - ip_addr_t server_ip; - TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; - - state->pcb = altcp_tls_new(tls_config, IPADDR_TYPE_ANY); - if (!state->pcb) { - printf("failed to create pcb\n"); - return false; - } - - altcp_arg(state->pcb, state); - altcp_poll(state->pcb, tls_client_poll, TLS_CLIENT_TIMEOUT_SECS * 2); - altcp_recv(state->pcb, tls_client_recv); - altcp_err(state->pcb, tls_client_err); - - /* Set SNI */ - mbedtls_ssl_set_hostname(altcp_tls_context(state->pcb), hostname); - - printf("resolving %s\n", hostname); - - // cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking. - // You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll - // these calls are a no-op and can be omitted, but it is a good practice to use them in - // case you switch the cyw43_arch type later. - cyw43_arch_lwip_begin(); - - err = dns_gethostbyname(hostname, &server_ip, tls_client_dns_found, state); - if (err == ERR_OK) - { - /* host is in DNS cache */ - tls_client_connect_to_server_ip(&server_ip, state); - } - else if (err != ERR_INPROGRESS) - { - printf("error initiating DNS resolving, err=%d\n", err); - tls_client_close(state->pcb); - } - - cyw43_arch_lwip_end(); - - return err == ERR_OK || err == ERR_INPROGRESS; -} - -// Perform initialisation -static TLS_CLIENT_T* tls_client_init(void) { - TLS_CLIENT_T *state = calloc(1, sizeof(TLS_CLIENT_T)); - if (!state) { - printf("failed to allocate state\n"); - return NULL; - } - - return state; -} - -void run_tls_client_test(void) { - /* No CA certificate checking */ - tls_config = altcp_tls_create_config_client(NULL, 0); - - TLS_CLIENT_T *state = tls_client_init(); - if (!state) { - return; - } - if (!tls_client_open(TLS_CLIENT_SERVER, state)) { - return; - } - while(!state->complete) { - // the following #ifdef is only here so this same example can be used in multiple modes; - // you do not need it in your code -#if PICO_CYW43_ARCH_POLL - // if you are using pico_cyw43_arch_poll, then you must poll periodically from your - // main loop (not from a timer) to check for Wi-Fi driver or lwIP work that needs to be done. - cyw43_arch_poll(); - // you can poll as often as you like, however if you have nothing else to do you can - // choose to sleep until either a specified time, or cyw43_arch_poll() has work to do: - cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); -#else - // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work - // is done via interrupt in the background. This sleep is just an example of some (blocking) - // work you might be doing. - sleep_ms(1000); -#endif - } - free(state); - altcp_tls_free_config(tls_config); -} +extern bool run_tls_client_test(const uint8_t *cert, size_t cert_len, const char *server, const char *request, int timeout); int main() { stdio_init_all(); @@ -233,12 +29,17 @@ int main() { printf("failed to connect\n"); return 1; } - run_tls_client_test(); - + bool pass = run_tls_client_test(NULL, 0, TLS_CLIENT_SERVER, TLS_CLIENT_HTTP_REQUEST, TLS_CLIENT_TIMEOUT_SECS); + if (pass) { + printf("Test passed\n"); + } else { + printf("Test failed\n"); + } /* sleep a bit to let usb stdio write out any buffer to host */ sleep_ms(100); cyw43_arch_deinit(); - return 0; + printf("All done\n"); + return pass ? 0 : 1; } diff --git a/pico_w/wifi/tls_client/tls_common.c b/pico_w/wifi/tls_client/tls_common.c new file mode 100644 index 0000000..454e24e --- /dev/null +++ b/pico_w/wifi/tls_client/tls_common.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include "lwip/pbuf.h" +#include "lwip/altcp_tcp.h" +#include "lwip/altcp_tls.h" +#include "lwip/dns.h" + +typedef struct TLS_CLIENT_T_ { + struct altcp_pcb *pcb; + bool complete; + int error; + const char *http_request; + int timeout; +} TLS_CLIENT_T; + +static struct altcp_tls_config *tls_config = NULL; + +static err_t tls_client_close(void *arg) { + TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; + err_t err = ERR_OK; + + state->complete = true; + if (state->pcb != NULL) { + altcp_arg(state->pcb, NULL); + altcp_poll(state->pcb, NULL, 0); + altcp_recv(state->pcb, NULL); + altcp_err(state->pcb, NULL); + err = altcp_close(state->pcb); + if (err != ERR_OK) { + printf("close failed %d, calling abort\n", err); + altcp_abort(state->pcb); + err = ERR_ABRT; + } + state->pcb = NULL; + } + return err; +} + +static err_t tls_client_connected(void *arg, struct altcp_pcb *pcb, err_t err) { + TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; + if (err != ERR_OK) { + printf("connect failed %d\n", err); + return tls_client_close(state); + } + + printf("connected to server, sending request\n"); + err = altcp_write(state->pcb, state->http_request, strlen(state->http_request), TCP_WRITE_FLAG_COPY); + if (err != ERR_OK) { + printf("error writing data, err=%d", err); + return tls_client_close(state); + } + + return ERR_OK; +} + +static err_t tls_client_poll(void *arg, struct altcp_pcb *pcb) { + TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; + printf("timed out\n"); + state->error = PICO_ERROR_TIMEOUT; + return tls_client_close(arg); +} + +static void tls_client_err(void *arg, err_t err) { + TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; + printf("tls_client_err %d\n", err); + tls_client_close(state); + state->error = PICO_ERROR_GENERIC; +} + +static err_t tls_client_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err) { + TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; + if (!p) { + printf("connection closed\n"); + return tls_client_close(state); + } + + if (p->tot_len > 0) { + /* For simplicity this examples creates a buffer on stack the size of the data pending here, + and copies all the data to it in one go. + Do be aware that the amount of data can potentially be a bit large (TLS record size can be 16 KB), + so you may want to use a smaller fixed size buffer and copy the data to it using a loop, if memory is a concern */ + char buf[p->tot_len + 1]; + + pbuf_copy_partial(p, buf, p->tot_len, 0); + buf[p->tot_len] = 0; + + printf("***\nnew data received from server:\n***\n\n%s\n", buf); + + altcp_recved(pcb, p->tot_len); + } + pbuf_free(p); + + return ERR_OK; +} + +static void tls_client_connect_to_server_ip(const ip_addr_t *ipaddr, TLS_CLIENT_T *state) +{ + err_t err; + u16_t port = 443; + + printf("connecting to server IP %s port %d\n", ipaddr_ntoa(ipaddr), port); + err = altcp_connect(state->pcb, ipaddr, port, tls_client_connected); + if (err != ERR_OK) + { + fprintf(stderr, "error initiating connect, err=%d\n", err); + tls_client_close(state); + } +} + +static void tls_client_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg) +{ + if (ipaddr) + { + printf("DNS resolving complete\n"); + tls_client_connect_to_server_ip(ipaddr, (TLS_CLIENT_T *) arg); + } + else + { + printf("error resolving hostname %s\n", hostname); + tls_client_close(arg); + } +} + + +static bool tls_client_open(const char *hostname, void *arg) { + err_t err; + ip_addr_t server_ip; + TLS_CLIENT_T *state = (TLS_CLIENT_T*)arg; + + state->pcb = altcp_tls_new(tls_config, IPADDR_TYPE_ANY); + if (!state->pcb) { + printf("failed to create pcb\n"); + return false; + } + + altcp_arg(state->pcb, state); + altcp_poll(state->pcb, tls_client_poll, state->timeout * 2); + altcp_recv(state->pcb, tls_client_recv); + altcp_err(state->pcb, tls_client_err); + + /* Set SNI */ + mbedtls_ssl_set_hostname(altcp_tls_context(state->pcb), hostname); + + printf("resolving %s\n", hostname); + + // cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking. + // You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll + // these calls are a no-op and can be omitted, but it is a good practice to use them in + // case you switch the cyw43_arch type later. + cyw43_arch_lwip_begin(); + + err = dns_gethostbyname(hostname, &server_ip, tls_client_dns_found, state); + if (err == ERR_OK) + { + /* host is in DNS cache */ + tls_client_connect_to_server_ip(&server_ip, state); + } + else if (err != ERR_INPROGRESS) + { + printf("error initiating DNS resolving, err=%d\n", err); + tls_client_close(state->pcb); + } + + cyw43_arch_lwip_end(); + + return err == ERR_OK || err == ERR_INPROGRESS; +} + +// Perform initialisation +static TLS_CLIENT_T* tls_client_init(void) { + TLS_CLIENT_T *state = calloc(1, sizeof(TLS_CLIENT_T)); + if (!state) { + printf("failed to allocate state\n"); + return NULL; + } + + return state; +} + +bool run_tls_client_test(const uint8_t *cert, size_t cert_len, const char *server, const char *request, int timeout) { + + /* No CA certificate checking */ + tls_config = altcp_tls_create_config_client(cert, cert_len); + assert(tls_config); + + //mbedtls_ssl_conf_authmode(&tls_config->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + + TLS_CLIENT_T *state = tls_client_init(); + if (!state) { + return false; + } + state->http_request = request; + state->timeout = timeout; + if (!tls_client_open(server, state)) { + return false; + } + while(!state->complete) { + // the following #ifdef is only here so this same example can be used in multiple modes; + // you do not need it in your code +#if PICO_CYW43_ARCH_POLL + // if you are using pico_cyw43_arch_poll, then you must poll periodically from your + // main loop (not from a timer) to check for Wi-Fi driver or lwIP work that needs to be done. + cyw43_arch_poll(); + // you can poll as often as you like, however if you have nothing else to do you can + // choose to sleep until either a specified time, or cyw43_arch_poll() has work to do: + cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); +#else + // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work + // is done via interrupt in the background. This sleep is just an example of some (blocking) + // work you might be doing. + sleep_ms(1000); +#endif + } + int err = state->error; + free(state); + altcp_tls_free_config(tls_config); + return err == 0; +} diff --git a/pico_w/wifi/tls_client/tls_verify.c b/pico_w/wifi/tls_client/tls_verify.c new file mode 100644 index 0000000..d8ea0ba --- /dev/null +++ b/pico_w/wifi/tls_client/tls_verify.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" + +// Using this url as we know the root cert won't change for a long time +#define TLS_CLIENT_SERVER "fw-download-alias1.raspberrypi.com" +#define TLS_CLIENT_HTTP_REQUEST "GET /net_install/boot.sig HTTP/1.1\r\n" \ + "Host: " TLS_CLIENT_SERVER "\r\n" \ + "Connection: close\r\n" \ + "\r\n" +#define TLS_CLIENT_TIMEOUT_SECS 15 + +// This is the PUBLIC root certificate exported from a browser +// Note that the newlines are needed +#define TLS_ROOT_CERT_OK "-----BEGIN CERTIFICATE-----\n\ +MIIC+jCCAn+gAwIBAgICEAAwCgYIKoZIzj0EAwIwgbcxCzAJBgNVBAYTAkdCMRAw\n\ +DgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQHDAlDYW1icmlkZ2UxHTAbBgNVBAoMFFJh\n\ +c3BiZXJyeSBQSSBMaW1pdGVkMRwwGgYDVQQLDBNSYXNwYmVycnkgUEkgRUNDIENB\n\ +MR0wGwYDVQQDDBRSYXNwYmVycnkgUEkgUm9vdCBDQTEmMCQGCSqGSIb3DQEJARYX\n\ +c3VwcG9ydEByYXNwYmVycnlwaS5jb20wIBcNMjExMjA5MTEzMjU1WhgPMjA3MTEx\n\ +MjcxMTMyNTVaMIGrMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEdMBsG\n\ +A1UECgwUUmFzcGJlcnJ5IFBJIExpbWl0ZWQxHDAaBgNVBAsME1Jhc3BiZXJyeSBQ\n\ +SSBFQ0MgQ0ExJTAjBgNVBAMMHFJhc3BiZXJyeSBQSSBJbnRlcm1lZGlhdGUgQ0Ex\n\ +JjAkBgkqhkiG9w0BCQEWF3N1cHBvcnRAcmFzcGJlcnJ5cGkuY29tMHYwEAYHKoZI\n\ +zj0CAQYFK4EEACIDYgAEcN9K6Cpv+od3w6yKOnec4EbyHCBzF+X2ldjorc0b2Pq0\n\ +N+ZvyFHkhFZSgk2qvemsVEWIoPz+K4JSCpgPstz1fEV6WzgjYKfYI71ghELl5TeC\n\ +byoPY+ee3VZwF1PTy0cco2YwZDAdBgNVHQ4EFgQUJ6YzIqFh4rhQEbmCnEbWmHEo\n\ +XAUwHwYDVR0jBBgwFoAUIIAVCSiDPXut23NK39LGIyAA7NAwEgYDVR0TAQH/BAgw\n\ +BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwIDaQAwZgIxAJYM+wIM\n\ +PC3wSPqJ1byJKA6D+ZyjKR1aORbiDQVEpDNWRKiQ5QapLg8wbcED0MrRKQIxAKUT\n\ +v8TJkb/8jC/oBVTmczKlPMkciN+uiaZSXahgYKyYhvKTatCTZb+geSIhc0w/2w==\n\ +-----END CERTIFICATE-----\n" + +// This is a test certificate +#define TLS_ROOT_CERT_BAD "-----BEGIN CERTIFICATE-----\n\ +MIIDezCCAwGgAwIBAgICEAEwCgYIKoZIzj0EAwIwgasxCzAJBgNVBAYTAkdCMRAw\n\ +DgYDVQQIDAdFbmdsYW5kMR0wGwYDVQQKDBRSYXNwYmVycnkgUEkgTGltaXRlZDEc\n\ +MBoGA1UECwwTUmFzcGJlcnJ5IFBJIEVDQyBDQTElMCMGA1UEAwwcUmFzcGJlcnJ5\n\ +IFBJIEludGVybWVkaWF0ZSBDQTEmMCQGCSqGSIb3DQEJARYXc3VwcG9ydEByYXNw\n\ +YmVycnlwaS5jb20wHhcNMjExMjA5MTMwMjIyWhcNNDYxMjAzMTMwMjIyWjA6MQsw\n\ +CQYDVQQGEwJHQjErMCkGA1UEAwwiZnctZG93bmxvYWQtYWxpYXMxLnJhc3BiZXJy\n\ +eXBpLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ6BQv8YtNiNv7ibLtt4\n\ +lwpgEr2XD4sOl9wu/l8GnGD5p39YK8jZV0j6HaTNkqi86Nly1H7YklzbxhFy5orM\n\ +356jggGDMIIBfzAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAzBglghkgB\n\ +hvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmljYXRlMB0G\n\ +A1UdDgQWBBRlONP3G2wTERZA9D+VxJABfiaCVTCB5QYDVR0jBIHdMIHagBQnpjMi\n\ +oWHiuFARuYKcRtaYcShcBaGBvaSBujCBtzELMAkGA1UEBhMCR0IxEDAOBgNVBAgM\n\ +B0VuZ2xhbmQxEjAQBgNVBAcMCUNhbWJyaWRnZTEdMBsGA1UECgwUUmFzcGJlcnJ5\n\ +IFBJIExpbWl0ZWQxHDAaBgNVBAsME1Jhc3BiZXJyeSBQSSBFQ0MgQ0ExHTAbBgNV\n\ +BAMMFFJhc3BiZXJyeSBQSSBSb290IENBMSYwJAYJKoZIhvcNAQkBFhdzdXBwb3J0\n\ +QHJhc3BiZXJyeXBpLmNvbYICEAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG\n\ +CCsGAQUFBwMBMAoGCCqGSM49BAMCA2gAMGUCMEHerJRT0WmG5tz4oVLSIxLbCizd\n\ +//SdJBCP+072zRUKs0mfl5EcO7dXWvBAb386PwIxAL7LrgpJroJYrYJtqeufJ3a9\n\ +zVi56JFnA3cNTcDYfIzyzy5wUskPAykdrRrCS534ig==\n\ +-----END CERTIFICATE-----\n" + +extern bool run_tls_client_test(const uint8_t *cert, size_t cert_len, const char *server, const char *request, int timeout); + +int main() { + stdio_init_all(); + + if (cyw43_arch_init()) { + printf("failed to initialise\n"); + return 1; + } + cyw43_arch_enable_sta_mode(); + + if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { + printf("failed to connect\n"); + return 1; + } + + // This should work + const uint8_t cert_ok[] = TLS_ROOT_CERT_OK; + bool pass1 = run_tls_client_test(cert_ok, sizeof(cert_ok), TLS_CLIENT_SERVER, TLS_CLIENT_HTTP_REQUEST, TLS_CLIENT_TIMEOUT_SECS); + if (pass1) { + printf("Test passed\n"); + } else { + printf("Test failed\n"); + } + + // Repeat the test with the wrong certificate. It should fail + const uint8_t cert_bad[] = TLS_ROOT_CERT_BAD; + bool pass2 = !run_tls_client_test(cert_bad, sizeof(cert_bad), TLS_CLIENT_SERVER, TLS_CLIENT_HTTP_REQUEST, TLS_CLIENT_TIMEOUT_SECS); + if (pass2) { + printf("Test passed\n"); + } else { + printf("Test failed\n"); + } + + /* sleep a bit to let usb stdio write out any buffer to host */ + sleep_ms(100); + + cyw43_arch_deinit(); + printf("All done\n"); + return (pass1 && pass2) ? 0 : 1; +} +