Sample HTTPS server 28/236728/1
authorOleksii Beketov <ol.beketov@samsung.com>
Tue, 12 May 2020 13:40:52 +0000 (16:40 +0300)
committerSudipto <sudipto.bal@samsung.com>
Fri, 19 Jun 2020 17:00:02 +0000 (22:30 +0530)
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 <ol.beketov@samsung.com>
Signed-off-by: Sudipto <sudipto.bal@samsung.com>
resource/csdk/security/provisioning/sample/SConscript
resource/csdk/security/provisioning/sample/oic_svr_db_server_https.dat [new file with mode: 0644]
resource/csdk/security/provisioning/sample/sampleserver_https.cpp [new file with mode: 0644]

index cfde979..bd72de9 100644 (file)
@@ -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 (file)
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 (file)
index 0000000..6982d2e
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#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 <stdlib.h>
+#include <string.h>
+
+#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" \
+    "<h2>mbed TLS Test Server</h2>\r\n" \
+    "<p>Successful connection using: %s</p>\r\n"
+
+#define DEBUG_LEVEL 0
+
+#if defined(MBEDTLS_CHECK_PARAMS)
+#include "mbedtls/platform_util.h"
+#endif
+
+#include "iotivity_config.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+#include <signal.h>
+#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 );
+}
+