fix(example): fix https_mbedtls to use new APIs

This commit is contained in:
Wu Jian Gang
2018-06-30 09:32:50 +08:00
parent 7e1efaa69d
commit d3769b9c6f
2 changed files with 210 additions and 155 deletions

View File

@ -1,60 +1,136 @@
/* mbedtls example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/* HTTPS GET Example using plain mbedTLS sockets
*
* Contacts the howsmyssl.com API via TLS v1.2 and reads a JSON
* response.
*
* Adapted from the ssl_client1 example in mbedtls.
*
* Original Copyright (C) 2006-2016, ARM Limited, All Rights Reserved, Apache 2.0 License.
* Additions Copyright (C) Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD, Apache 2.0 License.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <strings.h>
#include "sdkconfig.h"
#include "esp_misc.h"
#include "esp_sta.h"
#include "esp_system.h"
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include <sys/socket.h>
#include <netdb.h>
#include "lwip/apps/sntp.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
const int CONNECTED_BIT = 1 << 0;
/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "www.howsmyssl.com"
#define WEB_PORT "443"
#define WEB_URL "https://www.howsmyssl.com/a/check"
static const char* REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-idf/1.0 espressif\r\n"
"\r\n";
static const char *TAG = "example";
#define HTTPS_MBEDTLS_THREAD_NAME "https_mbedtls"
#define HTTPS_MBEDTLS_THREAD_STACK_WORDS 2048
#define HTTPS_MBEDTLS_THREAD_PRORIOTY 6
static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
#define HTTPS_MBEDTLS_SNTP_SERVERS "pool.ntp.org"
/* Root cert for howsmyssl.com, taken from server_root_cert.pem
static void https_get_task()
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void https_get_task(void *pvParameters)
{
char buf[512];
int ret, flags, len;
@ -69,203 +145,191 @@ static void https_get_task()
mbedtls_ssl_init(&ssl);
mbedtls_x509_crt_init(&cacert);
mbedtls_ctr_drbg_init(&ctr_drbg);
printf("Seeding the random number generator\n");
ESP_LOGI(TAG, "Seeding the random number generator");
mbedtls_ssl_config_init(&conf);
mbedtls_entropy_init(&entropy);
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
NULL, 0)) != 0) {
printf("mbedtls_ctr_drbg_seed returned %d\n", ret);
vTaskDelete(NULL);
return;
if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
NULL, 0)) != 0)
{
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
abort();
}
printf("Loading the CA root certificate...\n");
ESP_LOGI(TAG, "Loading the CA root certificate...");
ret = mbedtls_x509_crt_parse(&cacert, server_root_cert_pem_start, server_root_cert_pem_end - server_root_cert_pem_start);
ret = mbedtls_x509_crt_parse(&cacert, server_root_cert_pem_start,
server_root_cert_pem_end-server_root_cert_pem_start);
if (ret < 0) {
printf("mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
vTaskDelete(NULL);
return;
if(ret < 0)
{
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
abort();
}
printf("Setting hostname for TLS session...\n");
ESP_LOGI(TAG, "Setting hostname for TLS session...");
/* Hostname set here should match CN in server certificate */
if ((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) {
printf("mbedtls_ssl_set_hostname returned -0x%x", -ret);
vTaskDelete(NULL);
return;
/* Hostname set here should match CN in server certificate */
if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
{
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
abort();
}
printf("Setting up the SSL/TLS structure...\n");
ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
if ((ret = mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
printf("mbedtls_ssl_config_defaults returned %d", ret);
if((ret = mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
{
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
goto exit;
}
/* MBEDTLS_SSL_VERIFY_OPTIONAL is bad for security, in this example it will print
a warning if CA verification fails but it will continue to connect.
You should consider using MBEDTLS_SSL_VERIFY_REQUIRED in your own code.
*/
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
#ifdef CONFIG_MBEDTLS_DEBUG
mbedtls_esp_enable_debug_log(&conf, 4);
#endif
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
printf("mbedtls_ssl_setup returned -0x%x\n\n", -ret);
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
{
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
goto exit;
}
while (1) {
while(1) {
/* Wait for the callback to set the CONNECTED_BIT in the
event group.
*/
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
mbedtls_net_init(&server_fd);
printf("Connecting to %s:%s...\n", WEB_SERVER, WEB_PORT);
ESP_LOGI(TAG, "Connecting to %s:%s...", WEB_SERVER, WEB_PORT);
if ((ret = mbedtls_net_connect(&server_fd, WEB_SERVER,
WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
printf("mbedtls_net_connect returned -%x\n", -ret);
WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0)
{
ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
goto exit;
}
printf("Connected.\n");
ESP_LOGI(TAG, "Connected.");
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
printf("Performing the SSL/TLS handshake...\n");
ESP_LOGI(TAG, "Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
printf("mbedtls_ssl_handshake returned -0x%x\n", -ret);
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
goto exit;
}
}
printf("Verifying peer X.509 certificate...\n");
ESP_LOGI(TAG, "Verifying peer X.509 certificate...");
if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0)
{
/* In real life, we probably want to close connection if ret != 0 */
printf("Failed to verify peer certificate!\n");
ESP_LOGW(TAG, "Failed to verify peer certificate!");
bzero(buf, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
printf("verification info: %s\n", buf);
} else {
printf("Certificate verified.\n");
ESP_LOGW(TAG, "verification info: %s", buf);
}
else {
ESP_LOGI(TAG, "Certificate verified.");
}
printf("Cipher suite is %s\n", mbedtls_ssl_get_ciphersuite(&ssl));
ESP_LOGI(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl));
printf("Writing HTTP request...\n");
ESP_LOGI(TAG, "Writing HTTP request...");
size_t written_bytes = 0;
do {
ret = mbedtls_ssl_write(&ssl,
(const unsigned char*)REQUEST + written_bytes,
(const unsigned char *)REQUEST + written_bytes,
strlen(REQUEST) - written_bytes);
if (ret >= 0) {
printf("%d bytes written\n", ret);
ESP_LOGI(TAG, "%d bytes written", ret);
written_bytes += ret;
} else if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_WANT_READ) {
printf("mbedtls_ssl_write returned -0x%x\n", -ret);
ESP_LOGE(TAG, "mbedtls_ssl_write returned -0x%x", -ret);
goto exit;
}
} while (written_bytes < strlen(REQUEST));
} while(written_bytes < strlen(REQUEST));
printf("Reading HTTP response...\n");
ESP_LOGI(TAG, "Reading HTTP response...");
do {
do
{
len = sizeof(buf) - 1;
bzero(buf, sizeof(buf));
ret = mbedtls_ssl_read(&ssl, (unsigned char*)buf, len);
ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
continue;
}
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
ret = 0;
break;
}
if (ret < 0) {
printf("mbedtls_ssl_read returned -0x%x\n", -ret);
if(ret < 0)
{
ESP_LOGE(TAG, "mbedtls_ssl_read returned -0x%x", -ret);
break;
}
if (ret == 0) {
printf("\nconnection closed\n");
if(ret == 0)
{
ESP_LOGI(TAG, "connection closed");
break;
}
len = ret;
ESP_LOGD(TAG, "%d bytes read", len);
/* Print response directly to stdout as it is read */
for (int i = 0; i < len; i++) {
printf("%c", buf[i]);
for(int i = 0; i < len; i++) {
putchar(buf[i]);
}
} while (1);
} while(1);
mbedtls_ssl_close_notify(&ssl);
exit:
exit:
mbedtls_ssl_session_reset(&ssl);
mbedtls_net_free(&server_fd);
if (ret != 0) {
if(ret != 0)
{
mbedtls_strerror(ret, buf, 100);
printf("Last error was: -0x%x - %s\n", -ret, buf);
ESP_LOGE(TAG, "Last error was: -0x%x - %s", -ret, buf);
}
printf("\n"); // JSON output doesn't have a newline at end
putchar('\n'); // JSON output doesn't have a newline at end
static int request_count;
printf("Completed %d requests\n", ++request_count);
ESP_LOGI(TAG, "Completed %d requests", ++request_count);
for (int countdown = 10; countdown >= 0; countdown--) {
printf("%d...\n", countdown);
vTaskDelay(1000 / portTICK_RATE_MS);
for(int countdown = 10; countdown >= 0; countdown--) {
ESP_LOGI(TAG, "%d...", countdown);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Starting again!\n");
}
}
void user_conn_init(void)
{
int32_t ret;
ret = xTaskCreate(https_get_task,
HTTPS_MBEDTLS_THREAD_NAME,
HTTPS_MBEDTLS_THREAD_STACK_WORDS,
NULL,
HTTPS_MBEDTLS_THREAD_PRORIOTY,
NULL);
if (ret != pdPASS) {
printf("create thread %s failed\n", HTTPS_MBEDTLS_THREAD_NAME);
return ;
}
}
void wifi_event_handler_cb(System_Event_t* event)
{
if (event == NULL) {
return;
}
switch (event->event_id) {
case EVENT_STAMODE_GOT_IP:
printf("sta got ip\n");
user_conn_init();
break;
default:
break;
ESP_LOGI(TAG, "Starting again!");
}
}
@ -321,18 +385,9 @@ uint32_t user_rf_cal_sector_set(void)
return rf_cal_sec;
}
void user_init()
void app_main()
{
wifi_set_opmode(STATION_MODE);
{
// set AP parameter
struct station_config config;
bzero(&config, sizeof(struct station_config));
sprintf((char*)config.ssid, CONFIG_WIFI_SSID);
sprintf((char*)config.password, CONFIG_WIFI_PASSWORD);
wifi_station_set_config(&config);
}
wifi_set_event_handler_cb(wifi_event_handler_cb);
ESP_ERROR_CHECK( nvs_flash_init() );
initialise_wifi();
xTaskCreate(&https_get_task, "https_get_task", 2048, NULL, 5, NULL);
}