#if defined(USE_MBEDTLS) // USE_MBEDTLS used with NO_SSL #include "mbedtls/certs.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/debug.h" #include "mbedtls/entropy.h" #include "mbedtls/error.h" #include "mbedtls/net.h" #include "mbedtls/pk.h" #include "mbedtls/platform.h" #include "mbedtls/ssl.h" #include "mbedtls/x509.h" #include "mbedtls/x509_crt.h" #include typedef mbedtls_ssl_context SSL; typedef struct { mbedtls_ssl_config conf; /* SSL configuration */ mbedtls_x509_crt cert; /* Certificate */ mbedtls_ctr_drbg_context ctr; /* Counter random generator state */ mbedtls_entropy_context entropy; /* Entropy context */ mbedtls_pk_context pkey; /* Private key */ } SSL_CTX; /* public api */ int mbed_sslctx_init(SSL_CTX *ctx, const char *crt); void mbed_sslctx_uninit(SSL_CTX *ctx); void mbed_ssl_close(mbedtls_ssl_context *ssl); int mbed_ssl_accept(mbedtls_ssl_context **ssl, SSL_CTX *ssl_ctx, int *sock, struct mg_context *phys_ctx); int mbed_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, int len); int mbed_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, int len); static void mbed_debug(void *context, int level, const char *file, int line, const char *str); static int mbed_ssl_handshake(mbedtls_ssl_context *ssl); int mbed_sslctx_init(SSL_CTX *ctx, const char *crt) { mbedtls_ssl_config *conf; int rc; if (ctx == NULL || crt == NULL) { return -1; } DEBUG_TRACE("%s", "Initializing MbedTLS SSL"); mbedtls_entropy_init(&ctx->entropy); conf = &ctx->conf; mbedtls_ssl_config_init(conf); /* Set mbedTLS debug level by defining MG_CONFIG_MBEDTLS_DEBUG: * 0 No debug = mbedTLS DEFAULT * 1 Error (default if "DEBUG" is set for CivetWeb) * 2 State change * 3 Informational * 4 Verbose */ #if defined(DEBUG) || defined(MG_CONFIG_MBEDTLS_DEBUG) #if defined(MG_CONFIG_MBEDTLS_DEBUG) mbedtls_debug_set_threshold(MG_CONFIG_MBEDTLS_DEBUG); #else mbedtls_debug_set_threshold(1); #endif mbedtls_ssl_conf_dbg(conf, mbed_debug, (void *)ctx); #endif /* Initialize TLS key and cert */ mbedtls_pk_init(&ctx->pkey); mbedtls_ctr_drbg_init(&ctx->ctr); mbedtls_x509_crt_init(&ctx->cert); rc = mbedtls_ctr_drbg_seed(&ctx->ctr, mbedtls_entropy_func, &ctx->entropy, (unsigned char *)"CivetWeb", strlen("CivetWeb")); if (rc != 0) { DEBUG_TRACE("TLS random seed failed (%i)", rc); return -1; } rc = mbedtls_pk_parse_keyfile(&ctx->pkey, crt, NULL); if (rc != 0) { DEBUG_TRACE("TLS parse key file failed (%i)", rc); return -1; } rc = mbedtls_x509_crt_parse_file(&ctx->cert, crt); if (rc != 0) { DEBUG_TRACE("TLS parse crt file failed (%i)", rc); return -1; } rc = mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (rc != 0) { DEBUG_TRACE("TLS set defaults failed (%i)", rc); return -1; } mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &ctx->ctr); /* Set auth mode if peer cert should be verified */ mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_ca_chain(conf, NULL, NULL); /* Configure server cert and key */ rc = mbedtls_ssl_conf_own_cert(conf, &ctx->cert, &ctx->pkey); if (rc != 0) { DEBUG_TRACE("TLS cannot set certificate and private key (%i)", rc); return -1; } return 0; } void mbed_sslctx_uninit(SSL_CTX *ctx) { mbedtls_ctr_drbg_free(&ctx->ctr); mbedtls_pk_free(&ctx->pkey); mbedtls_x509_crt_free(&ctx->cert); mbedtls_entropy_free(&ctx->entropy); mbedtls_ssl_config_free(&ctx->conf); } int mbed_ssl_accept(mbedtls_ssl_context **ssl, SSL_CTX *ssl_ctx, int *sock, struct mg_context *phys_ctx) { int rc; (void)phys_ctx; /* unused, if server statistics is not turned on */ DEBUG_TRACE("TLS accept processing %p", ssl); *ssl = (mbedtls_ssl_context *)mg_calloc_ctx(1, sizeof(mbedtls_ssl_context), phys_ctx); if (*ssl == NULL) { DEBUG_TRACE("TLS accept: malloc ssl failed (%i)", (int)sizeof(mbedtls_ssl_context)); return -1; } mbedtls_ssl_init(*ssl); mbedtls_ssl_setup(*ssl, &ssl_ctx->conf); mbedtls_ssl_set_bio(*ssl, sock, mbedtls_net_send, mbedtls_net_recv, NULL); rc = mbed_ssl_handshake(*ssl); if (rc != 0) { DEBUG_TRACE("TLS handshake failed (%i)", rc); mbedtls_ssl_free(*ssl); mg_free(*ssl); *ssl = NULL; return -1; } DEBUG_TRACE("TLS connection %p accepted, state: %d", ssl, (*ssl)->state); return 0; } void mbed_ssl_close(mbedtls_ssl_context *ssl) { DEBUG_TRACE("TLS connection %p closed", ssl); mbedtls_ssl_close_notify(ssl); mbedtls_ssl_free(ssl); mg_free(ssl); /* mg_free for mg_calloc in mbed_ssl_accept */ } static int mbed_ssl_handshake(mbedtls_ssl_context *ssl) { int rc; while ((rc = mbedtls_ssl_handshake(ssl)) != 0) { if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE && rc != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) { break; } } DEBUG_TRACE("TLS handshake rc: %d, state: %d", rc, ssl->state); return rc; } int mbed_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, int len) { int rc = mbedtls_ssl_read(ssl, buf, len); /* DEBUG_TRACE("mbedtls_ssl_read: %d", rc); */ return rc; } int mbed_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, int len) { int rc = mbedtls_ssl_write(ssl, buf, len); /* DEBUG_TRACE("mbedtls_ssl_write: %d", rc); */ return rc; } static void mbed_debug(void *user_param, int level, const char *file, int line, const char *str) { (void)level; /* Ignored. Limit is set using mbedtls_debug_set_threshold */ (void)user_param; /* Ignored. User parameter (context) is set using mbedtls_ssl_conf_dbg */ DEBUG_TRACE("mbedTLS DEBUG: file: [%s] line: [%d] str: [%s]", file, line, str); } #endif /* USE_MBEDTLS */