zephyr/samples/net/http_server/src/https_server.c
Sergio Rodriguez de60e4c8cd samples/net/http: Add HTTP over TLS sample application
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>
2017-02-14 08:30:35 +02:00

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);
}