From: Oleksii Beketov Date: Tue, 12 May 2020 13:40:52 +0000 (+0300) Subject: Sample HTTPS server X-Git-Tag: accepted/tizen/6.5/unified/20211029.013650~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2a0c154b07a2298bc8b353e15c9c9f51aabd32dc;p=platform%2Fupstream%2Fiotivity.git Sample HTTPS server New HTTP secure server sample added. Server loads secure credentials from SVR DB. (cherry-picked from ffe5ae340e426f935a0993ef5971958262b310cb) Change-Id: I6ce4b925b9027184be36122363dc39eb182ecfac Signed-off-by: Oleksii Beketov Signed-off-by: Sudipto --- diff --git a/resource/csdk/security/provisioning/sample/SConscript b/resource/csdk/security/provisioning/sample/SConscript index cfde979..bd72de9 100644 --- a/resource/csdk/security/provisioning/sample/SConscript +++ b/resource/csdk/security/provisioning/sample/SConscript @@ -110,6 +110,7 @@ sampleserver_justworks_protectedDB = provisioning_env.Program('sampleserver_just sampleserver_randompin = provisioning_env.Program('sampleserver_randompin', 'sampleserver_randompin.cpp') sampleserver_mfg = provisioning_env.Program('sampleserver_mfg', hwemul_src + ['sampleserver_mfg.cpp']) sampleserver_mvjustworks = provisioning_env.Program('sampleserver_mvjustworks', 'sampleserver_mvjustworks.cpp') +sampleserver_https = provisioning_env.Program('sampleserver_https', hwemul_src + ['sampleserver_https.cpp']) if provisioning_env.get('MULTIPLE_OWNER') == '1': subownerclient = provisioning_env.Program('subownerclient', 'subownerclient.c') @@ -146,6 +147,9 @@ randompin_with_emptyuuid_dat = provisioning_env.Install(sec_provisioning_build_d sec_provisioning_src_dir+ 'oic_svr_db_randompin_with_empty_deviceid.dat') mvjustworksdat = provisioning_env.Install(sec_provisioning_build_dir, sec_provisioning_src_dir + 'oic_svr_db_server_mvjustworks.dat') +httpsdat = provisioning_env.Install(sec_provisioning_build_dir, + sec_provisioning_src_dir+ 'oic_svr_db_server_https.dat') + if provisioning_env.get('MULTIPLE_OWNER') == '1': subownerclientdat = provisioning_env.Install(sec_provisioning_build_dir, @@ -165,17 +169,17 @@ if provisioning_env.get('MULTIPLE_OWNER') == '1': Alias("samples", [ provisioningclient, subownerclient, sampleserver_justworks, sampleserver_randompin, sampleserver_mfg, - sampleserver_preconfpin,sampleserver_justworks_protectedDB, + sampleserver_preconfpin, sampleserver_https, sampleserver_justworks_protectedDB, clientdat, subownerclientdat, preconfserverdat, - justworksdat, randompindat, mfgdat, randompin_with_emptyuuid_dat, + justworksdat, randompindat, mfgdat, httpsdat, randompin_with_emptyuuid_dat, mvjustworksdat, justworksDefaultdat, justworksProtectedDBdat_plain ]) else: Alias("samples", [ provisioningclient, sampleserver_justworks, sampleserver_randompin, sampleserver_mfg, - clientdat,sampleserver_justworks_protectedDB, - justworksdat, randompindat, mfgdat, randompin_with_emptyuuid_dat, + clientdat, sampleserver_https, sampleserver_justworks_protectedDB, + justworksdat, randompindat, mfgdat, httpsdat, randompin_with_emptyuuid_dat, mvjustworksdat, justworksDefaultdat, justworksProtectedDBdat_plain ]) diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_server_https.dat b/resource/csdk/security/provisioning/sample/oic_svr_db_server_https.dat new file mode 100644 index 0000000..3c6758a Binary files /dev/null and b/resource/csdk/security/provisioning/sample/oic_svr_db_server_https.dat differ diff --git a/resource/csdk/security/provisioning/sample/sampleserver_https.cpp b/resource/csdk/security/provisioning/sample/sampleserver_https.cpp new file mode 100644 index 0000000..6982d2e --- /dev/null +++ b/resource/csdk/security/provisioning/sample/sampleserver_https.cpp @@ -0,0 +1,826 @@ +/****************************************************************** +* +* Copyright 2020 Samsung Electronics All Rights Reserved. +* +* +* +* 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. +* +******************************************************************/ +/////////////////////////////////////////////////////////////////////// +//NOTE : This sample server is generated based on svrdbeditor.c +/////////////////////////////////////////////////////////////////////// + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_time time +#define mbedtls_time_t time_t +#define mbedtls_fprintf fprintf +#define mbedtls_printf printf +#define mbedtls_exit exit +#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS +#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE +#endif +#if defined(MBEDTLS_SSL_CACHE_C) +#include "mbedtls/ssl_cache.h" +#endif + +#include +#include + +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/certs.h" +#include "mbedtls/x509.h" +#include "mbedtls/ssl.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" + +#define HTTP_RESPONSE \ + "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ + "

mbed TLS Test Server

\r\n" \ + "

Successful connection using: %s

\r\n" + +#define DEBUG_LEVEL 0 + +#if defined(MBEDTLS_CHECK_PARAMS) +#include "mbedtls/platform_util.h" +#endif + +#include "iotivity_config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_PTHREAD_H +#include +#endif +#include +#include "ocstack.h" +#include "logger.h" +#include "pkix_interface.h" +#include "casecurityinterface.h" +#include "utlist.h" +#include "base64.h" +#include "octypes.h" +#include "oic_malloc.h" +#include "oic_string.h" +#include "srmresourcestrings.h" +#include "credresource.h" +#include "security_internals.h" +extern "C" { +#include "psinterface.h" +} + +#define TAG "SAMPLE_HTTPS_PKIX" +#define PORT "4433" + +//Secure Virtual Resource database for Iotivity Server +//It contains Server's Identity and the manufacturer certificate +char g_svrDbPath[1024]; +static char CRED_FILE[] = "oic_svr_db_server_https.dat"; + +FILE* server_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + +static int ParseCertChain(mbedtls_x509_crt *crt, unsigned char *buf, size_t bufLen) +{ + if (NULL == crt || NULL == buf || 0 == bufLen) + { + OIC_LOG(DEBUG, TAG, "ParseCertChain : Invalid param"); + return -1; + } + + /* byte encoded ASCII string '-----BEGIN CERTIFICATE-----' */ + char pemCertHeader[] = + { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d + }; + // byte encoded ASCII string '-----END CERTIFICATE-----' */ + char pemCertFooter[] = + { + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d + }; + size_t pemCertHeaderLen = sizeof(pemCertHeader); + size_t pemCertFooterLen = sizeof(pemCertFooter); + + size_t len = 0; + unsigned char *tmp = NULL; + int count = 0; + int ret = 0; + size_t pos = 0; + + while (pos < bufLen) + { + if (0x30 == buf[pos] && 0x82 == buf[pos + 1]) + { + tmp = (unsigned char *)buf + pos + 1; + ret = mbedtls_asn1_get_len(&tmp, buf + bufLen, &len); + if (0 != ret) + { + OIC_LOG_V(DEBUG, TAG, "mbedtls_asn1_get_len failed: 0x%04x", ret); + return -1; + } + + if (pos + len < bufLen) + { + ret = mbedtls_x509_crt_parse_der(crt, buf + pos, len + 4); + if (0 == ret) + { + count++; + } + else + { + OIC_LOG_V(DEBUG, TAG, "mbedtls_x509_crt_parse_der failed: 0x%04x", ret); + } + } + pos += len + 4; + } + else if ((buf + pos + pemCertHeaderLen < buf + bufLen) && + 0 == memcmp(buf + pos, pemCertHeader, pemCertHeaderLen)) + { + void *endPos = NULL; + endPos = memmem(&(buf[pos]), bufLen - pos, pemCertFooter, pemCertFooterLen); + if (NULL == endPos) + { + OIC_LOG(DEBUG, TAG, "end of PEM certificate not found."); + return -1; + } + + len = (char *)endPos - ((char *)buf + pos) + pemCertFooterLen; + if (pos + len + 1 <= bufLen) + { + char con = buf[pos + len]; + buf[pos + len] = 0x00; + ret = mbedtls_x509_crt_parse(crt, buf + pos, len + 1); + if (0 == ret) + { + count++; + } + else + { + OIC_LOG_V(DEBUG, TAG, "mbedtls_x509_crt_parse failed: 0x%04x", ret); + } + buf[pos + len] = con; + } + else + { + unsigned char *lastCert = (unsigned char *)OICMalloc((len + 1) * sizeof(unsigned char)); + if (NULL == lastCert) + { + OIC_LOG(DEBUG, TAG, "Failed to allocate memory for certificate"); + return -1; + } + memcpy(lastCert, buf + pos, len); + lastCert[len] = 0x00; + ret = mbedtls_x509_crt_parse(crt, lastCert, len + 1); + if (0 == ret) + { + count++; + } + else + { + OIC_LOG_V(DEBUG, TAG, "mbedtls_x509_crt_parse failed: 0x%04x", ret); + } + OICFree(lastCert); + } + pos += len; + } + else + { + pos++; + } + } + + return 0; +} + +// TODO: Update to use credresource.c +static void ParseDerCaCert(ByteArray_t *crt, const char *usage, uint16_t credId) +{ + if (NULL == crt || NULL == usage) + { + OIC_LOG(DEBUG, TAG, "ParseDerCaCert : Invalid param"); + return; + } + crt->len = 0; + OicSecCred_t *temp = NULL; + + LL_FOREACH(((OicSecCred_t *)GetCredList()), temp) + { + if (SIGNED_ASYMMETRIC_KEY == temp->credType && + 0 == strcmp(temp->credUsage, usage) && + temp->credId == credId) + { + if (OIC_ENCODING_BASE64 == temp->optionalData.encoding) + { + size_t bufSize = B64DECODE_OUT_SAFESIZE((temp->optionalData.len + 1)); + uint8_t *buf = (uint8_t *)OICCalloc(1, bufSize); + if (NULL == buf) + { + OIC_LOG(DEBUG, TAG, "ParseDerCaCert : Failed to allocate memory"); + return; + } + uint32_t outSize; + if (B64_OK != b64Decode((char *)(temp->optionalData.data), temp->optionalData.len, buf, bufSize, + &outSize)) + { + OICFree(buf); + OIC_LOG(DEBUG, TAG, "ParseDerCaCert : Failed to decode base64 data"); + return; + } + crt->data = (uint8_t *)OICRealloc(crt->data, crt->len + outSize); + memcpy(crt->data + crt->len, buf, outSize); + crt->len += outSize; + OICFree(buf); + } + else + { + crt->data = (uint8_t *)OICRealloc(crt->data, crt->len + temp->optionalData.len); + memcpy(crt->data + crt->len, temp->optionalData.data, temp->optionalData.len); + crt->len += temp->optionalData.len; + } + } + } + if (0 == crt->len) + { + OIC_LOG_V(INFO, TAG, "ParseDerCaCert : %s not found", usage); + } + return; +} + +// TODO: Update to use credresource.c +static void ParseDerOwnCert(ByteArray_t *crt, const char *usage, uint16_t credId) +{ + OIC_LOG_V(DEBUG, TAG, "In %s", __func__); + if (NULL == crt || NULL == usage) + { + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); + return; + } + crt->len = 0; + OicSecCred_t *temp = NULL; + LL_FOREACH(((OicSecCred_t *)GetCredList()), temp) + { + if (SIGNED_ASYMMETRIC_KEY == temp->credType && + 0 == strcmp(temp->credUsage, usage) && + temp->credId == credId) + { + crt->data = (uint8_t *)OICRealloc(crt->data, crt->len + temp->publicData.len); + memcpy(crt->data + crt->len, temp->publicData.data, temp->publicData.len); + crt->len += temp->publicData.len; + OIC_LOG_V(DEBUG, TAG, "%s found", usage); + } + } + if (0 == crt->len) + { + OIC_LOG_V(WARNING, TAG, "%s not found", usage); + } + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); + return; +} + +inline void ParseDerKey(ByteArray_t *key, const char *usage, uint16_t credId) +{ + OIC_LOG_V(DEBUG, TAG, "In %s", __func__); + if (NULL == key || NULL == usage) + { + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); + return; + } + + OicSecCred_t *temp = NULL; + key->len = 0; + LL_FOREACH(((OicSecCred_t *)GetCredList()), temp) + { + if (SIGNED_ASYMMETRIC_KEY == temp->credType && + 0 == strcmp(temp->credUsage, usage) && + temp->credId == credId) + { + key->data = (uint8_t *)OICRealloc(key->data, key->len + temp->privateData.len); + memcpy(key->data + key->len, temp->privateData.data, temp->privateData.len); + key->len += temp->privateData.len; + OIC_LOG_V(DEBUG, TAG, "Key for %s found", usage); + } + } + if (0 == key->len) + { + OIC_LOG_V(WARNING, TAG, "Key for %s not found", usage); + } + OIC_LOG_V(DEBUG, TAG, "Out %s", __func__); +} + +void PrintCredList(const OicSecCred_t *creds, mbedtls_x509_crt * crt, mbedtls_pk_context * pkey) +{ + const OicSecCred_t *cred = NULL; + const OicSecCred_t *tempCred = NULL; + bool isEmptyList = true; + LL_FOREACH_SAFE(creds, cred, tempCred) + { + switch (cred->credType) + { + case SYMMETRIC_PAIR_WISE_KEY: + case SYMMETRIC_GROUP_KEY: + case ASYMMETRIC_KEY: + break; + case SIGNED_ASYMMETRIC_KEY: + //private data + if (cred->privateData.data) + { + int ret = mbedtls_pk_parse_key(pkey, cred->privateData.data, cred->privateData.len, + NULL, 0); + if (0 != ret) + { + OIC_LOG_V(ERROR, TAG, "%s: mbedtls_pk_parse_key returned %d", __func__, ret); + return; + } + } + + //public data + if (cred->publicData.data) + { + if (cred->credUsage && + (0 == strcmp(cred->credUsage, PRIMARY_CERT) || + 0 == strcmp(cred->credUsage, MF_PRIMARY_CERT))) + { + char buf[2048]; + mbedtls_x509_crt *tmpCrt = NULL; + PkiInfo_t inf; + int i = 0; + + memset(&inf, 0x00, sizeof(PkiInfo_t)); + + ParseDerOwnCert(&inf.crt, cred->credUsage, cred->credId); + ParseCertChain(crt, inf.crt.data, inf.crt.len); + + for (i = 0, tmpCrt = crt; NULL != tmpCrt; i++, tmpCrt = tmpCrt->next) + { + mbedtls_x509_crt_info( buf, sizeof(buf) - 1, "", tmpCrt ); + } + } + else + { + // TODO: T.B.D + } + } + + //optional data + if (cred->optionalData.data) + { + //CA chain + if (cred->credUsage && + (0 == strcmp(cred->credUsage, TRUST_CA) || + 0 == strcmp(cred->credUsage, MF_TRUST_CA))) + { + char buf[2048]; + mbedtls_x509_crt ca; + mbedtls_x509_crt *tmpCa = NULL; + PkiInfo_t inf; + int i = 0; + + memset(&inf, 0x00, sizeof(PkiInfo_t)); + mbedtls_x509_crt_init(&ca); + + ParseDerCaCert(&inf.ca, cred->credUsage, cred->credId); + ParseCertChain(&ca, inf.ca.data, inf.ca.len); + + for (i = 0, tmpCa = &ca; NULL != tmpCa; i++, tmpCa = tmpCa->next) + { + mbedtls_x509_crt_info( buf, sizeof(buf) - 1, "", tmpCa ); + } + } + else + { + // TODO: T.B.D + } + } + break; + case PIN_PASSWORD: + case ASYMMETRIC_ENCRYPTION_KEY: + default: + break; + } + isEmptyList = false; + } + + return; +} + +void RefreshCred() +{ + OCStackResult ocResult = OC_STACK_ERROR; + uint8_t *secPayload = NULL; + size_t payloadSize = 0; + + OicSecCred_t *credList = NULL; + OicSecCred_t *cred = NULL; + OicSecCred_t *tmpCred = NULL; + //Load security resource data from SVR DB. + ocResult = GetSecureVirtualDatabaseFromPS(OIC_JSON_CRED_NAME, &secPayload, &payloadSize); + if (OC_STACK_OK != ocResult) + { + OIC_LOG_V(WARNING, TAG, "GetSecureVirtualDatabaseFromPS : %d", ocResult); + return; + } + if (secPayload && 0 != payloadSize) + { + ocResult = CBORPayloadToCred(secPayload, payloadSize, &credList); + if (OC_STACK_OK != ocResult) + { + OIC_LOG_V(DEBUG, TAG, "CBORPayloadToCred : %d", ocResult); + OICFree(secPayload); + return; + } + } + OICFree(secPayload); + DeInitCredResource(); + + //Add the loaded credentials into gCred of CredResource module in order to use the credential management mechanism. + LL_FOREACH_SAFE(credList, cred, tmpCred) + { + ocResult = AddCredential(cred); + if (OC_STACK_OK != ocResult) + { + OIC_LOG_V(DEBUG, TAG, "AddCredential : %d", ocResult); + OICFree(credList); + return; + } + } +} + +static FILE *SVRDBFopen(const char *path, const char *mode) +{ + (void)path; // unused |path| parameter + return fopen(g_svrDbPath, mode); +} + +static int MainOperation(char * svrpath, mbedtls_x509_crt * crt, mbedtls_pk_context * pkey) +{ + OCStackResult ocResult = OC_STACK_ERROR; + // initialize persistent storage for SVR DB + static OCPersistentStorage psInst = + { + .open = SVRDBFopen, + .read = fread, + .write = fwrite, + .close = fclose, + .unlink = unlink + }; + + if (!svrpath) + { + OIC_LOG(DEBUG, TAG, "Incorrect file path"); + return -1; + } + + strncpy(g_svrDbPath, svrpath, sizeof(g_svrDbPath) - 1); + g_svrDbPath[sizeof(g_svrDbPath) - 1] = '\0'; + + ocResult = InitPersistentStorageInterface(); + if (OC_STACK_OK != ocResult) + { + OIC_LOG_V(DEBUG, TAG, "InitPersistentStorageInterface error : %d", ocResult); + return -1; + } + + ocResult = OCRegisterPersistentStorageHandler(&psInst); + if (OC_STACK_OK != ocResult) + { + OIC_LOG_V(DEBUG, TAG, "OCRegisterPersistentStorageHandler : %d", ocResult); + return -1; + } + + RefreshCred(); + PrintCredList(GetCredList(), crt, pkey); + + return 0; +} + +int main(int argc, char **argv) +{ + OIC_LOG(DEBUG, TAG, "OCServer is starting..."); + + int opt; + char cert_file[4096] = {0,}; + char key_file[4096] = {0,}; + char key_pass[32] = {0,}; + + // Set options + while ((opt = getopt(argc, argv, "c:k:p:")) != -1) + { + switch (opt) + { + case 'c': + strncpy(cert_file, optarg, sizeof(cert_file) - 1); + printf("Set own certificate file : %s\n", cert_file); + break; + case 'k': + strncpy(key_file, optarg, sizeof(key_file) - 1); + printf("Set private key file : %s\n", key_file); + break; + case 'p': + strncpy(key_pass, optarg, sizeof(key_pass) - 1); + printf("Set private key password : %s\n", key_pass); + break; + default: + printf("Not set any options\n"); + } + } + + mbedtls_ssl_config config; + mbedtls_ssl_config * conf = &config; + mbedtls_ssl_config_init( conf ); + + mbedtls_pk_context pkey; + mbedtls_x509_crt crt; + mbedtls_x509_crt_init(&crt); + mbedtls_pk_init(&pkey); + + MainOperation(CRED_FILE, &crt, &pkey); + + int ret = mbedtls_ssl_conf_own_cert(conf, &crt, &pkey); + + int len; + mbedtls_net_context listen_fd, client_fd; + unsigned char buf[1024]; + const char *pers = "ssl_server"; + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; +#if defined(MBEDTLS_SSL_CACHE_C) + mbedtls_ssl_cache_context cache; +#endif + + mbedtls_net_init( &listen_fd ); + mbedtls_net_init( &client_fd ); + mbedtls_ssl_init( &ssl ); +#if defined(MBEDTLS_SSL_CACHE_C) + mbedtls_ssl_cache_init( &cache ); +#endif + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &ctr_drbg ); + +#if defined(MBEDTLS_DEBUG_C) + mbedtls_debug_set_threshold( DEBUG_LEVEL ); +#endif + + mbedtls_printf( " ok\n" ); + + /* + * 2. Setup the listening TCP socket + */ + mbedtls_printf( " . Bind on https://localhost:%s/ ...", PORT ); + fflush( stdout ); + + if( ( ret = mbedtls_net_bind( &listen_fd, NULL, PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); + goto exit; + } + + mbedtls_printf( " ok\n" ); + + /* + * 3. Seed the RNG + */ + mbedtls_printf( " . Seeding the random number generator..." ); + fflush( stdout ); + + if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char *) pers, + strlen( pers ) ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); + goto exit; + } + + mbedtls_printf( " ok\n" ); + + /* + * 4. Setup stuff + */ + mbedtls_printf( " . Setting up the SSL data...." ); + fflush( stdout ); + + if( ( ret = mbedtls_ssl_config_defaults( conf, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT ) ) != 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 ); + +#if defined(MBEDTLS_SSL_CACHE_C) + mbedtls_ssl_conf_session_cache( conf, &cache, + mbedtls_ssl_cache_get, + mbedtls_ssl_cache_set ); +#endif + + mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); + + if( ( ret = mbedtls_ssl_setup( &ssl, conf ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); + goto exit; + } + + mbedtls_printf( " ok\n" ); + +reset: +#ifdef MBEDTLS_ERROR_C + if( ret != 0 ) + { + char error_buf[100]; + mbedtls_strerror( ret, error_buf, 100 ); + mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf ); + } +#endif + + mbedtls_net_free( &client_fd ); + + mbedtls_ssl_session_reset( &ssl ); + + /* + * 3. Wait until a client connects + */ + mbedtls_printf( " . Waiting for a remote connection ..." ); + fflush( stdout ); + + if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, + NULL, 0, NULL ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); + goto exit; + } + + mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL ); + + mbedtls_printf( " ok\n" ); + + /* + * 5. Handshake + */ + mbedtls_printf( " . Performing the SSL/TLS handshake..." ); + fflush( stdout ); + + while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); + goto reset; + } + } + + mbedtls_printf( " ok\n" ); + + /* + * 6. Read the HTTP Request + */ + mbedtls_printf( " < Read from client:" ); + fflush( stdout ); + + do + { + len = sizeof( buf ) - 1; + memset( buf, 0, sizeof( buf ) ); + ret = mbedtls_ssl_read( &ssl, buf, 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" ); + break; + + 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; + mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); + + if( ret > 0 ) + break; + } + while( 1 ); + + /* + * 7. Write the 200 Response + */ + mbedtls_printf( " > Write to client:" ); + fflush( stdout ); + + len = sprintf( (char *) buf, HTTP_RESPONSE, + mbedtls_ssl_get_ciphersuite( &ssl ) ); + + while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 ) + { + if( ret == MBEDTLS_ERR_NET_CONN_RESET ) + { + mbedtls_printf( " failed\n ! peer closed the connection\n\n" ); + goto reset; + } + + if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); + goto exit; + } + } + + len = ret; + mbedtls_printf( " %d bytes written\n\n%s\n", len, (char *) buf ); + + mbedtls_printf( " . Closing the connection..." ); + + while( ( ret = mbedtls_ssl_close_notify( &ssl ) ) < 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_close_notify returned %d\n\n", ret ); + goto reset; + } + } + + mbedtls_printf( " ok\n" ); + + ret = 0; + goto reset; + +exit: + +#ifdef MBEDTLS_ERROR_C + if( ret != 0 ) + { + char error_buf[100]; + mbedtls_strerror( ret, error_buf, 100 ); + mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf ); + } +#endif + + mbedtls_net_free( &client_fd ); + mbedtls_net_free( &listen_fd ); + + mbedtls_x509_crt_free( &crt ); + mbedtls_pk_free( &pkey ); + mbedtls_ssl_free( &ssl ); + mbedtls_ssl_config_free( &config ); +#if defined(MBEDTLS_SSL_CACHE_C) + mbedtls_ssl_cache_free( &cache ); +#endif + mbedtls_ctr_drbg_free( &ctr_drbg ); + mbedtls_entropy_free( &entropy ); + +#if defined(_WIN32) + mbedtls_printf( " Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +