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