Article Index


Chapter 4

Page 90  Simple TLS Client  main.c

#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"

#include "lwip/altcp.h"
#include "lwip/altcp_tls.h"

#include "setupWifi.h"

#define BUF_SIZE 2048
char myBuff[BUF_SIZE];
char header[] = "GET /index.html HTTP/1.1\r\nHOST:example.com\r\n\r\n";

err_t recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
{

    if (p != NULL)
    {
        printf("recv total %d  this buffer %d next %d err %d\n", p->tot_len, p->len, p->next, err);
        pbuf_copy_partial(p, myBuff, p->tot_len, 0);
        myBuff[p->tot_len] = 0;
        printf("Buffer= %s\n", myBuff);
        altcp_recved(pcb, p->tot_len);
        pbuf_free(p);
    }
    return ERR_OK;
}

static err_t altcp_client_connected(void *arg, struct altcp_pcb *pcb, err_t err)
{
    err = altcp_write(pcb, header, strlen(header), 0);
    err = altcp_output(pcb);

    return ERR_OK;
}

int main()
{

    stdio_init_all();
    connect();

    struct altcp_tls_config *tls_config = altcp_tls_create_config_client(NULL, 0);
    struct altcp_pcb *pcb = altcp_tls_new(tls_config, IPADDR_TYPE_ANY);
    mbedtls_ssl_set_hostname(altcp_tls_context(pcb), "example.com");
    altcp_recv(pcb, recv);



    ip_addr_t ip;
    IP4_ADDR(&ip, 93, 184, 216, 34);
    cyw43_arch_lwip_begin();
    err_t err = altcp_connect(pcb, &ip, 443, altcp_client_connected);
    cyw43_arch_lwip_end();
    while (true)
    {
        sleep_ms(500);
    }
}

Page 90 Simple TLS Client cmakelists.txt

cmake_minimum_required(VERSION 3.13)
set(PICO_BOARD pico_w)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

include(pico_sdk_import.cmake)
project(PicoW C CXX ASM)
pico_sdk_init()


add_executable(main
 main.c
)


target_include_directories(main PRIVATE ${CMAKE_CURRENT_LIST_DIR})

target_link_libraries(main pico_stdlib pico_cyw43_arch_lwip_threadsafe_background pico_lwip_mbedtls
pico_mbedtls)
pico_add_extra_outputs(main)

Page 88 Simple TLS Client mbedtls_config.h

//Hardware config
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT
#define MBEDTLS_HAVE_TIME

//error reporting
 #define MBEDTLS_ERROR_C
//used by LwIP
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_CTR_DRBG_C

//RSA KEY EXCHANGE
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_RSA_C
//general key exchange
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C

//encryption
#define MBEDTLS_AES_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_AES_FEWER_TABLES

//certs
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_OID_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C

//hash methods
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C

//TLS
#define MBEDTLS_CIPHER_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_MD_C

//enable client and server modes and TLS
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SERVER_NAME_INDICATION

//enable TLS 1.2
#define MBEDTLS_SSL_PROTO_TLS1_2

#include "/home/pi/pico/pico-sdk/lib/mbedtls/include/mbedtls/check_config.h"

Page 90 full listing not in book

Simple TLS Client lwipopts.h

#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
#define _LWIPOPTS_EXAMPLE_COMMONH_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

#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

#endif /* __LWIPOPTS_H__ */

Page 92 Full listing not in book

TLS Request.h

struct connectionState
{
    int state;
    struct altcp_pcb *pcb;
    char *sendData;
    int bytes;
    char *recvData;
    int start;
};

err_t sent(void *arg, struct altcp_pcb *pcb, u16_t len)
{
    printf("data sent %d\n", len);
}

err_t recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
{
    struct connectionState *cs = (struct connectionState *)arg;
    if (p != NULL)
    {
        printf("recv total %d  this buffer %d next %d err %d\n", p->tot_len, p->len, p->next, err);
        if ((p->tot_len) > 2)
        {
            pbuf_copy_partial(p, (cs->recvData) + (cs->start), p->tot_len, 0);
            cs->start += p->tot_len;
            cs->recvData[cs->start] = 0;
            cs->state = 4;
            altcp_recved(pcb, p->tot_len);
        }
        pbuf_free(p);
    }
    else
    {
        cs->state = 6;
    }
    return ERR_OK;
}

static err_t connected(void *arg, struct altcp_pcb *pcb, err_t err)
{
    struct connectionState *cs = (struct connectionState *)arg;
    cs->state = 2;
    return ERR_OK;
}

err_t poll(void *arg, struct altcp_pcb *pcb)
{
    printf("Connection Closed \n");
    struct connectionState *cs = (struct connectionState *)arg;
    cs->state = 6;
}

void err(void *arg, err_t err)
{
    if (err != ERR_ABRT)
    {
        printf("client_err %d\n", err);
    }
}

struct connectionState *newConnection(char *sendData, int bytes, char *recvData)
{
    struct connectionState *cs = (struct connectionState *)malloc(sizeof(struct connectionState));
    cs->state = 0;
    cs->pcb = altcp_new(NULL);
    altcp_recv(cs->pcb, recv);
    altcp_sent(cs->pcb, sent);
    altcp_err(cs->pcb, err);
    altcp_poll(cs->pcb, poll, 10);
    altcp_arg(cs->pcb, cs);
    cs->sendData = sendData;
    cs->bytes=bytes;
    cs->recvData = recvData;
    cs->start = 0;
    return cs;
}

