/* example-lwip-native-echoclient.c * * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. (formerly known as CyaSSL) * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/tcp.h" #include "lwip/memp.h" #include #include #ifndef WOLFSSL_USER_SETTINGS #include #endif #include #include #ifndef NO_RSA #define USE_CERT_BUFFERS_2048 #define CA_CERTS ca_cert_der_2048 #define CA_CERTS_LEN sizeof_ca_cert_der_2048 #define CLIENT_CERT client_cert_der_2048 #define CLIENT_CERT_LEN sizeof_client_cert_der_2048 #define CLIENT_KEY client_key_der_2048 #define CLIENT_KEY_LEN sizeof_client_key_der_2048 #elif defined(HAVE_ECC) #define USE_CERT_BUFFERS_256 #define CA_CERTS ca_ecc_cert_der_256 #define CA_CERTS_LEN sizeof_ca_ecc_cert_der_256 #define CLIENT_CERT cliecc_cert_der_256 #define CLIENT_CERT_LEN sizeof_cliecc_cert_der_256 #define CLIENT_KEY ecc_clikey_der_256 #define CLIENT_KEY_LEN sizeof_ecc_clikey_der_256 #else #error This examples requires either RSA or ECC to be enabled #endif #include #include #ifndef DEST_PORT #define DEST_PORT 11111 #endif #ifndef DEST_IP_ADDR0 #define DEST_IP_ADDR0 127 #define DEST_IP_ADDR1 0 #define DEST_IP_ADDR2 0 #define DEST_IP_ADDR3 1 #endif #ifndef MAX_MSG_SIZE #define MAX_MSG_SIZE #endif #define TEST_MSG "TLS **TEST 1** " static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err); static void TLS_shutdown(void); static int TLS_connect(void); static int TLS_setup(void); struct tcp_pcb *tls_pcb = NULL; struct tcp_pcb *debug_pcb = NULL; static int tlsConnected = 0; static int tcpConnected = 0; static int tlsWaitingForReply = 0; static WOLFSSL_CTX *ctx = NULL; static WOLFSSL *ssl = NULL; void loggingCb(const int logLevel, const char *const logMessage) { printf("%s\n", logMessage); (void)logLevel; } void tls_echoclient_connect(void) { ip_addr_t DestIPaddr; if (tcpConnected == 0) { tls_pcb = tcp_new(); if (tls_pcb != NULL) { IP4_ADDR(&DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3); tcp_connect(tls_pcb, &DestIPaddr, DEST_PORT, tcp_echoclient_connected); } } if (tcpConnected == 1 && tlsConnected == 0) { TLS_connect(); } if (tlsConnected == 1) { int ret; char reply[MAX_MSG_SIZE]; int err; if (tlsWaitingForReply == 0) { ret = wolfSSL_write(ssl, TEST_MSG, sizeof(TEST_MSG)); if (ret <= 0) { loggingCb(0, "error when writing TLS message"); shutdown(); } else { tlsWaitingForReply = 1; } } /* read a reply from the server */ if (tlsWaitingForReply == 1) { memset(reply, 0, sizeof(reply)); ret = wolfSSL_read(ssl, reply, sizeof(reply)); if (ret <= 0) { err = wolfSSL_get_error(ssl, 0); if (err != SSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) { loggingCb(0, "error when reading TLS message"); shutdown(); } } if (ret > 0) { loggingCb(0, reply); shutdown(); /* received reply, done with connection */ } } } } static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { if (err == ERR_OK) { tcpConnected = 1; /* a tcp_poll could be added here for connection timeout checking */ return TLS_setup(); } return ERR_OK; } /* setup all the TLS structures and load CA */ static int TLS_setup(void) { int ret; #ifdef DEBUG_WOLFSSL /* redirect wolfssl debug print outs */ wolfSSL_SetLoggingCb(loggingCb); wolfSSL_Debugging_ON(); #endif wolfSSL_Init(); /* called once on program startup */ ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()); if (ctx == NULL) { loggingCb(0, "ctx was null"); shutdown(); return ERR_MEM; } /* Load the CA */ ret = wolfSSL_CTX_load_verify_buffer(ctx, CA_CERTS, CA_CERTS_LEN, WOLFSSL_FILETYPE_ASN1); if (ret != WOLFSSL_SUCCESS) { loggingCb(0, "error loading in verify buffer"); return ERR_MEM; } #if 1 /* Disable peer certificate validation for testing */ wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); #endif ssl = wolfSSL_new(ctx); if (ssl == NULL) { loggingCb(0, "ssl was null"); return ERR_MEM; } wolfSSL_SetIO_LwIP(ssl, tls_pcb, NULL, NULL, NULL); return ERR_OK; } static int TLS_connect(void) { if (wolfSSL_connect(ssl) != WOLFSSL_SUCCESS) { /* check if hitting a want read/write case and should call again */ int err = wolfSSL_get_error(ssl, 0); if (err != SSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) { loggingCb(0, "connect error, shutting down"); loggingCb(0, wolfSSL_ERR_reason_error_string(err)); shutdown(); return ERR_CONN; } loggingCb(0, "found want read/write"); } else { loggingCb(0, "setting tlsConnected to 1"); tlsConnected = 1; } return ERR_OK; } /* close all connections and free TLS session */ static void TLS_shutdown(void) { if (ssl != NULL) { wolfSSL_shutdown(ssl); wolfSSL_free(ssl); } if (ctx != NULL) { wolfSSL_CTX_free(ctx); } tlsConnected = 0; tlsWaitingForReply = 0; wolfSSL_Cleanup(); if (tcpConnected == 1) { tcp_output(tls_pcb); tcp_close(tls_pcb); tls_pcb = NULL; tcpConnected = 0; } }