Imported Upstream version 1.0.1
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / adapter_util / caadapternetdtls.c
index 562a5fa..7d7eba2 100644 (file)
 #include "caipinterface.h"
 #include "dtls.h"
 #include "oic_malloc.h"
+#include "oic_string.h"
+#include "global.h"
+#include <netdb.h>
+
+#ifdef __WITH_X509__
+#include "pki.h"
+#include "crl.h"
+#include "cainterface.h"
+
+/* lenght of ASN.1 header in DER format
+ * for subject field in X.509 certificate */
+#define DER_SUBJECT_HEADER_LEN  (9)
+
+#undef VERIFY_SUCCESS
+#define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
+            {OIC_LOG_V(FATAL, NET_DTLS_TAG, "%s failed!!", #op); goto exit;} }
+#endif
 
 /**
  * @def NET_DTLS_TAG
@@ -42,16 +59,158 @@ static stCADtlsContext_t *g_caDtlsContext = NULL;
 static ca_mutex g_dtlsContextMutex = NULL;
 
 /**
- * @var g_dtlsListMutex
- * @brief Mutex to synchronize access to DTLS Cache.
+ * @var g_getCredentialsCallback
+ * @brief callback to get DTLS credentials
  */
-static ca_mutex g_dtlsListMutex = NULL;
+static CAGetDTLSPskCredentialsHandler g_getCredentialsCallback = NULL;
 
+#ifdef __WITH_X509__
 /**
- * @var g_getCredentialsCallback
- * @brief callback to get DTLS credentials
+ * @var g_getX509CredentialsCallback
+ * @brief callback to get DTLS certificate credentials
+ */
+static CAGetDTLSX509CredentialsHandler g_getX509CredentialsCallback = NULL;
+/**
+ * @var g_getCrlCallback
+ * @brief callback to get CRL for DTLS
  */
-static CAGetDTLSCredentialsHandler g_getCredentialsCallback = NULL;
+static CAGetDTLSCrlHandler g_getCrlCallback = NULL;
+#endif //__WITH_X509__
+
+static CASecureEndpoint_t *GetPeerInfo(const CAEndpoint_t *peer)
+{
+    uint32_t list_index = 0;
+    uint32_t list_length = 0;
+
+    if(NULL == peer)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "CAPeerInfoListContains invalid parameters");
+        return NULL;
+    }
+
+    CASecureEndpoint_t *peerInfo = NULL;
+    list_length = u_arraylist_length(g_caDtlsContext->peerInfoList);
+    for (list_index = 0; list_index < list_length; list_index++)
+    {
+        peerInfo = (CASecureEndpoint_t *)u_arraylist_get(g_caDtlsContext->peerInfoList, list_index);
+        if (NULL == peerInfo)
+        {
+            continue;
+        }
+
+        if((0 == strncmp(peer->addr, peerInfo->endpoint.addr, MAX_ADDR_STR_SIZE_CA)) &&
+                (peer->port == peerInfo->endpoint.port))
+        {
+            return peerInfo;
+        }
+    }
+    return NULL;
+}
+
+static CAResult_t CAAddIdToPeerInfoList(const char *peerAddr, uint32_t port,
+        const unsigned char *id, uint16_t id_length)
+{
+    if(NULL == peerAddr
+       || NULL == id
+       || 0 == port
+       || 0 == id_length
+       || CA_MAX_ENDPOINT_IDENTITY_LEN < id_length)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "CAAddIdToPeerInfoList invalid parameters");
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    CASecureEndpoint_t *peer = (CASecureEndpoint_t *)OICCalloc(1, sizeof (CASecureEndpoint_t));
+    if (NULL == peer)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "peerInfo malloc failed!");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    OICStrcpy(peer->endpoint.addr, sizeof(peer->endpoint.addr), peerAddr);
+    peer->endpoint.port = port;
+
+    memcpy(peer->identity.id, id, id_length);
+    peer->identity.id_length = id_length;
+
+    if (NULL != GetPeerInfo(&peer->endpoint))
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "CAAddIdToPeerInfoList peer already exist");
+        OICFree(peer);
+        return CA_STATUS_FAILED;
+    }
+
+    bool result = u_arraylist_add(g_caDtlsContext->peerInfoList, (void *)peer);
+    if (!result)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!");
+        OICFree(peer);
+        return CA_STATUS_FAILED;
+    }
+
+    return CA_STATUS_OK;
+}
+
+static void CAFreePeerInfoList()
+{
+    uint32_t list_length = u_arraylist_length(g_caDtlsContext->peerInfoList);
+    for (uint32_t list_index = 0; list_index < list_length; list_index++)
+    {
+        CAEndpoint_t *peerInfo = (CAEndpoint_t *)u_arraylist_get(
+                                     g_caDtlsContext->peerInfoList, list_index);
+        OICFree(peerInfo);
+    }
+    u_arraylist_free(&(g_caDtlsContext->peerInfoList));
+    g_caDtlsContext->peerInfoList = NULL;
+}
+
+static void CARemovePeerFromPeerInfoList(const char * addr, uint16_t port)
+{
+    if (NULL == addr || 0 >= port)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "CADTLSGetPeerPSKId invalid parameters");
+        return;
+    }
+
+    uint32_t list_length = u_arraylist_length(g_caDtlsContext->peerInfoList);
+    for (uint32_t list_index = 0; list_index < list_length; list_index++)
+    {
+        CAEndpoint_t *peerInfo = (CAEndpoint_t *)u_arraylist_get(
+                                g_caDtlsContext->peerInfoList,list_index);
+        if (NULL == peerInfo)
+        {
+            continue;
+        }
+        if((0 == strncmp(addr, peerInfo->addr, MAX_ADDR_STR_SIZE_CA)) &&
+                (port == peerInfo->port))
+        {
+            OICFree(u_arraylist_remove(g_caDtlsContext->peerInfoList, list_index));
+            return;
+        }
+    }
+}
+
+static int CASizeOfAddrInfo(stCADtlsAddrInfo_t *addrInfo)
+{
+    VERIFY_NON_NULL_RET(addrInfo, NET_DTLS_TAG, "addrInfo is NULL" , DTLS_FAIL);
+
+    switch (addrInfo->addr.st.ss_family)
+    {
+    case AF_INET:
+        {
+            return sizeof (struct sockaddr_in);
+        }
+    case AF_INET6:
+        {
+            return sizeof (struct sockaddr_in6);
+        }
+    default:
+        {
+            break;
+        }
+    }
+    return sizeof (struct sockaddr_storage);
+}
 
 static eDtlsRet_t CAAdapterNetDtlsEncryptInternal(const stCADtlsAddrInfo_t *dstSession,
         uint8_t *data, uint32_t dataLen)