struct connectionState *newTLSConnection(char* host, char *sendData, int bytes, char *recvData)
{
    struct connectionState *cs = (struct connectionState *)malloc(sizeof(struct connectionState));
    cs->state = 0;

    struct altcp_tls_config *tls_config = altcp_tls_create_config_client(NULL, 0);
    cs->pcb = altcp_tls_new(tls_config, IPADDR_TYPE_ANY);    
    mbedtls_ssl_set_hostname(altcp_tls_context(cs->pcb), host);
    altcp_recv(cs->pcb, recv);
    altcp_sent(cs->pcb, sent);
    altcp_err(cs->pcb, err);
    altcp_poll(cs->pcb, poll, 10);
    altcp_arg(cs->pcb, cs);
    cs->sendData = sendData;
    cs->bytes=bytes;
    cs->recvData = recvData;
    cs->start = 0;
    return cs;
}

struct connectionState *doRequest(ip_addr_t *ip, char *host, u16_t port, char *request, char *file, char *sendData, char *recvData)
{
    char headerTemplate[] = "%s %s HTTP/1.1\r\nHOST:%s:%d\r\nConnection: close\r\nContent-length: %d\r\n\r\n%s";
    int len = snprintf(NULL, 0, headerTemplate, request, file, host, port, strlen(sendData), sendData);
    char *requestData = malloc(len + 1);
    snprintf(requestData, len + 1, headerTemplate, request, file, host, port, strlen(sendData), sendData);
    struct connectionState *cs = newConnection(requestData, strlen(requestData),recvData);
    cyw43_arch_lwip_begin();
    err_t err = altcp_connect(cs->pcb, ip, port, connected);
    cyw43_arch_lwip_end();
    cs->state = 1;
    return cs;
}

struct connectionState *doRequestBinary(ip_addr_t *ip, char *host, u16_t port, char *request, char *file, char *sendData, int bytes, char *recvData)
{

    char headerTemplate[] = "%s %s HTTP/1.1\r\nHOST:%s:%d\r\nConnection: close\r\nContent-length: %d\r\n\r\n";
    int len = snprintf(NULL, 0, headerTemplate, request, file, host, port, bytes);
    char *requestData = malloc(len + bytes + 1);
    snprintf(requestData, len + 1, headerTemplate, request, file, host, port, bytes);
    memcpy(requestData + len, sendData, bytes);
    struct connectionState *cs = newConnection(requestData, len + bytes, recvData);
    cyw43_arch_lwip_begin();
    err_t err = altcp_connect(cs->pcb, ip, port, connected);
    cyw43_arch_lwip_end();
    cs->state = 1;
    return cs;
}


struct connectionState *doTLSRequestBinary(ip_addr_t *ip, char *host, u16_t port, char *request, char *file,  char *sendData,int bytes, char *recvData)
{

    char headerTemplate[] = "%s %s HTTP/1.1\r\nHOST:%s:%d\r\nConnection: close\r\nContent-length: %d\r\n\r\n";
    int len = snprintf(NULL, 0, headerTemplate, request, file, host, port, bytes);
    char *requestData = malloc(len + bytes+1);
    snprintf(requestData, len+1, headerTemplate, request, file, host, port, bytes);
    memcpy(requestData+len,sendData,bytes);  
    struct connectionState *cs = newTLSConnection(host,requestData,len+bytes ,recvData);
    cyw43_arch_lwip_begin();
    err_t err = altcp_connect(cs->pcb, ip, port, connected);
    cyw43_arch_lwip_end();
    cs->state = 1;
    return cs;
}


int pollRequest(struct connectionState **pcs)
{
    if (*pcs == NULL)
        return 0;
    struct connectionState *cs = *pcs;
    switch (cs->state)
    {
    case 0:
    case 1:
    case 3:
        break;

    case 2:
        cs->state = 3;
        cyw43_arch_lwip_begin();
        err_t err = altcp_write(cs->pcb, cs->sendData, cs->bytes, 0);
        err = altcp_output(cs->pcb);
        cyw43_arch_lwip_end();
        break;
    case 4:
        cs->state = 5;
        break;
    case 6:
        cyw43_arch_lwip_begin();
        altcp_close(cs->pcb);
        cyw43_arch_lwip_end();
        free(cs);
        *pcs = NULL;
        return 0;
    }
    return cs->state;
}

Page 94 RequestTLS Client Main.c

#include <stdio.h>

#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "lwip/pbuf.h"
#include "lwip/altcp_tcp.h"
#include "lwip/altcp_tls.h"
#include "setupWifi.h"

#include "request.h"

#define BUF_SIZE 2048
char myBuff[BUF_SIZE];

int main()
{

    stdio_init_all();
    connect();

    ip_addr_t ip;
    IP4_ADDR(&ip, 93, 184, 216, 34);

    struct connectionState *cs1 = doTLSRequestBinary(&ip, "example.com", 443, "GET", "/", NULL, 0, myBuff);
    while (pollRequest(&cs1))
    {
        sleep_ms(200);
    }
    printf("%s\n", myBuff);

    return 0;
}