詳細步驟:
- 使用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"
沒有留言:
張貼留言