@@ -67,31 +226,32 @@ static eDtlsRet_t CAAdapterNetDtlsEncryptInternal(const stCADtlsAddrInfo_t *dstS
         return DTLS_FAIL;
     }
 
-    ca_mutex_lock(g_dtlsContextMutex);
     if (NULL == g_caDtlsContext)
     {
         OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
-        ca_mutex_unlock(g_dtlsContextMutex);
         return DTLS_FAIL;
     }
 
     int retLen = dtls_write(g_caDtlsContext->dtlsContext, (session_t *)dstSession, data,
                                 dataLen);
     OIC_LOG_V(DEBUG, NET_DTLS_TAG, "dtls_write retun len [%d]", retLen);
-    ca_mutex_unlock(g_dtlsContextMutex);
-
+    if (retLen < 0)
+    {
+        OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT FAILURE");
+        return DTLS_FAIL;
+    }
     if (0 == retLen)
     {
         // A new DTLS session was initiated by tinyDTLS library and wait for callback.
         return DTLS_SESSION_INITIATED;
     }
-    else if (dataLen == retLen)
+    else if (dataLen != (uint32_t)retLen)
     {
-        OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
-        return DTLS_OK;
+        OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT FAILURE");
+        return DTLS_FAIL;
     }
-    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT FAILURE");
-    return DTLS_FAIL;
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
+    return DTLS_OK;
 }
 
 static eDtlsRet_t CAAdapterNetDtlsDecryptInternal(const stCADtlsAddrInfo_t *srcSession,
@@ -110,7 +270,6 @@ static eDtlsRet_t CAAdapterNetDtlsDecryptInternal(const stCADtlsAddrInfo_t *srcS
 
     eDtlsRet_t ret = DTLS_FAIL;
 
-    ///  TODO: how to protect g_caDtlsContext as dtls_handle_message is blocking call
     if (dtls_handle_message(g_caDtlsContext->dtlsContext, (session_t *)srcSession, buf, bufLen) == 0)
     {
         OIC_LOG(DEBUG, NET_DTLS_TAG, "dtls_handle_message success");
@@ -126,7 +285,6 @@ static void CAFreeCacheMsg(stCACacheMessage_t *msg)
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
     VERIFY_NON_NULL_VOID(msg, NET_DTLS_TAG, "msg");
 
-    OICFree(msg->destSession);
     OICFree(msg->data);
     OICFree(msg);
 
@@ -138,11 +296,9 @@ static void CAClearCacheList()
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
     uint32_t list_index = 0;
     uint32_t list_length = 0;
-    ca_mutex_lock(g_dtlsListMutex);
     if (NULL == g_caDtlsContext)
     {
         OIC_LOG(ERROR, NET_DTLS_TAG, "Dtls Context is NULL");
-        ca_mutex_unlock(g_dtlsListMutex);
         return;
     }
     list_length = u_arraylist_length(g_caDtlsContext->cacheList);
@@ -157,7 +313,6 @@ static void CAClearCacheList()
     }
     u_arraylist_free(&g_caDtlsContext->cacheList);
     g_caDtlsContext->cacheList = NULL;
-    ca_mutex_unlock(g_dtlsListMutex);
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
 }
 
@@ -165,32 +320,35 @@ static CAResult_t CADtlsCacheMsg(stCACacheMessage_t *msg)
 {
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
-    ca_mutex_lock(g_dtlsListMutex);
     if (NULL == g_caDtlsContext)
     {
         OIC_LOG(ERROR, NET_DTLS_TAG, "Dtls Context is NULL");
-        ca_mutex_unlock(g_dtlsListMutex);
         return CA_STATUS_FAILED;
     }
 
-    CAResult_t result = u_arraylist_add(g_caDtlsContext->cacheList, (void *)msg);
-    if (CA_STATUS_OK != result)
+    bool result = u_arraylist_add(g_caDtlsContext->cacheList, (void *)msg);
+    if (!result)
     {
         OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!");
+        return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_dtlsListMutex);
 
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
-    return result;
+    return CA_STATUS_OK;
 }
 
 
 static bool CAIsAddressMatching(const stCADtlsAddrInfo_t *a,  const stCADtlsAddrInfo_t *b)
 {
-    return (a->size == b->size) &&
-           (a->addr.sa.sa_family == b->addr.sa.sa_family) &&
-           (a->addr.sin.sin_port == b->addr.sin.sin_port) &&
-           memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, sizeof(struct in_addr)) == 0;
+    if (a->size != b->size)
+    {
+        return false;
+    }
+    if (memcmp(&a->addr, &b->addr, a->size))
+    {
+        return false;
+    }
+    return true;
 }
 
 static void CASendCachedMsg(const stCADtlsAddrInfo_t *dstSession)
@@ -200,15 +358,14 @@ static void CASendCachedMsg(const stCADtlsAddrInfo_t *dstSession)
 
     uint32_t list_index = 0;
     uint32_t list_length = 0;
