mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-10 11:21:56 +00:00
Add the HTTPS (HTTP over TLS) server sample application on top of the current HTTP Parser Library and mbedTLS. This code uses TLS to stablish a secure connection and HTTP parser to identify the request and the proper response. Jira: ZEP-799 Change-Id: Ifbbcd0347bec47d12158440e50a82dc2966334d3 Signed-off-by: Sergio Rodriguez <sergio.sf.rodriguez@intel.com> Signed-off-by: Flavio Santes <flavio.santes@intel.com>
407 lines
8.7 KiB
C
407 lines
8.7 KiB
C
/* Minimal TLS server.
|
|
*
|
|
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
#include <misc/printk.h>
|
|
|
|
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
|
|
#include "mbedtls/config.h"
|
|
#else
|
|
#include CONFIG_MBEDTLS_CFG_FILE
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PLATFORM_C)
|
|
#include "mbedtls/platform.h"
|
|
#else
|
|
#include <stdlib.h>
|
|
#define mbedtls_time_t time_t
|
|
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
|
|
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <net/net_context.h>
|
|
#include <net/net_if.h>
|
|
#include "config.h"
|
|
#include "ssl_utils.h"
|
|
#include "test_certs.h"
|
|
|
|
#include "mbedtls/ssl_cookie.h"
|
|
#include "mbedtls/entropy.h"
|
|
#include "mbedtls/ctr_drbg.h"
|
|
#include "mbedtls/net_sockets.h"
|
|
#include "mbedtls/x509.h"
|
|
#include "mbedtls/ssl.h"
|
|
#include "mbedtls/error.h"
|
|
#include "mbedtls/debug.h"
|
|
|
|
#if defined(MBEDTLS_DEBUG_C)
|
|
#include "mbedtls/debug.h"
|
|
#define DEBUG_THRESHOLD 0
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
|
|
#include "mbedtls/memory_buffer_alloc.h"
|
|
static unsigned char heap[12000];
|
|
#endif
|
|
|
|
/*
|
|
* Hardcoded values for server host and port
|
|
*/
|
|
|
|
static const char *pers = "tls_server";
|
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
static struct in6_addr server_addr;
|
|
#else
|
|
static struct in_addr server_addr;
|
|
#endif
|
|
|
|
struct parsed_url {
|
|
const char *url;
|
|
uint16_t url_len;
|
|
};
|
|
|
|
#define HTTP_RESPONSE \
|
|
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
|
|
"<h2>Zephyr TLS Test Server</h2>\r\n" \
|
|
"<p>Successful connection</p>\r\n"
|
|
|
|
#define HTTP_NOT_FOUND \
|
|
"HTTP/1.0 404 NOT FOUND\r\nContent-Type: text/html\r\n\r\n" \
|
|
"<h2>Zephyr TLS page not found </h2>\r\n" \
|
|
"<p>Successful connection</p>\r\n"
|
|
|
|
static void my_debug(void *ctx, int level,
|
|
const char *file, int line, const char *str)
|
|
{
|
|
const char *p, *basename;
|
|
|
|
ARG_UNUSED(ctx);
|
|
|
|
/* Extract basename from file */
|
|
for (p = basename = file; *p != '\0'; p++) {
|
|
if (*p == '/' || *p == '\\') {
|
|
basename = p + 1;
|
|
}
|
|
|
|
}
|
|
|
|
mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
|
|
}
|
|
|
|
static int entropy_source(void *data, unsigned char *output, size_t len,
|
|
size_t *olen)
|
|
{
|
|
uint32_t seed;
|
|
|
|
ARG_UNUSED(data);
|
|
|
|
seed = sys_rand32_get();
|
|
|
|
if (len > sizeof(seed)) {
|
|
len = sizeof(seed);
|
|
}
|
|
|
|
memcpy(output, &seed, len);
|
|
|
|
*olen = len;
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int on_url(struct http_parser *parser, const char *at, size_t length)
|
|
{
|
|
struct parsed_url *req = (struct parsed_url *)parser->data;
|
|
|
|
req->url = at;
|
|
req->url_len = length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static unsigned char payload[256];
|
|
|
|
void https_server(void)
|
|
{
|
|
struct ssl_context ctx;
|
|
struct parsed_url request;
|
|
int ret, len = 0;
|
|
|
|
mbedtls_entropy_context entropy;
|
|
mbedtls_ctr_drbg_context ctr_drbg;
|
|
mbedtls_ssl_context ssl;
|
|
mbedtls_ssl_config conf;
|
|
mbedtls_x509_crt srvcert;
|
|
mbedtls_pk_context pkey;
|
|
|
|
mbedtls_platform_set_printf(printk);
|
|
|
|
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
|
|
mbedtls_memory_buffer_alloc_init(heap, sizeof(heap));
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_DEBUG_C)
|
|
mbedtls_debug_set_threshold(DEBUG_THRESHOLD);
|
|
mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
|
|
#endif
|
|
mbedtls_x509_crt_init(&srvcert);
|
|
mbedtls_pk_init(&pkey);
|
|
mbedtls_ssl_init(&ssl);
|
|
mbedtls_ssl_config_init(&conf);
|
|
mbedtls_entropy_init(&entropy);
|
|
mbedtls_ctr_drbg_init(&ctr_drbg);
|
|
|
|
/*
|
|
* 1. Load the certificates and private RSA key
|
|
*/
|
|
|
|
ret = mbedtls_x509_crt_parse(&srvcert, rsa_example_cert_der,
|
|
rsa_example_cert_der_len);
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_x509_crt_parse returned %d\n\n", ret);
|
|
goto exit;
|
|
}
|
|
|
|
ret = mbedtls_pk_parse_key(&pkey, rsa_example_keypair_der,
|
|
rsa_example_keypair_der_len, NULL, 0);
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_pk_parse_key returned %d\n\n", ret);
|
|
goto exit;
|
|
}
|
|
|
|
/*
|
|
* 3. Seed the RNG
|
|
*/
|
|
|
|
mbedtls_entropy_add_source(&entropy, entropy_source, NULL,
|
|
MBEDTLS_ENTROPY_MAX_GATHER,
|
|
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
|
|
|
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
|
(const unsigned char *)pers, strlen(pers));
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_ctr_drbg_seed returned %d\n", ret);
|
|
goto exit;
|
|
}
|
|
|
|
/*
|
|
* 4. Setup stuff
|
|
*/
|
|
ret = mbedtls_ssl_config_defaults(&conf,
|
|
MBEDTLS_SSL_IS_SERVER,
|
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
|
MBEDTLS_SSL_PRESET_DEFAULT);
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_ssl_config_defaults returned %d\n\n",
|
|
ret);
|
|
goto exit;
|
|
}
|
|
|
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
|
mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
|
|
|
|
mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL);
|
|
ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey);
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_ssl_conf_own_cert returned %d\n\n",
|
|
ret);
|
|
goto exit;
|
|
}
|
|
|
|
ret = mbedtls_ssl_setup(&ssl, &conf);
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_ssl_setup returned %d\n\n", ret);
|
|
goto exit;
|
|
}
|
|
|
|
/*
|
|
* 3. Wait until a client connects
|
|
*/
|
|
ret = ssl_init(&ctx, &server_addr);
|
|
if (ret != 0) {
|
|
mbedtls_printf(" failed\n ! ssl_init returned %d\n\n", ret);
|
|
goto exit;
|
|
|
|
}
|
|
|
|
/*
|
|
* 4. Prepare http parser
|
|
*/
|
|
http_parser_init(&ctx.parser, HTTP_REQUEST);
|
|
http_parser_settings_init(&ctx.parser_settings);
|
|
ctx.parser.data = &request;
|
|
ctx.parser_settings.on_url = on_url;
|
|
|
|
mbedtls_printf("Zephyr HTTPS Server\n");
|
|
mbedtls_printf("Address: %s, port: %d\n", ZEPHYR_ADDR, SERVER_PORT);
|
|
reset:
|
|
mbedtls_ssl_session_reset(&ssl);
|
|
mbedtls_ssl_set_bio(&ssl, &ctx, ssl_tx, ssl_rx, NULL);
|
|
/*
|
|
* 5. Handshake
|
|
*/
|
|
do {
|
|
ret = mbedtls_ssl_handshake(&ssl);
|
|
if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
|
|
ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
if (ret < 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_ssl_handshake returned %d\n\n",
|
|
ret);
|
|
goto reset;
|
|
}
|
|
}
|
|
} while (ret != 0);
|
|
|
|
/*
|
|
* 6. Read the HTTPS Request
|
|
*/
|
|
mbedtls_printf("Read HTTPS request\n");
|
|
do {
|
|
len = sizeof(payload) - 1;
|
|
memset(payload, 0, sizeof(payload));
|
|
ret = mbedtls_ssl_read(&ssl, payload, len);
|
|
|
|
if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
|
|
ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
continue;
|
|
}
|
|
|
|
if (ret <= 0) {
|
|
switch (ret) {
|
|
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
|
mbedtls_printf(" connection was"
|
|
" closed gracefully\n");
|
|
goto close;
|
|
|
|
case MBEDTLS_ERR_NET_CONN_RESET:
|
|
mbedtls_printf(" connection was"
|
|
" reset by peer\n");
|
|
break;
|
|
|
|
default:
|
|
mbedtls_printf
|
|
(" mbedtls_ssl_read returned -0x%x\n",
|
|
-ret);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
len = ret;
|
|
ret = http_parser_execute(&ctx.parser, &ctx.parser_settings,
|
|
payload, len);
|
|
if (ret < 0) {
|
|
}
|
|
} while (ret < 0);
|
|
|
|
/*
|
|
* 7. Write the Response
|
|
*/
|
|
mbedtls_printf("Write HTTPS response\n");
|
|
|
|
if (!strncmp("/index.html", request.url, request.url_len)) {
|
|
len = snprintf((char *)payload, sizeof(payload),
|
|
HTTP_RESPONSE);
|
|
} else {
|
|
|
|
len = snprintf((char *)payload, sizeof(payload),
|
|
HTTP_NOT_FOUND);
|
|
}
|
|
|
|
do {
|
|
ret = mbedtls_ssl_write(&ssl, payload, len);
|
|
if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
|
|
mbedtls_printf(" failed\n !"
|
|
" peer closed the connection\n");
|
|
goto reset;
|
|
}
|
|
|
|
if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
|
|
ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
if (ret < 0) {
|
|
mbedtls_printf(" failed\n !"
|
|
" mbedtls_ssl_write"
|
|
" returned %d\n", ret);
|
|
goto exit;
|
|
}
|
|
}
|
|
} while (ret <= 0);
|
|
|
|
close:
|
|
|
|
mbedtls_ssl_close_notify(&ssl);
|
|
ret = 0;
|
|
goto reset;
|
|
|
|
exit:
|
|
#ifdef MBEDTLS_ERROR_C
|
|
if (ret != 0) {
|
|
mbedtls_strerror(ret, payload, 100);
|
|
mbedtls_printf("Last error was: %d - %s\n", ret, payload);
|
|
}
|
|
#endif
|
|
|
|
mbedtls_ssl_free(&ssl);
|
|
mbedtls_ssl_config_free(&conf);
|
|
mbedtls_ctr_drbg_free(&ctr_drbg);
|
|
mbedtls_entropy_free(&entropy);
|
|
}
|
|
|
|
#define STACK_SIZE 8192
|
|
uint8_t stack[STACK_SIZE];
|
|
|
|
static inline int init_app(void)
|
|
{
|
|
#if defined(CONFIG_NET_IPV6)
|
|
if (net_addr_pton(AF_INET6, ZEPHYR_ADDR, &server_addr) < 0) {
|
|
mbedtls_printf("Invalid IPv6 address %s", ZEPHYR_ADDR);
|
|
}
|
|
|
|
if (!net_if_ipv6_addr_add(net_if_get_default(), &server_addr,
|
|
NET_ADDR_MANUAL, 0)) {
|
|
return -EIO;
|
|
}
|
|
#else
|
|
if (net_addr_pton(AF_INET, ZEPHYR_ADDR, &server_addr) < 0) {
|
|
mbedtls_printf("Invalid IPv4 address %s", ZEPHYR_ADDR);
|
|
}
|
|
|
|
if (!net_if_ipv4_addr_add(net_if_get_default(), &server_addr,
|
|
NET_ADDR_MANUAL, 0)) {
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
void https_server_start(void)
|
|
{
|
|
if (init_app() != 0) {
|
|
printk("Cannot initialize network\n");
|
|
return;
|
|
}
|
|
|
|
k_thread_spawn(stack, STACK_SIZE, (k_thread_entry_t) https_server,
|
|
NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0);
|
|
|
|
}
|