詳細步驟:
- 使用rpi-imager建立Raspberry Pi 3+作業系統,使用不含Desktop。
設定WiFi連線與enable SSH。 - 安裝NODE-RED:
~$ sudo apt install build-essential git curl
~$ bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) - 安裝self signed CA certificates:
1.產生一組CA key:
openssl genrsa -des3 -out ca.key 2048
2.製作一組CA 憑證:
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
3.製作 server key:
openssl genrsa -out node_red_tls.key 2048
4. 使用server key製作server憑證需求(certificate request):
openssl req -new -out node_red_tls.csr -key node_red_tls.key
5.製作server憑證:
openssl x509 -req -in node_red_tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out node_red_tls.crt -days 360 - 建立NODE-RED flow:
- PicoW Client端:
在lwipopts.h加入啟用mbedtls:
加入ca.crt憑證。
/* 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!" */ // tls #undef TCP_WND #define TCP_WND 16384 #define LWIP_ALTCP 1 #define LWIP_ALTCP_TLS 1 #define LWIP_ALTCP_TLS_MBEDTLS 1 #define LWIP_DEBUG 1 #define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON #define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_REQUIRED
詳細步驟請參閱下列影片:
程式碼:
- picow_tls_client.c
#include < stdio.h > #include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include "picow_tls_client.h" #include "picow_tls_cert.h" #define TCP_POLL_INTERVAL 10 #define LED_RED_PIN 13 #define LED_GREEN_PIN 14 #define LED_BLUE_PIN 15 #define WIFI_SSID "your-ssid" #define WIFI_PASSWORD "your-password" #define SERVER_IP "your-server-ip" #define SERVER_PORT 20000 static struct altcp_tls_config *tls_config = NULL; err_t tcp_connect_close(TLS_CLIENT_T * tls_client) { tls_client->connected=false; tls_client->dns_found=false; return altcp_close(tls_client->tpcb); } static int32_t buff_remain_len=0; err_t tcp_recv_cb(void *arg, struct altcp_pcb *tpcb, struct pbuf *p, err_t err) { TLS_CLIENT_T *tls_client = (TLS_CLIENT_T*)arg; if (!p) { printf("pbuf null\n"); return tcp_connect_close(tls_client); } if (p->tot_len > 0) { // for test only int32_t len; int32_t offset=0; buff_remain_len = p->tot_len; while (buff_remain_len > 0) { len = buff_remain_len > RECV_BUFF_MAX_LEN ? RECV_BUFF_MAX_LEN : buff_remain_len; pbuf_copy_partial(p, tls_client->recv_buff, len,offset); tls_client->recv_buff[len]=0; printf("%s\n", tls_client->recv_buff); buff_remain_len -= len; offset+=len; } altcp_recved(tpcb, p->tot_len); } gpio_put(LED_GREEN_PIN, !gpio_get(LED_GREEN_PIN)); pbuf_free(p); return ERR_OK; } err_t tcp_sent_cb(void *arg, struct altcp_pcb *tpcb, u16_t len) { return ERR_OK; } err_t tcp_poll_cb(void *arg, struct altcp_pcb *tpcb) { TLS_CLIENT_T *tls_client = (TLS_CLIENT_T*)arg; return tcp_connect_close(tls_client); } void tcp_err_cb(void *arg, err_t err) { printf("tcp error:%d\n"); tcp_connect_close(arg); } err_t tcp_connected_cb(void *arg, struct altcp_pcb *tpcb, err_t err) { TLS_CLIENT_T *tls_client = (TLS_CLIENT_T*)arg; if (err == ERR_OK) { printf("tls server connected \n"); tls_client->connected = true; } return err; } void tls_client_dns_found(const char *name, const ip_addr_t *ipaddr, void *callback_arg) { TLS_CLIENT_T *tls_client = (TLS_CLIENT_T*)callback_arg; if (ipaddr) { printf("DNS resolving complete\n"); tls_client->dns_found=true; tls_client->server_addr = *ipaddr; } else { printf("error resolving hostname %s\n", name); tls_client->dns_found=false; } } int main() { int wifi_stat; err_t tcp_stat; stdio_init_all(); printf("Starting \n"); if (cyw43_arch_init()) { printf("cyw43 init error\n"); return 0; } gpio_init_mask(1 << LED_BLUE_PIN | 1 << LED_GREEN_PIN | 1 << LED_RED_PIN); gpio_set_dir_out_masked(1 << LED_BLUE_PIN | 1 << LED_GREEN_PIN | 1 << LED_RED_PIN); tls_config = altcp_tls_create_config_client(ca_cert, sizeof(ca_cert)); //tls_config = altcp_tls_create_config_client(NULL, 0); assert(tls_config); //led: red gpio_put_masked(1 << LED_BLUE_PIN | 1 << LED_GREEN_PIN | 1 << LED_RED_PIN, 0); gpio_put(LED_RED_PIN, true); // connect to WiFi cyw43_arch_enable_sta_mode(); wifi_stat = cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000); if (wifi_stat) { printf("wifi connect error:%d\n", wifi_stat); return 0; } printf("Wifi connected\n"); //led: blue gpio_put_masked(1 << LED_BLUE_PIN | 1 << LED_GREEN_PIN | 1 << LED_RED_PIN, 0); gpio_put(LED_BLUE_PIN, true); // connect to tcp server TLS_CLIENT_T* tls_client = (TLS_CLIENT_T*)calloc(1, sizeof(TLS_CLIENT_T)); // set callback tls_client->tpcb = altcp_tls_new(tls_config, IPADDR_TYPE_ANY); altcp_arg(tls_client->tpcb, tls_client); altcp_sent(tls_client->tpcb, tcp_sent_cb); altcp_recv(tls_client->tpcb, tcp_recv_cb); altcp_poll(tls_client->tpcb, tcp_poll_cb, TCP_POLL_INTERVAL); altcp_err(tls_client->tpcb, tcp_err_cb); /* // if DNS query mbedtls_ssl_set_hostname(altcp_tls_context(tcp_client.tpcb), SERVER_NAME); tls_client->dns_found=false; cyw43_arch_lwip_begin(); tcp_stat = dns_gethostbyname(SERVER_NAME, &tls_client->server_addr, tls_client_dns_found, &tls_client); while(!tls_client->dns_found) { cyw43_arch_poll(); sleep_ms(10); } */ // if not by dns ipaddr_aton(SERVER_IP, &tls_client->server_addr); // connect to server; tls_client->connected = false; tcp_stat = altcp_connect(tls_client->tpcb, &tls_client->server_addr, SERVER_PORT, tcp_connected_cb); if (tcp_stat != ERR_OK) { printf("connect TCP server error:%d\n", tcp_stat); return 0; } absolute_time_t timeout = make_timeout_time_ms(20000); while(!tls_client->connected && absolute_time_diff_us(get_absolute_time(), timeout)>0){ printf("."); cyw43_arch_poll(); sleep_ms(10); } printf("\n"); if (!tls_client->connected) { printf("connection timeout\n"); free(tls_client); return 0; } // led : green gpio_put_masked(1 << LED_BLUE_PIN | 1 << LED_GREEN_PIN | 1 << LED_RED_PIN, 0); gpio_put(LED_GREEN_PIN, true); uint8_t buff[100]; uint32_t idx=0; while(1) { sprintf(buff, "test from PicoW:%020d", idx++); altcp_write(tls_client->tpcb, buff, strlen(buff), TCP_WRITE_FLAG_COPY); cyw43_arch_poll(); cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); //sleep_ms(50); } altcp_close(tls_client->tpcb); free(tls_client); cyw43_arch_deinit(); return 0; }
- CMakeLists.txt
# Generated Cmake Pico project file cmake_minimum_required(VERSION 3.13) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) # Initialise pico_sdk from installed location # (note this can come from environment, CMake cache etc) set(PICO_SDK_PATH "/home/duser/pico/pico-sdk") set(PICO_BOARD pico_w CACHE STRING "Board type") # Pull in Raspberry Pi Pico SDK (must be before project) include(pico_sdk_import.cmake) if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0") message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") endif() project(picow_tls_client C CXX ASM) # Initialise the Raspberry Pi Pico SDK pico_sdk_init() # Add executable. Default name is the project name, version 0.1 add_executable(picow_tls_client picow_tls_client.c ) pico_set_program_name(picow_tls_client "picow_tls_client") pico_set_program_version(picow_tls_client "0.1") pico_enable_stdio_uart(picow_tls_client 1) pico_enable_stdio_usb(picow_tls_client 0) # Add the standard library to the build target_link_libraries(picow_tls_client pico_stdlib) # Add the standard include files to the build target_include_directories(picow_tls_client PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required ) # Add any user requested libraries target_link_libraries(picow_tls_client pico_cyw43_arch_lwip_poll pico_lwip_mbedtls pico_mbedtls ) pico_add_extra_outputs(picow_tls_client)
- picow_tls_client.h
#ifndef __PICOW_TLS_CLIENT_H__ #define __PICOW_TLS_CLIENT_H__ #include "lwip/pbuf.h" #include "lwip/altcp_tcp.h" #include "lwip/altcp_tcp.h" #include "lwip/altcp_tls.h" #include "lwip/dns.h" #define RECV_BUFF_MAX_LEN 1024 typedef struct { struct altcp_pcb *tpcb; ip_addr_t server_addr; bool connected; bool dns_found; uint8_t recv_buff[RECV_BUFF_MAX_LEN+1]; } TLS_CLIENT_T; #endif
- lwipopts.h
#ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ // Common settings used in most of the pico_w examples // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) // allow override in some examples #ifndef NO_SYS #define NO_SYS 1 #endif // allow override in some examples #ifndef LWIP_SOCKET #define LWIP_SOCKET 0 #endif #if PICO_CYW43_ARCH_POLL #define MEM_LIBC_MALLOC 1 #else // MEM_LIBC_MALLOC is incompatible with non polling versions #define MEM_LIBC_MALLOC 0 #endif #define MEM_ALIGNMENT 4 #define MEM_SIZE 4000 #define MEMP_NUM_TCP_SEG 32 #define MEMP_NUM_ARP_QUEUE 10 #define PBUF_POOL_SIZE 24 #define LWIP_ARP 1 #define LWIP_ETHERNET 1 #define LWIP_ICMP 1 #define LWIP_RAW 1 #define TCP_WND (8 * TCP_MSS) #define TCP_MSS 1460 #define TCP_SND_BUF (8 * TCP_MSS) #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) #define LWIP_NETIF_STATUS_CALLBACK 1 #define LWIP_NETIF_LINK_CALLBACK 1 #define LWIP_NETIF_HOSTNAME 1 #define LWIP_NETCONN 0 #define MEM_STATS 0 #define SYS_STATS 0 #define MEMP_STATS 0 #define LINK_STATS 0 // #define ETH_PAD_SIZE 2 #define LWIP_CHKSUM_ALGORITHM 3 #define LWIP_DHCP 1 #define LWIP_IPV4 1 #define LWIP_TCP 1 #define LWIP_UDP 1 #define LWIP_DNS 1 #define LWIP_TCP_KEEPALIVE 1 #define LWIP_NETIF_TX_SINGLE_PBUF 1 #define DHCP_DOES_ARP_CHECK 0 #define LWIP_DHCP_DOES_ACD_CHECK 0 #ifndef NDEBUG #define LWIP_DEBUG 1 #define LWIP_STATS 1 #define LWIP_STATS_DISPLAY 1 #endif #define ETHARP_DEBUG LWIP_DBG_OFF #define NETIF_DEBUG LWIP_DBG_OFF #define PBUF_DEBUG LWIP_DBG_OFF #define API_LIB_DEBUG LWIP_DBG_OFF #define API_MSG_DEBUG LWIP_DBG_OFF #define SOCKETS_DEBUG LWIP_DBG_OFF #define ICMP_DEBUG LWIP_DBG_OFF #define INET_DEBUG LWIP_DBG_OFF #define IP_DEBUG LWIP_DBG_OFF #define IP_REASS_DEBUG LWIP_DBG_OFF #define RAW_DEBUG LWIP_DBG_OFF #define MEM_DEBUG LWIP_DBG_OFF #define MEMP_DEBUG LWIP_DBG_OFF #define SYS_DEBUG LWIP_DBG_OFF #define TCP_DEBUG LWIP_DBG_OFF #define TCP_INPUT_DEBUG LWIP_DBG_OFF #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #define TCP_RTO_DEBUG LWIP_DBG_OFF #define TCP_CWND_DEBUG LWIP_DBG_OFF #define TCP_WND_DEBUG LWIP_DBG_OFF #define TCP_FR_DEBUG LWIP_DBG_OFF #define TCP_QLEN_DEBUG LWIP_DBG_OFF #define TCP_RST_DEBUG LWIP_DBG_OFF #define UDP_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF #define PPP_DEBUG LWIP_DBG_OFF #define SLIP_DEBUG LWIP_DBG_OFF #define DHCP_DEBUG LWIP_DBG_OFF /* 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!" */ // tls #undef TCP_WND #define TCP_WND 16384 #define LWIP_ALTCP 1 #define LWIP_ALTCP_TLS 1 #define LWIP_ALTCP_TLS_MBEDTLS 1 #define LWIP_DEBUG 1 #define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON #define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_REQUIRED #endif /* __LWIPOPTS_H__ */
- mbedtls_config.h
/* Workaround for some mbedtls source files using INT_MAX without including limits.h */ #include < limits.h > #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
- picow_tls_cert.h
#define ca_cert "-----BEGIN CERTIFICATE-----\n\ . . . -----END CERTIFICATE-----\n"
沒有留言:
張貼留言