-    ca_mutex_lock(g_dtlsListMutex);
     list_length = u_arraylist_length(g_caDtlsContext->cacheList);
     for (list_index = 0; list_index < list_length;)
     {
         stCACacheMessage_t *msg = (stCACacheMessage_t *)u_arraylist_get(g_caDtlsContext->cacheList,
                                   list_index);
-        if ((NULL != msg) && (true == CAIsAddressMatching(msg->destSession, dstSession)))
+        if ((NULL != msg) && (true == CAIsAddressMatching(&(msg->destSession), dstSession)))
         {
-            eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(msg->destSession,
+            eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(&(msg->destSession),
                              msg->data, msg->dataLen);
             if (ret == DTLS_OK)
             {
@@ -237,16 +394,16 @@ static void CASendCachedMsg(const stCADtlsAddrInfo_t *dstSession)
             ++list_index;
         }
     }
-    ca_mutex_unlock(g_dtlsListMutex);
 
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
 }
 
-static int32_t CAReadDecryptedPayload(dtls_context_t *dtlsContext,
+static int32_t CAReadDecryptedPayload(dtls_context_t *context,
                                       session_t *session,
                                       uint8_t *buf,
                                       size_t bufLen )
 {
+    (void)context;
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
     VERIFY_NON_NULL_RET(session, NET_DTLS_TAG, "Param Session is NULL", 0);
@@ -254,39 +411,48 @@ static int32_t CAReadDecryptedPayload(dtls_context_t *dtlsContext,
 
     stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session;
 
-    char *remoteAddress = inet_ntoa(addrInfo->addr.sin.sin_addr);
-    uint32_t port = ntohs(addrInfo->addr.sin.sin_port);
-    eDtlsAdapterType_t type = (eDtlsAdapterType_t)addrInfo->ifIndex;
+    CASecureEndpoint_t sep =
+    { .endpoint =
+    { .adapter = CA_ADAPTER_IP, .flags =
+            ((addrInfo->addr.st.ss_family == AF_INET) ? CA_IPV4 : CA_IPV6) | CA_SECURE, .port = 0 },
+            .identity =
+            { 0 } };
+    CAConvertAddrToName(&(addrInfo->addr.st), addrInfo->size, sep.endpoint.addr, &sep.endpoint.port);
 
-    ca_mutex_lock(g_dtlsContextMutex);
     if (NULL == g_caDtlsContext)
     {
         OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
-        ca_mutex_unlock(g_dtlsContextMutex);
         return 0;
     }
 
+    int type = 0;
     if ((0 <= type) && (MAX_SUPPORTED_ADAPTERS > type) &&
         (NULL != g_caDtlsContext->adapterCallbacks[type].recvCallback))
     {
-        g_caDtlsContext->adapterCallbacks[type].recvCallback(remoteAddress, port,
-                buf,  bufLen, true);
+        // Get identity of the source of packet
+        CASecureEndpoint_t *peerInfo = GetPeerInfo(&sep.endpoint);
+        if (peerInfo)
+        {
+            sep.identity = peerInfo->identity;
+        }
+
+        g_caDtlsContext->adapterCallbacks[type].recvCallback(&sep, buf, bufLen);
     }
     else
     {
         OIC_LOG_V(DEBUG, NET_DTLS_TAG, "recvCallback Callback or adapter type is wrong [%d]", type);
     }
-    ca_mutex_unlock(g_dtlsContextMutex);
 
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
     return 0;
 }
 
-static int32_t CASendSecureData(dtls_context_t *dtlsContext,
+static int32_t CASendSecureData(dtls_context_t *context,
                                 session_t *session,
                                 uint8_t *buf,
                                 size_t bufLen)
 {
+    (void)context;
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
     VERIFY_NON_NULL_RET(session, NET_DTLS_TAG, "Param Session is NULL", -1);
@@ -300,35 +466,36 @@ static int32_t CASendSecureData(dtls_context_t *dtlsContext,
 
     stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session;
 
-    char *remoteAddress = inet_ntoa(addrInfo->addr.sin.sin_addr);
-    uint16_t port = ntohs(addrInfo->addr.sin.sin_port);
-    eDtlsAdapterType_t type = (eDtlsAdapterType_t)addrInfo->ifIndex;
+    CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER};
+
+    CAConvertAddrToName(&(addrInfo->addr.st), addrInfo->size, endpoint.addr, &endpoint.port);
+    endpoint.flags = addrInfo->addr.st.ss_family == AF_INET ? CA_IPV4 : CA_IPV6;
+    endpoint.flags |= CA_SECURE;
+    endpoint.adapter = CA_ADAPTER_IP;
+    endpoint.interface = session->ifindex;
+    int type = 0;
 
     //Mutex is not required for g_caDtlsContext. It will be called in same thread.
-    int32_t sentLen = 0;
     if ((0 <= type) && (MAX_SUPPORTED_ADAPTERS > type) &&
         (NULL != g_caDtlsContext->adapterCallbacks[type].sendCallback))
     {
-        sentLen = g_caDtlsContext->adapterCallbacks[type].sendCallback(remoteAddress, port,
-                  buf,  bufLen);
+        g_caDtlsContext->adapterCallbacks[type].sendCallback(&endpoint, buf, bufLen);
     }
     else
     {
         OIC_LOG_V(DEBUG, NET_DTLS_TAG, "send Callback or adapter type is wrong [%d]", type );
     }
 
-    OIC_LOG_V(DEBUG, NET_DTLS_TAG, "sent buffer length [%d]", sentLen);
-
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
-    return sentLen;
+    return bufLen;
 }
 
-
-static int32_t CAHandleSecureEvent(dtls_context_t *dtlsContext,
+static int32_t CAHandleSecureEvent(dtls_context_t *context,
                                    session_t *session,
                                    dtls_alert_level_t level,
                                    unsigned short code)
 {
+    (void)context;
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
     VERIFY_NON_NULL_RET(session, NET_DTLS_TAG, "Param Session is NULL", 0);
@@ -341,6 +508,17 @@ static int32_t CAHandleSecureEvent(dtls_context_t *dtlsContext,
         CASendCachedMsg((stCADtlsAddrInfo_t *)session);
     }
 
+    if(DTLS_ALERT_LEVEL_FATAL == level && DTLS_ALERT_CLOSE_NOTIFY == code)
+    {
+        OIC_LOG(INFO, NET_DTLS_TAG, "Peer closing connection");
+
+        stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session;
+        char peerAddr[MAX_ADDR_STR_SIZE_CA] = { 0 };
+        uint16_t port = 0;
+        CAConvertAddrToName(&(addrInfo->addr.st), addrInfo->size, peerAddr, &port);
+        CARemovePeerFromPeerInfoList(peerAddr, port);
+    }
+
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
     return 0;
 }
@@ -355,61 +533,40 @@ static int32_t CAGetPskCredentials(dtls_context_t *ctx,
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
     int32_t ret  = -1;
+    if(NULL == ctx || NULL == session || NULL == result)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "CAGetPskCredentials invalid parameters");
+        return ret;
+    }
 
     VERIFY_NON_NULL_RET(g_getCredentialsCallback, NET_DTLS_TAG, "GetCredential callback", -1);
-    VERIFY_NON_NULL_RET(result, NET_DTLS_TAG, "result", -1);
-
-    CADtlsPskCredsBlob_t *credInfo = NULL;
 
     // Retrieve the credentials blob from security module
-    g_getCredentialsCallback(&credInfo);
+    ret =  g_getCredentialsCallback(type, desc, descLen, result, resultLen);
 
-    VERIFY_NON_NULL_RET(credInfo, NET_DTLS_TAG, "credInfo is NULL", -1);
-    if(NULL == credInfo->creds)
+    if (ret > 0)
     {
-        OIC_LOG(DEBUG, NET_DTLS_TAG, "credentials are NULL");
-        memset(credInfo, 0, sizeof(CADtlsPskCredsBlob_t));
-        OICFree(credInfo);
-        return -1;
-    }
-
-    if ((type == DTLS_PSK_HINT) || (type == DTLS_PSK_IDENTITY))
-    {
-        if (DTLS_PSK_ID_LEN <= resultLen)
+        // TODO SRM needs identity of the remote end-point with every data packet to
+        // perform access control management. tinyDTLS 'frees' the handshake parameters
+        // data structure when handshake completes. Therefore, currently this is a
+        // workaround to cache remote end-point identity when tinyDTLS asks for PSK.
+        stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session;
+        char peerAddr[MAX_ADDR_STR_SIZE_CA] = { 0 };
+        uint16_t port = 0;
+        CAConvertAddrToName(&(addrInfo->addr.st), addrInfo->size, peerAddr, &port);
+
+        if(CA_STATUS_OK != CAAddIdToPeerInfoList(peerAddr, port, desc, descLen) )
         {
-            memcpy(result, credInfo->identity, DTLS_PSK_ID_LEN);
-            ret = DTLS_PSK_ID_LEN;
+            OIC_LOG(ERROR, NET_DTLS_TAG, "Fail to add peer id to gDtlsPeerInfoList");
         }
     }
 
-    if ((type == DTLS_PSK_KEY) && (desc) && (descLen == DTLS_PSK_PSK_LEN))
-    {
-        // Check if we have the credentials for the device with which we
-        // are trying to perform a handshake
-        int index = 0;
-        for (index = 0; index < credInfo->num; index++)
-        {
-            if (memcmp(desc, credInfo->creds[index].id, DTLS_PSK_ID_LEN) == 0)
-            {
-                memcpy(result, credInfo->creds[index].psk, DTLS_PSK_PSK_LEN);
-                ret = DTLS_PSK_PSK_LEN;
-            }
-        }
-    }
-
-    // Erase sensitive data before freeing.
-    memset(credInfo->creds, 0, sizeof(OCDtlsPskCreds) * (credInfo->num));
-    OICFree(credInfo->creds);
-
-    memset(credInfo, 0, sizeof(CADtlsPskCredsBlob_t));
-    OICFree(credInfo);
-    credInfo = NULL;
-
     return ret;
 }
 
 void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback,
-                               CAPacketSendCallback sendCallback, eDtlsAdapterType_t type)
+                               CAPacketSendCallback sendCallback,
+                               CATransportAdapter_t type)
 {
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
     ca_mutex_lock(g_dtlsContextMutex);
@@ -422,8 +579,9 @@ void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback,
 
     if ((0 <= type) && (MAX_SUPPORTED_ADAPTERS > type))
     {
-        g_caDtlsContext->adapterCallbacks[type].recvCallback = recvCallback;
-        g_caDtlsContext->adapterCallbacks[type].sendCallback = sendCallback;
+        // TODO: change the zeros to better values.
+        g_caDtlsContext->adapterCallbacks[0].recvCallback = recvCallback;
+        g_caDtlsContext->adapterCallbacks[0].sendCallback = sendCallback;
     }
 
     ca_mutex_unlock(g_dtlsContextMutex);
@@ -431,17 +589,378 @@ void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback,
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
 }
 
-void CADTLSSetCredentialsCallback(CAGetDTLSCredentialsHandler credCallback)
+void CADTLSSetCredentialsCallback(CAGetDTLSPskCredentialsHandler credCallback)
 {
+    // TODO Does this method needs protection of DtlsContextMutex ?
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
     g_getCredentialsCallback = credCallback;
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
 }
 
+#ifdef __WITH_X509__
+void CADTLSSetX509CredentialsCallback(CAGetDTLSX509CredentialsHandler credCallback)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
+    g_getX509CredentialsCallback = credCallback;
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
+}
+void CADTLSSetCrlCallback(CAGetDTLSCrlHandler crlCallback)
+{
+    // TODO Does this method needs protection of DtlsContextMutex ?
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
+    g_getCrlCallback = crlCallback;
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
+}
+#endif // __WITH_X509__
+
+CAResult_t CADtlsSelectCipherSuite(const dtls_cipher_t cipher)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsSelectCipherSuite");
+
+    ca_mutex_lock(g_dtlsContextMutex);
+    if (NULL == g_caDtlsContext)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+    dtls_select_cipher(g_caDtlsContext->dtlsContext, cipher);
+    ca_mutex_unlock(g_dtlsContextMutex);
+
+    OIC_LOG_V(DEBUG, NET_DTLS_TAG, "Selected cipher suite is 0x%02X%02X\n",
+        ((uint8_t*)(&cipher))[1], ((uint8_t*)(&cipher))[0]);
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsSelectCipherSuite");
+
+    return CA_STATUS_OK ;
+}
+
+CAResult_t CADtlsEnableAnonECDHCipherSuite(const bool enable)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsEnablesAnonEcdh");
+
+    ca_mutex_lock(g_dtlsContextMutex);
+    if (NULL == g_caDtlsContext)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+    dtls_enables_anon_ecdh(g_caDtlsContext->dtlsContext,
+        enable == true ? DTLS_CIPHER_ENABLE : DTLS_CIPHER_DISABLE);
+    ca_mutex_unlock(g_dtlsContextMutex);
+    OIC_LOG_V(DEBUG, NET_DTLS_TAG, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256  is %s",
+        enable ? "enabled" : "disabled");
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsEnablesAnonEcdh");
+
+    return CA_STATUS_OK ;
+}
+
+CAResult_t CADtlsInitiateHandshake(const CAEndpoint_t *endpoint)
+{
+    stCADtlsAddrInfo_t dst = { 0 };
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsInitiateHandshake");
+
+    if(!endpoint)
+    {
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    CAConvertNameToAddr(endpoint->addr, endpoint->port, &(dst.addr.st));
+    dst.ifIndex = 0;
+    dst.size = CASizeOfAddrInfo(&dst);
+
+    ca_mutex_lock(g_dtlsContextMutex);
+    if(NULL == g_caDtlsContext)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    if(0 > dtls_connect(g_caDtlsContext->dtlsContext, (session_t*)(&dst)))
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to connect");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    ca_mutex_unlock(g_dtlsContextMutex);
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsInitiateHandshake");
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CADtlsClose(const CAEndpoint_t *endpoint)
+{
+    stCADtlsAddrInfo_t dst = { 0 };
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsDisconnect");
+
+    if(!endpoint)
+    {
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    CAConvertNameToAddr(endpoint->addr, endpoint->port, &(dst.addr.st));
+    dst.ifIndex = 0;
+    dst.size = CASizeOfAddrInfo(&dst);
+
+    ca_mutex_lock(g_dtlsContextMutex);
+    if (NULL == g_caDtlsContext)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    if (0 > dtls_close(g_caDtlsContext->dtlsContext, (session_t*)(&dst)))
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to close the session");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    ca_mutex_unlock(g_dtlsContextMutex);
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsDisconnect");
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CADtlsGenerateOwnerPSK(const CAEndpoint_t *endpoint,
+                    const uint8_t* label, const size_t labelLen,
+                    const uint8_t* rsrcServerDeviceID, const size_t rsrcServerDeviceIDLen,
+                    const uint8_t* provServerDeviceID, const size_t provServerDeviceIDLen,
+                    uint8_t* ownerPSK, const size_t ownerPSKSize)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsGenerateOwnerPSK");
+
+    if(!endpoint || !label || 0 == labelLen || !ownerPSK || 0 == ownerPSKSize)
+    {
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    stCADtlsAddrInfo_t dst = { 0 };
+
+    CAConvertNameToAddr(endpoint->addr, endpoint->port, &(dst.addr.st));
+    dst.ifIndex = 0;
+    dst.size = CASizeOfAddrInfo(&dst);
+
+    ca_mutex_lock(g_dtlsContextMutex);
+    if (NULL == g_caDtlsContext)
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    if( 0 == dtls_prf_with_current_keyblock(g_caDtlsContext->dtlsContext, (session_t*)(&dst),
+                 label, labelLen, rsrcServerDeviceID, rsrcServerDeviceIDLen,
+                 provServerDeviceID, provServerDeviceIDLen, ownerPSK, ownerPSKSize))
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to DTLS PRF");
+        ca_mutex_unlock(g_dtlsContextMutex);
+        return CA_STATUS_FAILED;
+    }
+    ca_mutex_unlock(g_dtlsContextMutex);
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsGenerateOwnerPSK");
+
+    return CA_STATUS_OK;
+}
+
+#ifdef __WITH_X509__
+static CADtlsX509Creds_t g_X509Cred = {{0}, 0, 0, {0}, {0}, {0}};
+
+int CAInitX509()
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CAInitX509");
+    VERIFY_NON_NULL_RET(g_getX509CredentialsCallback, NET_DTLS_TAG, "GetX509Credential callback", -1);
+    int isX509Init = (0 == g_getX509CredentialsCallback(&g_X509Cred));
+
+    if (isX509Init)
+    {
+        uint8_t crlData[CRL_MAX_LEN] = {0};
+        ByteArray crlArray = {crlData, CRL_MAX_LEN};
+        g_getCrlCallback(crlArray);
+        if (crlArray.len > 0)
+        {
+            uint8_t keyData[PUBLIC_KEY_SIZE] = {0};
+            CertificateList crl = CRL_INITIALIZER;
+            ByteArray rootPubKey = {keyData, PUBLIC_KEY_SIZE};
+            memcpy(keyData, g_X509Cred.rootPublicKeyX, PUBLIC_KEY_SIZE / 2);
+            memcpy(keyData + PUBLIC_KEY_SIZE / 2, g_X509Cred.rootPublicKeyY, PUBLIC_KEY_SIZE / 2);
+            DecodeCertificateList(crlArray, &crl, rootPubKey);
+        }
+    }
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CAInitX509");
+    if (isX509Init)
+    {
+        return 0;
+    }
+    else
+    {
+        return 1;
+    }
+}
+
+
+static int CAIsX509Active(struct dtls_context_t *ctx)
+{
+    (void)ctx;
+    return 0;
+}
+
+static int CAGetDeviceKey(struct dtls_context_t *ctx,
+                       const session_t *session,
+                       const dtls_ecc_key_t **result)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "CAGetDeviceKey");
+    static dtls_ecc_key_t ecdsa_key = {DTLS_ECDH_CURVE_SECP256R1, NULL, NULL, NULL};
+
+    int ret = 1;
+    VERIFY_SUCCESS(CAInitX509(), 0);
+
+    ecdsa_key.priv_key = g_X509Cred.devicePrivateKey;
+    *result = &ecdsa_key;
+
+    ret = 0;
+exit:
+    return ret;
+}
+
+static int
+CAGetDeviceCertificate(struct dtls_context_t *ctx,
+                    const session_t *session,
+                    const unsigned char **cert,
+                    size_t *cert_size)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "CAGetDeviceCertificate");
+    int ret = 1;
+
+    VERIFY_SUCCESS(CAInitX509(), 0);
+
+    *cert = g_X509Cred.certificateChain;
+    *cert_size = g_X509Cred.certificateChainLen;
+#ifdef X509_DEBUG
+    ByteArray ownCert = {g_X509Cred.certificateChain, g_X509Cred.certificateChainLen};
+    PRINT_BYTE_ARRAY("OWN CERT: \n", ownCert);
+#endif
+
+    ret = 0;
+exit:
+    return ret;
+}
+/**
+ * @fn  CAGetRootKey
+ * @brief  Gets x and y components of Root Certificate Autority public key
+ *
+ * @return  0 on success otherwise a positive error value.
+ *
+ */
+static int CAGetRootKey(const unsigned char **ca_pub_x, const unsigned char **ca_pub_y)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "CAGetRootKey");
+    int ret = 1;
+
+    VERIFY_SUCCESS(CAInitX509(), 0);
+
+    *ca_pub_x = g_X509Cred.rootPublicKeyX;
+    *ca_pub_y = g_X509Cred.rootPublicKeyY;
+
+    ret = 0;
+exit:
+    return ret;
+}
+
+
+static int CAVerifyCertificate(struct dtls_context_t *ctx, const session_t *session,
+                               const unsigned char *cert, size_t certLen,
+                               const unsigned char *x, size_t xLen,
+                               const unsigned char *y, size_t yLen)
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "Verify Certificate");
+
+    ByteArray crtChainDer[MAX_CHAIN_LEN];
+    CertificateX509 crtChain[MAX_CHAIN_LEN];
+
+    uint8_t chainLength;
+
+    int ret;
+    const unsigned char *ca_pub_x;
+    const unsigned char *ca_pub_y;
+    ByteArray certDerCode = BYTE_ARRAY_INITIALIZER;
+    ByteArray caPubKey = BYTE_ARRAY_INITIALIZER;
+    unsigned char ca_pub_key[PUBLIC_KEY_SIZE];
+
+    if ( !ctx ||  !session ||  !cert || !x || !y)
+    {
+        return -PKI_NULL_PASSED;
+    }
+
+    CAGetRootKey (&ca_pub_x, &ca_pub_y);
+
+    certDerCode.data = (uint8_t *)cert;
+    certDerCode.len = certLen;
+
+#ifdef X509_DEBUG
+    PRINT_BYTE_ARRAY("CERT :\n", certDerCode);
+#endif
+
+
+    caPubKey.len = PUBLIC_KEY_SIZE;
+    caPubKey.data = ca_pub_key;
+
+    memcpy(caPubKey.data, ca_pub_x, PUBLIC_KEY_SIZE / 2);
+    memcpy(caPubKey.data + PUBLIC_KEY_SIZE / 2, ca_pub_y, PUBLIC_KEY_SIZE / 2);
+
+    ret = (int)  LoadCertificateChain (certDerCode, crtChainDer, &chainLength);
+    VERIFY_SUCCESS(ret, PKI_SUCCESS);
+    ret = (int)  ParseCertificateChain (crtChainDer, crtChain, chainLength );
+    VERIFY_SUCCESS(ret, PKI_SUCCESS);
+    ret = (int)  CheckCertificateChain (crtChain, chainLength, caPubKey);
+    VERIFY_SUCCESS(ret, PKI_SUCCESS);
+
+    INC_BYTE_ARRAY(crtChain[0].pubKey, 2);
+
+    memcpy(x, crtChain[0].pubKey.data, xLen);
+    memcpy(y, crtChain[0].pubKey.data + PUBLIC_KEY_SIZE / 2, yLen);
+
+    stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session;
+    char peerAddr[MAX_ADDR_STR_SIZE_CA] = { 0 };
+    uint16_t port = 0;
+    CAConvertAddrToName(&(addrInfo->addr.st), addrInfo->size, peerAddr, &port);
+
+    CAResult_t result = CAAddIdToPeerInfoList(peerAddr, port,
+            crtChain[0].subject.data + DER_SUBJECT_HEADER_LEN + 2, crtChain[0].subject.data[DER_SUBJECT_HEADER_LEN + 1]);
+    if (CA_STATUS_OK != result )
+    {
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Fail to add peer id to gDtlsPeerInfoList");
+    }
+
+exit:
+    if (ret != 0)
+    {
+        OIC_LOG(DEBUG, NET_DTLS_TAG, "Certificate verification FAILED\n");
+    }
+    else
+    {
+        OIC_LOG(DEBUG, NET_DTLS_TAG, "Certificate verification SUCCESS\n");
+    }
+    return -ret;
+}
+
+#endif
+
 CAResult_t CAAdapterNetDtlsInit()
 {
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
+    // Initialize mutex for DtlsContext
     if (NULL == g_dtlsContextMutex)
     {
         g_dtlsContextMutex = ca_mutex_new();
@@ -454,47 +973,40 @@ CAResult_t CAAdapterNetDtlsInit()
         return CA_STATUS_OK;
     }
 
-    if (NULL == g_dtlsListMutex)
-    {
-        g_dtlsListMutex = ca_mutex_new();
-        if (NULL == g_dtlsListMutex)
-        {
-            OIC_LOG(ERROR, NET_DTLS_TAG, "g_dtlsListMutex malloc failed");
-            ca_mutex_free(g_dtlsContextMutex);
-            return CA_MEMORY_ALLOC_FAILED;
-        }
-    }
-
+    // Lock DtlsContext mutex and create DtlsContext
     ca_mutex_lock(g_dtlsContextMutex);
     g_caDtlsContext = (stCADtlsContext_t *)OICCalloc(1, sizeof(stCADtlsContext_t));
 
     if (NULL == g_caDtlsContext)
     {
         OIC_LOG(ERROR, NET_DTLS_TAG, "Context malloc failed");
-        ca_mutex_free(g_dtlsListMutex);
         ca_mutex_unlock(g_dtlsContextMutex);
         ca_mutex_free(g_dtlsContextMutex);
         return CA_MEMORY_ALLOC_FAILED;
     }
 
-    ca_mutex_lock(g_dtlsListMutex);
+
+    // Create PeerInfoList and CacheList
+    g_caDtlsContext->peerInfoList = u_arraylist_create();
     g_caDtlsContext->cacheList = u_arraylist_create();
 
-    if (NULL == g_caDtlsContext->cacheList)
+    if( (NULL == g_caDtlsContext->peerInfoList) ||
+        (NULL == g_caDtlsContext->cacheList))
     {
-        OIC_LOG(ERROR, NET_DTLS_TAG, "cacheList initialization failed!");
-        ca_mutex_unlock(g_dtlsListMutex);
-        ca_mutex_free(g_dtlsListMutex);
-        ca_mutex_unlock(g_dtlsContextMutex);
-        ca_mutex_free(g_dtlsContextMutex);
+    OIC_LOG(ERROR, NET_DTLS_TAG, "peerInfoList or cacheList initialization failed!");
+        CAClearCacheList();
+        CAFreePeerInfoList();
         OICFree(g_caDtlsContext);
         g_caDtlsContext = NULL;
+        ca_mutex_unlock(g_dtlsContextMutex);
+        ca_mutex_free(g_dtlsContextMutex);
         return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_dtlsListMutex);
+
     // Initialize clock, crypto and other global vars in tinyDTLS library
     dtls_init();
 
+    // Create tinydtls Context
     g_caDtlsContext->dtlsContext = dtls_new_context(g_caDtlsContext);
 
     if (NULL ==  g_caDtlsContext->dtlsContext)
@@ -508,8 +1020,14 @@ CAResult_t CAAdapterNetDtlsInit()
     g_caDtlsContext->callbacks.write = CASendSecureData;
     g_caDtlsContext->callbacks.read  = CAReadDecryptedPayload;
     g_caDtlsContext->callbacks.event = CAHandleSecureEvent;
-    g_caDtlsContext->callbacks.get_psk_info = CAGetPskCredentials;
 
+    g_caDtlsContext->callbacks.get_psk_info = CAGetPskCredentials;
+#ifdef __WITH_X509__
+    g_caDtlsContext->callbacks.get_x509_key = CAGetDeviceKey;
+    g_caDtlsContext->callbacks.verify_x509_cert = CAVerifyCertificate;
+    g_caDtlsContext->callbacks.get_x509_cert = CAGetDeviceCertificate;
+    g_caDtlsContext->callbacks.is_x509_active = CAIsX509Active;
+#endif //__WITH_X509__*
     dtls_set_handler(g_caDtlsContext->dtlsContext, &(g_caDtlsContext->callbacks));
     ca_mutex_unlock(g_dtlsContextMutex);
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
@@ -521,35 +1039,41 @@ void CAAdapterNetDtlsDeInit()
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
     VERIFY_NON_NULL_VOID(g_caDtlsContext, NET_DTLS_TAG, "context is NULL");
+    VERIFY_NON_NULL_VOID(g_dtlsContextMutex, NET_DTLS_TAG, "context mutex is NULL");
 
+    //Lock DtlsContext mutex
     ca_mutex_lock(g_dtlsContextMutex);
+
+    // Clear all lists
+    CAFreePeerInfoList();
     CAClearCacheList();
+
+    // De-initialize tinydtls context
     dtls_free_context(g_caDtlsContext->dtlsContext);
     g_caDtlsContext->dtlsContext = NULL;
+
+    // De-initialize DtlsContext
     OICFree(g_caDtlsContext);
     g_caDtlsContext = NULL;
-    ca_mutex_unlock(g_dtlsContextMutex);
 
+    // Unlock DtlsContext mutex and de-initialize it
+    ca_mutex_unlock(g_dtlsContextMutex);
     ca_mutex_free(g_dtlsContextMutex);
     g_dtlsContextMutex = NULL;
-    ca_mutex_free(g_dtlsListMutex);
-    g_dtlsListMutex = NULL;
+
     OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
 }
 
-CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress,
-                                   const uint16_t port,
-                                   void *data,
-                                   uint32_t dataLen,
-                                   uint8_t *cacheFlag,
-                                   eDtlsAdapterType_t adapterType)
+CAResult_t CAAdapterNetDtlsEncrypt(const CAEndpoint_t *endpoint,
+                                   void *data, uint32_t dataLen)
 {
 
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
 
-    VERIFY_NON_NULL_RET(remoteAddress, NET_DTLS_TAG,"Param remoteAddress is NULL",CA_STATUS_FAILED);
-
-    VERIFY_NON_NULL_RET(data, NET_DTLS_TAG, "Param data is NULL" , CA_STATUS_FAILED);
+    VERIFY_NON_NULL_RET(endpoint, NET_DTLS_TAG,"Param remoteAddress is NULL",
+                        CA_STATUS_INVALID_PARAM);
+    VERIFY_NON_NULL_RET(data, NET_DTLS_TAG, "Param data is NULL" ,
+                        CA_STATUS_INVALID_PARAM);
 
     if (0 == dataLen)
     {
@@ -559,30 +1083,28 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress,
 
     OIC_LOG_V(DEBUG, NET_DTLS_TAG, "Data to be encrypted dataLen [%d]", dataLen);
 
-    stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)OICCalloc(1, sizeof(stCADtlsAddrInfo_t));
+    stCADtlsAddrInfo_t addrInfo = { 0 };
 
-    VERIFY_NON_NULL_RET(addrInfo, NET_DTLS_TAG, "malloc failed" , CA_MEMORY_ALLOC_FAILED);
+    CAConvertNameToAddr(endpoint->addr, endpoint->port, &(addrInfo.addr.st));
+    addrInfo.ifIndex = 0;
+    addrInfo.size = CASizeOfAddrInfo(&addrInfo);
 
-    addrInfo->addr.sin.sin_family = AF_INET;
-    addrInfo->addr.sin.sin_port = htons(port);
-    // Conversion from ASCII format to Network format
-    if (inet_aton(remoteAddress, &addrInfo->addr.sin.sin_addr) == 0)
+    ca_mutex_lock(g_dtlsContextMutex);
+    if(NULL == g_caDtlsContext)
     {
-        OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address");
-        OICFree(addrInfo);
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
         return CA_STATUS_FAILED;
     }
-    addrInfo->size = sizeof(addrInfo->addr);
-    addrInfo->ifIndex = adapterType;
 
-    eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(addrInfo, data, dataLen);
+    eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(&addrInfo, data, dataLen);
     if (ret == DTLS_SESSION_INITIATED)
     {
         stCACacheMessage_t *message = (stCACacheMessage_t *)OICCalloc(1, sizeof(stCACacheMessage_t));
         if (NULL == message)
         {
             OIC_LOG(ERROR, NET_DTLS_TAG, "calloc failed!");
-            OICFree(addrInfo);
+            ca_mutex_unlock(g_dtlsContextMutex);
             return CA_MEMORY_ALLOC_FAILED;
         }
 
@@ -590,8 +1112,8 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress,
         if (NULL == message->data)
         {
             OIC_LOG(ERROR, NET_DTLS_TAG, "calloc failed!");
-            OICFree(addrInfo);
             OICFree(message);
+            ca_mutex_unlock(g_dtlsContextMutex);
             return CA_MEMORY_ALLOC_FAILED;
         }
         memcpy(message->data, data, dataLen);
@@ -599,63 +1121,51 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress,
         message->destSession = addrInfo;
 
         CAResult_t result = CADtlsCacheMsg(message);
-        if (CA_STATUS_OK == result)
-        {
-            if (cacheFlag)
-            {
-                *cacheFlag = 1;
-            }
-        }
-        else
+        if (CA_STATUS_OK != result)
         {
             OIC_LOG(DEBUG, NET_DTLS_TAG, "CADtlsCacheMsg failed!");
             CAFreeCacheMsg(message);
         }
         OIC_LOG_V(DEBUG, NET_DTLS_TAG, "OUT Initiating Dtls session [%d]", result);
+        ca_mutex_unlock(g_dtlsContextMutex);
         return result;
     }
 
-    OICFree(addrInfo);
+    ca_mutex_unlock(g_dtlsContextMutex);
 
-    if (ret == DTLS_OK)
+    if (ret != DTLS_OK)
     {
-        OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
-        return CA_STATUS_OK;
+        OIC_LOG(ERROR, NET_DTLS_TAG, "OUT FAILURE");
+        return CA_STATUS_FAILED;
     }
 
-    OIC_LOG(ERROR, NET_DTLS_TAG, "OUT FAILURE");
-    return CA_STATUS_FAILED;
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
+    return CA_STATUS_OK;
 }
 
