From a2b1f4221b39e61d0ad41c55f523b08d4a6a2605 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 15 Nov 2016 15:08:51 +0800 Subject: [PATCH] feature/openssl: add the openssl server demo --- examples/10_openssl_server/Makefile | 9 + examples/10_openssl_server/README.md | 20 ++ .../10_openssl_server/main/Kconfig.projbuild | 15 + examples/10_openssl_server/main/cacert.pem | 21 ++ examples/10_openssl_server/main/component.mk | 11 + .../10_openssl_server/main/openssl_server.c | 258 ++++++++++++++++++ .../10_openssl_server/main/openssl_server.h | 22 ++ examples/10_openssl_server/main/prvtkey.pem | 27 ++ 8 files changed, 383 insertions(+) create mode 100644 examples/10_openssl_server/Makefile create mode 100644 examples/10_openssl_server/README.md create mode 100644 examples/10_openssl_server/main/Kconfig.projbuild create mode 100644 examples/10_openssl_server/main/cacert.pem create mode 100644 examples/10_openssl_server/main/component.mk create mode 100644 examples/10_openssl_server/main/openssl_server.c create mode 100644 examples/10_openssl_server/main/openssl_server.h create mode 100644 examples/10_openssl_server/main/prvtkey.pem diff --git a/examples/10_openssl_server/Makefile b/examples/10_openssl_server/Makefile new file mode 100644 index 000000000..f65f11a56 --- /dev/null +++ b/examples/10_openssl_server/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := openssl_server + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/10_openssl_server/README.md b/examples/10_openssl_server/README.md new file mode 100644 index 000000000..ae5c8da0c --- /dev/null +++ b/examples/10_openssl_server/README.md @@ -0,0 +1,20 @@ +# Openssl Example + +The Example contains of OpenSSL server demo. + +First you should configure the project by "make menuconfig": + Example Configuration -> + 1. WiFi SSID: you own wifi that you pc is connected to alse. + 1. WiFi Password: wifi password + +IF you want to test the OpenSSL server demo: + 1. compile the code and load the firmware + 2. input the context of "https://192.168.17.128" into your web browser, the IP of your module may not be 192.168.17.128, you should input your module's IP + 3. You may see that it shows the website is not able to be trusted, but you should select that "go on to visit it" + 4. You should wait for a moment until your see the "OpenSSL server demo!" in your web browser + +Note: + The private key and certification at the example are not trusted by web browser, because they are not created by CA official, just by ourselves. + You can alse create your own private key and ceritification by "openssl at ubuntu or others". + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/10_openssl_server/main/Kconfig.projbuild b/examples/10_openssl_server/main/Kconfig.projbuild new file mode 100644 index 000000000..7a9cb97a0 --- /dev/null +++ b/examples/10_openssl_server/main/Kconfig.projbuild @@ -0,0 +1,15 @@ +menu "Example Configuration" + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + +endmenu \ No newline at end of file diff --git a/examples/10_openssl_server/main/cacert.pem b/examples/10_openssl_server/main/cacert.pem new file mode 100644 index 000000000..e09c3989c --- /dev/null +++ b/examples/10_openssl_server/main/cacert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIJAPMMNobNczaUMA0GCSqGSIb3DQEBBAUAMHQxEzARBgNV +BAMTCk15IFRlc3QgQ0ExCzAJBgNVBAgTAkhaMQswCQYDVQQGEwJDTjEcMBoGCSqG +SIb3DQEJARYNdGVzdEBjZXJ0LmNvbTElMCMGA1UEChMcUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNjExMTUwNTA0MThaFw0xOTExMTUwNTA0MThaMHQx +EzARBgNVBAMTCk15IFRlc3QgQ0ExCzAJBgNVBAgTAkhaMQswCQYDVQQGEwJDTjEc +MBoGCSqGSIb3DQEJARYNdGVzdEBjZXJ0LmNvbTElMCMGA1UEChMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALDjSPDlomepHCzbw4MUrquQAU0xTV4/Npb27k9I5TRVTjIoOs/5hNI2LPFW +e4CREx09ZrT8K3NFOBoSy7bhPAsjGaFxCYYWc9tiX1m5gq3ToVRSmbZ65fE3kvnI +8E/d5VyzA0OMmWbfaolBSTMoWgqRynEaT+z1Eh2yDTzVFy9eov1DdQFUqGDqbH5b +QYvTY5Fyem7UcKWAe2yS0j3H4dVtVBKNY7qV3Px08yGAs5fQFgUwhyB5+qwhvkeL +JdgapGaSTwLgoQKWHbe/lA3NiBIB9hznFUGKo3hmniAvYZbrQcn3tc0l/J4I39v2 +Pm29FAyjWvQyBkGktz2q4elOZYkCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQQFAAOCAQEAJCJ+97oae/FcOLbPpjCpUQnWqYydgSChgalkZNvr4fVp +TnuNg471l0Y2oTJLoWn2YcbPSFVOEeKkU47mpjMzucHHp0zGaW9SdzhZalWwmbgK +q2ijecIbuFHFNedYTk/03K7eaAcjVhD8e0oOJImeLOL6DAFivA1LUnSgXsdGPDtD +zhISsCPTu+cL1j0yP6HBvLeAyb8kaCWJ05RtiVLRANNHQn/keHajJYpMwnEEbJdG +cqN3whfJoGVbZ6isEf2RQJ0pYRnP7uGLW3wGkLWxfdto8uER8HVDx7fZpevLIqGd +1OoSEi3cIJXWBAjx0TLzzhtb6aeIxBJWQqHThtkKdg== +-----END CERTIFICATE----- diff --git a/examples/10_openssl_server/main/component.mk b/examples/10_openssl_server/main/component.mk new file mode 100644 index 000000000..4a891d52f --- /dev/null +++ b/examples/10_openssl_server/main/component.mk @@ -0,0 +1,11 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, +# this will take the sources in the src/ directory, compile them and link them into +# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# + +COMPONENT_EMBED_TXTFILES := cacert.pem +COMPONENT_EMBED_TXTFILES += prvtkey.pem diff --git a/examples/10_openssl_server/main/openssl_server.c b/examples/10_openssl_server/main/openssl_server.c new file mode 100644 index 000000000..4fc841ac7 --- /dev/null +++ b/examples/10_openssl_server/main/openssl_server.c @@ -0,0 +1,258 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "openssl_server.h" + +#include + +#include "openssl/ssl.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "esp_types.h" +#include "esp_log.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" + +#include "nvs_flash.h" +#include "tcpip_adapter.h" + +#include "lwip/sockets.h" +#include "lwip/netdb.h" + +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 static int CONNECTED_BIT = BIT0; + +const static char *TAG = "Openssl_demo"; + +#define OPENSSL_DEMO_SERVER_ACK "HTTP/1.1 200 OK\r\n" \ + "Content-Type: text/html\r\n" \ + "Content-Length: 98\r\n" \ + "\r\n" \ + "\r\n" \ + "OpenSSL demo\r\n" \ + "OpenSSL server demo!\r\n" \ + "\r\n" \ + "\r\n" + +static void openssl_demo_thread(void *p) +{ + int ret; + + SSL_CTX *ctx; + SSL *ssl; + + int socket, new_socket; + socklen_t addr_len; + struct sockaddr_in sock_addr; + + char send_data[] = OPENSSL_DEMO_SERVER_ACK; + int send_bytes = sizeof(send_data); + char recv_buf[OPENSSL_DEMO_RECV_BUF_LEN]; + + extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start"); + extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end"); + const unsigned int cacert_pem_bytes = cacert_pem_end - cacert_pem_start; + + extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start"); + extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end"); + const unsigned int prvtkey_pem_bytes = prvtkey_pem_end - prvtkey_pem_start; + + ESP_LOGI(TAG, "SSL server context create ......"); + ctx = SSL_CTX_new(SSLv3_server_method()); + if (!ctx) { + ESP_LOGI(TAG, "failed"); + goto failed1; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server context set own certification......"); + ret = SSL_CTX_use_certificate_ASN1(ctx, cacert_pem_bytes, cacert_pem_start); + if (!ret) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server context set private key......"); + ret = SSL_CTX_use_PrivateKey_ASN1(0, ctx, prvtkey_pem_start, prvtkey_pem_bytes); + if (!ret) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server create socket ......"); + socket = socket(AF_INET, SOCK_STREAM, 0); + if (socket < 0) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server socket bind ......"); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = 0; + sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT); + ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if (ret) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server socket listen ......"); + ret = listen(socket, 32); + if (ret) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + +reconnect: + ESP_LOGI(TAG, "SSL server create ......"); + ssl = SSL_new(ctx); + if (!ssl) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server socket accept client ......"); + new_socket = accept(socket, (struct sockaddr *)&sock_addr, &addr_len); + if (new_socket < 0) { + ESP_LOGI(TAG, "failed" ); + goto failed4; + } + ESP_LOGI(TAG, "OK"); + + SSL_set_fd(ssl, new_socket); + + ESP_LOGI(TAG, "SSL server accept client ......"); + ret = SSL_accept(ssl); + if (!ret) { + ESP_LOGI(TAG, "failed"); + goto failed5; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server read message ......"); + do { + memset(recv_buf, 0, OPENSSL_DEMO_RECV_BUF_LEN); + ret = SSL_read(ssl, recv_buf, OPENSSL_DEMO_RECV_BUF_LEN - 1); + if (ret <= 0) { + break; + } + if (strstr(recv_buf, "GET / HTTP/1.1")) { + SSL_write(ssl, send_data, send_bytes); + break; + } + } while (1); + + ESP_LOGI(TAG, "result %d", ret); + + SSL_shutdown(ssl); +failed5: + close(new_socket); + new_socket = -1; +failed4: + SSL_free(ssl); + ssl = NULL; + goto reconnect; +failed3: + close(socket); + socket = -1; +failed2: + SSL_CTX_free(ctx); + ctx = NULL; +failed1: + vTaskDelete(NULL); + return ; +} + +static void openssl_client_init(void) +{ + int ret; + xTaskHandle openssl_handle; + extern void openssl_demo_thread(void *p); + + ret = xTaskCreate(openssl_demo_thread, + OPENSSL_DEMO_THREAD_NAME, + OPENSSL_DEMO_THREAD_STACK_WORDS, + NULL, + OPENSSL_DEMO_THREAD_PRORIOTY, + &openssl_handle); + + if (ret != pdPASS) { + ESP_LOGI(TAG, "create thread %s failed", OPENSSL_DEMO_THREAD_NAME); + return ; + } +} + +static esp_err_t wifi_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); + openssl_client_init(); + 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 wifi_conn_init(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(wifi_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_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]\n", EXAMPLE_WIFI_SSID, EXAMPLE_WIFI_PASS); + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +void app_main(void) +{ + nvs_flash_init(); + wifi_conn_init(); +} diff --git a/examples/10_openssl_server/main/openssl_server.h b/examples/10_openssl_server/main/openssl_server.h new file mode 100644 index 000000000..e87f5e482 --- /dev/null +++ b/examples/10_openssl_server/main/openssl_server.h @@ -0,0 +1,22 @@ +#ifndef _OPENSSL_DEMO_H_ +#define _OPENSSL_DEMO_H_ + +/* 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 + +#define OPENSSL_DEMO_THREAD_NAME "OpenSSL_demo" +#define OPENSSL_DEMO_THREAD_STACK_WORDS 10240 +#define OPENSSL_DEMO_THREAD_PRORIOTY 8 + +#define OPENSSL_DEMO_RECV_BUF_LEN 1024 + +#define OPENSSL_DEMO_LOCAL_TCP_PORT 443 + +#endif + diff --git a/examples/10_openssl_server/main/prvtkey.pem b/examples/10_openssl_server/main/prvtkey.pem new file mode 100644 index 000000000..4ead61f6f --- /dev/null +++ b/examples/10_openssl_server/main/prvtkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAsONI8OWiZ6kcLNvDgxSuq5ABTTFNXj82lvbuT0jlNFVOMig6 +z/mE0jYs8VZ7gJETHT1mtPwrc0U4GhLLtuE8CyMZoXEJhhZz22JfWbmCrdOhVFKZ +tnrl8TeS+cjwT93lXLMDQ4yZZt9qiUFJMyhaCpHKcRpP7PUSHbINPNUXL16i/UN1 +AVSoYOpsfltBi9NjkXJ6btRwpYB7bJLSPcfh1W1UEo1jupXc/HTzIYCzl9AWBTCH +IHn6rCG+R4sl2BqkZpJPAuChApYdt7+UDc2IEgH2HOcVQYqjeGaeIC9hlutByfe1 +zSX8ngjf2/Y+bb0UDKNa9DIGQaS3Parh6U5liQIDAQABAoIBAB9K9jp3xXVlO3DM +KBhmbkg3n6NSV4eW00d9w8cO9E1/0eeZql3knJS7tNO1IwApqiIAHM1j1yP7WONz +88oUqpSlzwD6iF7KVhC3pHqxEOdDi0Tpn/viXg+Ab2X1IF5guRTfLnKiyviiCazi +edqtBtDb3d6Icx9Oc7gBKcpbQFDGt++wSOb5L+xhRm9B5B4l/6byikiPeKqIK5tC +SoP9Zr1mvpNoGm1P4LvEunFJcRBqVI010VNwfO9P98oVyzJu9/FZZrQxXoY9JdXF +OM6nbl+hMDM3TkEOda9NvBhImozEAvuc97CaaXyR3XivxMqNqNIb4+syUPa2PCS3 +ZztI5qECgYEA1gbVG6ifpvpbBkDPi3Im8fM3F7FLLrQc48FdFjdMvDhHD9lVKucD +Uaa8PF9dbbvlu2cwMyfBOKSuWaXxRxRsiqiPmTunS1MvPzQcSrGwUrL2AogGucn6 ++NrLQf5P4H5IpkDQ9ih3zwjO6xKFK1WeYnYpHM8qUBtl6q0YFyVBPu0CgYEA05Pn +StWA4D7VSbNnVi6lvFyEOUsTrK3v419598TFiq4eXLq6aV8/CQYzKsSzoG+aOZhX +Li+0uyT5cNzUcXYhTsW1hA/pNhMfxMrYiB1x14zlLp2WRGg4vd/+SxX6d9Yd3acX +7QzPKgdDicXs9QN8ozJOICKvNbUI53AJdATVEY0CgYEAwvpGeoQLrdq1weSZLrg3 +soOX1QW3MDz1dKdbXjnStkWut0mOxR7fbysuoPFf8/ARQcCnsHKvHCMqkpESVWbN +2yPkbfxiU8Tcbf/TJljqAOz4ISY6ula/RKZONTixHBrvpEW4GAiV3Q5xMsYUe33s +ZFaw7YXtTj0ng7tdDvjpj6ECgYEApHdUU9ejVq2BHslWiqe4LbO9FMxHfvO2hgix +xugupp6y+2Irhb2EQn+PRq+g8hXOzPaezkhHNTKItDL08T3iplkJwJ6dqmszRsZn +i2dYFzZu8M2PAZ4CfZahFbz/9id7D9HTx3EtmH4NAgvZJpyPRkzUbiaIDDettDpj +Hsyi1AECgYAPLvjBzQj4kPF8Zo9pQEUcz4pmupRVfv3aRfjnahDK4qZHEePDRj+J +W7pzayrs1dyN9QLB8pTc424z7f8MB3llCICN+ohs8CR/eW0NEobE9ldDOeoCr1Vh +NhNSbrN1iZ8U4oLkRTMaDKkVngGffvjGi/q0tOU7hJdZOqNlk2Iahg== +-----END RSA PRIVATE KEY-----