From 2ca4da96b08a94e9f5dc3f529016465dbc780aff Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 17 May 2023 18:38:34 +0100 Subject: [PATCH] Add HTTP client examples Examples to demonstrate HTTP, HTTPS and TLS validation Fixes #318 --- README.md | 4 + pico_w/wifi/CMakeLists.txt | 1 + pico_w/wifi/freertos/CMakeLists.txt | 1 + .../wifi/freertos/http_client/CMakeLists.txt | 49 ++++++ .../freertos/http_client/FreeRTOSConfig.h | 7 + pico_w/wifi/freertos/http_client/lwipopts.h | 36 +++++ .../freertos/http_client/mbedtls_config.h | 66 ++++++++ .../http_client/picow_freertos_http_client.c | 142 ++++++++++++++++++ pico_w/wifi/http_client/CMakeLists.txt | 45 ++++++ pico_w/wifi/http_client/lwipopts.h | 27 ++++ pico_w/wifi/http_client/mbedtls_config.h | 66 ++++++++ pico_w/wifi/http_client/picow_http_client.c | 59 ++++++++ pico_w/wifi/http_client/picow_http_verify.c | 98 ++++++++++++ 13 files changed, 601 insertions(+) create mode 100644 pico_w/wifi/freertos/http_client/CMakeLists.txt create mode 100644 pico_w/wifi/freertos/http_client/FreeRTOSConfig.h create mode 100644 pico_w/wifi/freertos/http_client/lwipopts.h create mode 100644 pico_w/wifi/freertos/http_client/mbedtls_config.h create mode 100644 pico_w/wifi/freertos/http_client/picow_freertos_http_client.c create mode 100644 pico_w/wifi/http_client/CMakeLists.txt create mode 100644 pico_w/wifi/http_client/lwipopts.h create mode 100644 pico_w/wifi/http_client/mbedtls_config.h create mode 100644 pico_w/wifi/http_client/picow_http_client.c create mode 100644 pico_w/wifi/http_client/picow_http_verify.c diff --git a/README.md b/README.md index 1b693554a..f017ee11e 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,8 @@ App|Description [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. +[picow_http_client](pico_w/wifi/http_client) | Demonstrates how to make http and https requests +[picow_http_client_verify](pico_w/wifi/http_client) | Demonstrates how to make a https request with server authentication #### FreeRTOS examples @@ -142,6 +144,8 @@ App|Description [picow_freertos_iperf_server_sys](pico_w/wifi/freertos/iperf) | Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The LED is blinked in another task [picow_freertos_ping_nosys](pico_w/wifi/freertos/ping) | Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=1 mode. [picow_freertos_ping_sys](pico_w/wifi/freertos/ping) | Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The test app uses the lwIP _socket_ API in this case. +[picow_freertos_http_client_nosys](pico_w/wifi/freertos/http_client) | Demonstrates how to make a https request in NO_SYS=1 mode +[picow_freertos_http_client_sys](pico_w/wifi/freertos/http_client) | Demonstrates how to make a https request in NO_SYS=0 (i.e. full FreeRTOS integration) ### Pico W Bluetooth diff --git a/pico_w/wifi/CMakeLists.txt b/pico_w/wifi/CMakeLists.txt index 8288eb7aa..3794901e0 100644 --- a/pico_w/wifi/CMakeLists.txt +++ b/pico_w/wifi/CMakeLists.txt @@ -16,6 +16,7 @@ else() add_subdirectory(tcp_server) add_subdirectory(freertos) add_subdirectory(udp_beacon) + add_subdirectory(http_client) if (NOT PICO_MBEDTLS_PATH) message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined") diff --git a/pico_w/wifi/freertos/CMakeLists.txt b/pico_w/wifi/freertos/CMakeLists.txt index 4769aee56..9874cb0ab 100644 --- a/pico_w/wifi/freertos/CMakeLists.txt +++ b/pico_w/wifi/freertos/CMakeLists.txt @@ -5,4 +5,5 @@ else() add_subdirectory(iperf) add_subdirectory(ping) + add_subdirectory(http_client) endif() \ No newline at end of file diff --git a/pico_w/wifi/freertos/http_client/CMakeLists.txt b/pico_w/wifi/freertos/http_client/CMakeLists.txt new file mode 100644 index 000000000..c165e88bc --- /dev/null +++ b/pico_w/wifi/freertos/http_client/CMakeLists.txt @@ -0,0 +1,49 @@ +add_executable(picow_freertos_http_client_nosys + picow_freertos_http_client.c + ) +target_compile_definitions(picow_freertos_http_client_nosys PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" + ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED + ) +target_include_directories(picow_freertos_http_client_nosys PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig + ${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts + ) +target_link_libraries(picow_freertos_http_client_nosys + pico_cyw43_arch_lwip_threadsafe_background + pico_stdlib + pico_lwip_http_util + FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap + ) +pico_add_extra_outputs(picow_freertos_http_client_nosys) + +add_executable(picow_freertos_http_client_sys + picow_freertos_http_client.c + ) +target_compile_definitions(picow_freertos_http_client_sys PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" + NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h) + ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED + ) +target_include_directories(picow_freertos_http_client_sys PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig + ${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts + ) +target_link_libraries(picow_freertos_http_client_sys + pico_cyw43_arch_lwip_sys_freertos + pico_stdlib + pico_lwip_http_util + FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap + ) +pico_add_extra_outputs(picow_freertos_http_client_sys) + +# Ignore warnings from lwip code +set_source_files_properties( + ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c + PROPERTIES + COMPILE_OPTIONS "-Wno-unused-result" + ) \ No newline at end of file diff --git a/pico_w/wifi/freertos/http_client/FreeRTOSConfig.h b/pico_w/wifi/freertos/http_client/FreeRTOSConfig.h new file mode 100644 index 000000000..831e53500 --- /dev/null +++ b/pico_w/wifi/freertos/http_client/FreeRTOSConfig.h @@ -0,0 +1,7 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +// This example uses a common include to avoid repetition +#include "FreeRTOSConfig_examples_common.h" + +#endif diff --git a/pico_w/wifi/freertos/http_client/lwipopts.h b/pico_w/wifi/freertos/http_client/lwipopts.h new file mode 100644 index 000000000..caf985cd8 --- /dev/null +++ b/pico_w/wifi/freertos/http_client/lwipopts.h @@ -0,0 +1,36 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +// Generally you would define your own explicit list of lwIP options +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html) +// +// This example uses a common include to avoid repetition +#include "lwipopts_examples_common.h" + +#if !NO_SYS +#define TCPIP_THREAD_STACKSIZE 1024 +#define DEFAULT_THREAD_STACKSIZE 1024 +#define DEFAULT_RAW_RECVMBOX_SIZE 8 +#define TCPIP_MBOX_SIZE 8 +#define LWIP_TIMEVAL_PRIVATE 0 + +// not necessary, can be done either way +#define LWIP_TCPIP_CORE_LOCKING_INPUT 1 + +// ping_thread sets socket receive timeout, so enable this feature +#define LWIP_SO_RCVTIMEO 1 +#endif + +#define LWIP_ALTCP 1 + +// If you don't want to use TLS (just a http request) you can avoid linking to mbedtls and remove the following +#define LWIP_ALTCP_TLS 1 +#define LWIP_ALTCP_TLS_MBEDTLS 1 + +// Note bug in lwip with LWIP_ALTCP and LWIP_DEBUG +// https://savannah.nongnu.org/bugs/index.php?62159 +//#define LWIP_DEBUG 1 +#undef LWIP_DEBUG +#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON + +#endif diff --git a/pico_w/wifi/freertos/http_client/mbedtls_config.h b/pico_w/wifi/freertos/http_client/mbedtls_config.h new file mode 100644 index 000000000..0ceab1aad --- /dev/null +++ b/pico_w/wifi/freertos/http_client/mbedtls_config.h @@ -0,0 +1,66 @@ +/* Workaround for some mbedtls source files using INT_MAX without including limits.h */ +#include + +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_ENTROPY_HARDWARE_ALT + +#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048 + +#define MBEDTLS_ALLOW_PRIVATE_ACCESS +#define MBEDTLS_HAVE_TIME + +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_SSL_SERVER_NAME_INDICATION +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ERROR_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_OID_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA224_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_AES_FEWER_TABLES + +/* TLS 1.2 */ +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_GCM_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECP_C +#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/freertos/http_client/picow_freertos_http_client.c b/pico_w/wifi/freertos/http_client/picow_freertos_http_client.c new file mode 100644 index 000000000..8fe0e5eda --- /dev/null +++ b/pico_w/wifi/freertos/http_client/picow_freertos_http_client.c @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/cyw43_arch.h" +#include "pico/stdlib.h" +#include "pico/http_client_util.h" +#include "lwip/altcp_tls.h" + +#include "lwip/netif.h" + +#include "FreeRTOS.h" +#include "task.h" + +#ifndef RUN_FREERTOS_ON_CORE +#define RUN_FREERTOS_ON_CORE 0 +#endif + +#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2UL ) +#define BLINK_TASK_PRIORITY ( tskIDLE_PRIORITY + 4UL ) + +// Using this url as we know the root cert won't change for a long time +#define HOST "fw-download-alias1.raspberrypi.com" +#define URL_REQUEST "/net_install/boot.sig" + +// 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" + +void blink_task(__unused void *params) { + bool on = false; + printf("blink_task starts\n"); + while (true) { +#if 0 && configNUM_CORES > 1 + static int last_core_id; + if (portGET_CORE_ID() != last_core_id) { + last_core_id = portGET_CORE_ID(); + printf("blinking now from core %d\n", last_core_id); + } +#endif + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, on); + on = !on; + vTaskDelay(200); + } + vTaskDelete(NULL); +} + +void main_task(__unused void *params) { + if (cyw43_arch_init()) { + printf("failed to initialise\n"); + return; + } + TaskHandle_t blinkHandle = NULL; + xTaskCreate(blink_task, "BlinkThread", configMINIMAL_STACK_SIZE, NULL, BLINK_TASK_PRIORITY, &blinkHandle); + + cyw43_arch_enable_sta_mode(); + printf("Connecting to Wi-Fi...\n"); + if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { + printf("failed to connect.\n"); + exit(1); + } else { + printf("Connected.\n"); + } + + static const uint8_t cert_ok[] = TLS_ROOT_CERT_OK; + PICO_HTTP_REQUEST_T req = {0}; + req.hostname = HOST; + req.url = URL_REQUEST; + req.headers_fn = http_client_header_print_fn; + req.recv_fn = http_client_receive_print_fn; + req.tls_config = altcp_tls_create_config_client(cert_ok, sizeof(cert_ok)); + int pass = http_client_request_sync(cyw43_arch_async_context(), &req); + altcp_tls_free_config(req.tls_config); + + if (pass != 0) { + panic("test failed"); + } + + vTaskDelete(blinkHandle); + cyw43_arch_deinit(); + panic("Test passed"); +} + +void vLaunch( void) { + TaskHandle_t task; + xTaskCreate(main_task, "TestMainThread", 1024, NULL, TEST_TASK_PRIORITY, &task); + +#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1 + // we must bind the main task to one core (well at least while the init is called) + // (note we only do this in NO_SYS mode, because cyw43_arch_freertos + // takes care of it otherwise) + vTaskCoreAffinitySet(task, 1); +#endif + + /* Start the tasks and timer running. */ + vTaskStartScheduler(); +} + +int main( void ) +{ + stdio_init_all(); + + /* Configure the hardware ready to run the demo. */ + const char *rtos_name; +#if ( portSUPPORT_SMP == 1 ) + rtos_name = "FreeRTOS SMP"; +#else + rtos_name = "FreeRTOS"; +#endif + +#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 ) + printf("Starting %s on both cores:\n", rtos_name); + vLaunch(); +#elif ( RUN_FREERTOS_ON_CORE == 1 ) + printf("Starting %s on core 1:\n", rtos_name); + multicore_launch_core1(vLaunch); + while (true); +#else + printf("Starting %s on core 0:\n", rtos_name); + vLaunch(); +#endif + return 0; +} diff --git a/pico_w/wifi/http_client/CMakeLists.txt b/pico_w/wifi/http_client/CMakeLists.txt new file mode 100644 index 000000000..96ba1f957 --- /dev/null +++ b/pico_w/wifi/http_client/CMakeLists.txt @@ -0,0 +1,45 @@ +add_executable(picow_http_client + picow_http_client.c + ) +target_compile_definitions(picow_http_client PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" + ) +target_include_directories(picow_http_client PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts + ) +target_link_libraries(picow_http_client + pico_cyw43_arch_lwip_threadsafe_background + pico_lwip_http_util + pico_stdlib + ) +pico_add_extra_outputs(picow_http_client) + +add_executable(picow_http_client_verify + picow_http_verify.c + ) +target_compile_definitions(picow_http_client_verify 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_http_client_verify PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts + ) +target_link_libraries(picow_http_client_verify + pico_cyw43_arch_lwip_threadsafe_background + pico_lwip_http_util + pico_stdlib + ) +pico_add_extra_outputs(picow_http_client_verify) + +# Ignore warnings from lwip code +set_source_files_properties( + ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c + PROPERTIES + COMPILE_OPTIONS "-Wno-unused-result" + ) diff --git a/pico_w/wifi/http_client/lwipopts.h b/pico_w/wifi/http_client/lwipopts.h new file mode 100644 index 000000000..50b0ab140 --- /dev/null +++ b/pico_w/wifi/http_client/lwipopts.h @@ -0,0 +1,27 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +// Generally you would define your own explicit list of lwIP options +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html) +// +// This example uses a common include to avoid repetition +#include "lwipopts_examples_common.h" + +/* TCP WND must be at least 16 kb to match TLS record size + or you will get a warning "altcp_tls: TCP_WND is smaller than the RX decrypion buffer, connection RX might stall!" */ +#undef TCP_WND +#define TCP_WND 16384 + +#define LWIP_ALTCP 1 + +// If you don't want to use TLS (just a http request) you can avoid linking to mbedtls and remove the following +#define LWIP_ALTCP_TLS 1 +#define LWIP_ALTCP_TLS_MBEDTLS 1 + +// Note bug in lwip with LWIP_ALTCP and LWIP_DEBUG +// https://savannah.nongnu.org/bugs/index.php?62159 +//#define LWIP_DEBUG 1 +#undef LWIP_DEBUG +#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON + +#endif diff --git a/pico_w/wifi/http_client/mbedtls_config.h b/pico_w/wifi/http_client/mbedtls_config.h new file mode 100644 index 000000000..0ceab1aad --- /dev/null +++ b/pico_w/wifi/http_client/mbedtls_config.h @@ -0,0 +1,66 @@ +/* Workaround for some mbedtls source files using INT_MAX without including limits.h */ +#include + +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_ENTROPY_HARDWARE_ALT + +#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048 + +#define MBEDTLS_ALLOW_PRIVATE_ACCESS +#define MBEDTLS_HAVE_TIME + +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_SSL_SERVER_NAME_INDICATION +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ERROR_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_OID_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA224_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_AES_FEWER_TABLES + +/* TLS 1.2 */ +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_GCM_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECP_C +#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/http_client/picow_http_client.c b/pico_w/wifi/http_client/picow_http_client.c new file mode 100644 index 000000000..ef272a07e --- /dev/null +++ b/pico_w/wifi/http_client/picow_http_client.c @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/http_client_util.h" +#include "pico/stdio.h" +#include "pico/cyw43_arch.h" +#include "pico/async_context.h" +#include "lwip/altcp_tls.h" + +#define HOST "worldtimeapi.org" +#define URL_REQUEST "/api/ip" + +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, 10000)) { + printf("failed to connect\n"); + return 1; + } + + PICO_HTTP_REQUEST_T req1 = {0}; + req1.hostname = HOST; + req1.url = URL_REQUEST; + req1.headers_fn = http_client_header_print_fn; + req1.recv_fn = http_client_receive_print_fn; + int result = http_client_request_sync(cyw43_arch_async_context(), &req1); + result += http_client_request_sync(cyw43_arch_async_context(), &req1); // repeat + + // test async + PICO_HTTP_REQUEST_T req2 = req1; + result += http_client_request_async(cyw43_arch_async_context(), &req1); + result += http_client_request_async(cyw43_arch_async_context(), &req2); + while(!req1.complete && !req2.complete) { + async_context_poll(cyw43_arch_async_context()); + async_context_wait_for_work_ms(cyw43_arch_async_context(), 1000); + } + + req1.tls_config = altcp_tls_create_config_client(NULL, 0); // https + result += http_client_request_sync(cyw43_arch_async_context(), &req1); + result += http_client_request_sync(cyw43_arch_async_context(), &req1); // repeat + altcp_tls_free_config(req1.tls_config); + + + if (result != 0) { + panic("test failed"); + } + cyw43_arch_deinit(); + printf("Test passed\n"); + sleep_ms(100); + return 0; +} \ No newline at end of file diff --git a/pico_w/wifi/http_client/picow_http_verify.c b/pico_w/wifi/http_client/picow_http_verify.c new file mode 100644 index 000000000..335e5c85e --- /dev/null +++ b/pico_w/wifi/http_client/picow_http_verify.c @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/http_client_util.h" +#include "pico/stdio.h" +#include "pico/cyw43_arch.h" +#include "pico/async_context.h" +#include "lwip/altcp_tls.h" + +// Using this url as we know the root cert won't change for a long time +#define HOST "fw-download-alias1.raspberrypi.com" +#define URL_REQUEST "/net_install/boot.sig" + +// 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" + +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, 10000)) { + printf("failed to connect\n"); + return 1; + } + // This should work + + static const uint8_t cert_ok[] = TLS_ROOT_CERT_OK; + PICO_HTTP_REQUEST_T req = {0}; + req.hostname = HOST; + req.url = URL_REQUEST; + req.headers_fn = http_client_header_print_fn; + req.recv_fn = http_client_receive_print_fn; + req.tls_config = altcp_tls_create_config_client(cert_ok, sizeof(cert_ok)); + int pass = http_client_request_sync(cyw43_arch_async_context(), &req); + altcp_tls_free_config(req.tls_config); + + // Repeat the test with the wrong certificate. It should fail + static const uint8_t cert_bad[] = TLS_ROOT_CERT_BAD; + req.tls_config = altcp_tls_create_config_client(cert_bad, sizeof(cert_bad)); + int fail = http_client_request_sync(cyw43_arch_async_context(), &req); + altcp_tls_free_config(req.tls_config); + + if (pass != 0 || fail == 0) { + panic("test failed"); + } + cyw43_arch_deinit(); + printf("Test passed\n"); + sleep_ms(100); + return 0; +} \ No newline at end of file