-
-CAResult_t CAAdapterNetDtlsDecrypt(const char *remoteAddress,
-                                   const uint16_t port,
-                                   uint8_t *data,
-                                   uint32_t dataLen,
-                                   eDtlsAdapterType_t adapterType)
+CAResult_t CAAdapterNetDtlsDecrypt(const CASecureEndpoint_t *sep,
+                                   uint8_t *data, uint32_t dataLen)
 {
     OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
+    VERIFY_NON_NULL_RET(sep, NET_DTLS_TAG, "endpoint is NULL" , CA_STATUS_INVALID_PARAM);
 
-    stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)OICCalloc(1, sizeof(stCADtlsAddrInfo_t));
-
-    VERIFY_NON_NULL_RET(addrInfo, NET_DTLS_TAG, "calloc failed" , CA_MEMORY_ALLOC_FAILED);
+    stCADtlsAddrInfo_t addrInfo = { 0 };
 
-    addrInfo->addr.sin.sin_family = AF_INET;
-    addrInfo->addr.sin.sin_port = htons(port);
+    CAConvertNameToAddr(sep->endpoint.addr, sep->endpoint.port, &(addrInfo.addr.st));
+    addrInfo.ifIndex = 0;
+    addrInfo.size = CASizeOfAddrInfo(&addrInfo);
 
-    // Conversion from ASCII format to Network format
-    if (inet_aton(remoteAddress, &addrInfo->addr.sin.sin_addr) == 0)
+    ca_mutex_lock(g_dtlsContextMutex);
+    if (NULL == g_caDtlsContext)
     {
-        OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address");
-        OICFree(addrInfo);
+        OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL");
+        ca_mutex_unlock(g_dtlsContextMutex);
         return CA_STATUS_FAILED;
     }
-    addrInfo->size = sizeof(addrInfo->addr);
-    addrInfo->ifIndex = adapterType;
 
-    eDtlsRet_t ret = CAAdapterNetDtlsDecryptInternal(addrInfo, data, dataLen);
+    eDtlsRet_t ret = CAAdapterNetDtlsDecryptInternal(&addrInfo, data, dataLen);
+    ca_mutex_unlock(g_dtlsContextMutex);
 
-    OICFree(addrInfo);
     if (DTLS_OK == ret || DTLS_HS_MSG == ret)
     {
         OIC_LOG_V(DEBUG, NET_DTLS_TAG, "Successfully Decrypted or Handshake msg recvd [%d]", ret);
@@ -667,4 +1177,3 @@ CAResult_t CAAdapterNetDtlsDecrypt(const char *remoteAddress,
     return CA_STATUS_FAILED;
 }
 
-