svace fixes
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / adapter_util / ca_adapter_net_ssl.c
index 73831e4..ce4765a 100644 (file)
@@ -36,6 +36,7 @@
 #include "ocrandom.h"
 #include "byte_array.h"
 #include "octhread.h"
+#include "octypes.h"
 #include "timer.h"
 
 
  */
 #define UUID_LENGTH (128/8)
 /**
+ * @def UUID_STR_SIZE
+ * @brief Size of string representation RFC4122 based UUID.
+ * 32 chars for hex data and 4 '-' symbols.
+ */
+#define UUID_STR_SIZE (36)
+
+/**
  * @def MASTER_SECRET_LEN
  * @brief TLS master secret length
  */
@@ -519,6 +527,11 @@ static CAgetCredentialTypesHandler g_getCredentialTypesCallback = NULL;
 static CAgetPkixInfoHandler g_getPkixInfoCallback = NULL;
 
 /**
+ * Callback to inform in case of client's certificate absence
+ */
+static CertificateVerificationCallback_t g_CertificateVerificationCallback = NULL;
+
+/**
  * @var g_setupPkContextCallback
  *
  * @brief callback to setup PK context handler for H/W based Public Key Infrastructure
@@ -614,6 +627,20 @@ void CAsetCredentialTypesCallback(CAgetCredentialTypesHandler credTypesCallback)
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
 }
 
+void CAsetCertificateVerificationCallback(CertificateVerificationCallback_t certVerifyStatusCallback)
+{
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
+    g_CertificateVerificationCallback = certVerifyStatusCallback;
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+}
+
+void CAunsetCertificateVerificationCallback()
+{
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
+    g_CertificateVerificationCallback = NULL;
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+}
+
 static int GetAdapterIndex(CATransportAdapter_t adapter)
 {
     switch (adapter)
@@ -660,7 +687,7 @@ static int SendCallBack(void * tep, const unsigned char * data, size_t dataLen)
         else if ((size_t)sentLen != dataLen)
         {
             OIC_LOG_V(DEBUG, NET_SSL_TAG,
-                    "Packet was partially sent - total/sent/remained bytes : %zd/%zu/%lu",
+                    "Packet was partially sent - total/sent/remained bytes : %zd/%zu/%zu",
                     sentLen, dataLen, (dataLen - sentLen));
         }
     }
@@ -901,6 +928,10 @@ static int ParseChain(mbedtls_x509_crt * crt, unsigned char * buf, size_t bufLen
             else
             {
                 unsigned char * lastCert = (unsigned char *)OICMalloc((len + 1) * sizeof(unsigned char));
+                if (lastCert == NULL)
+                {
+                    goto exit;
+                }
                 memcpy(lastCert, buf + pos, len);
                 lastCert[len] = 0x00;
                 ret = mbedtls_x509_crt_parse(crt, lastCert, len + 1);
@@ -1333,6 +1364,35 @@ const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer)
 }
 #endif
 
+CAResult_t SetCASecureEndpointUuid(const CAEndpoint_t *peer, const char *uuid)
+{
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
+    VERIFY_NON_NULL(peer, NET_SSL_TAG, "peer");
+    VERIFY_NON_NULL(peer, NET_SSL_TAG, "uuid");
+
+    oc_mutex_lock(g_sslContextMutex);
+    SslEndPoint_t *sslPeer = GetSslPeer(peer);
+    if (NULL == sslPeer)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Peer not found");
+        oc_mutex_unlock(g_sslContextMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    OCRandomUuidResult ret = OCConvertStringToUuid(uuid, sslPeer->sep.identity.id);
+    oc_mutex_unlock(g_sslContextMutex);
+
+    if (RAND_UUID_OK != ret)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Failed to convert uuid");
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+
+    return CA_STATUS_OK;
+}
+
 /**
  * Deletes cached message.
  *
@@ -1410,9 +1470,9 @@ static void RemovePeerFromList(const CAEndpoint_t * endpoint)
                 && (endpoint->port == tep->sep.endpoint.port || CA_ADAPTER_GATT_BTLE == endpoint->adapter))
         {
             u_arraylist_remove(g_caSslContext->peerList, listIndex);
-            DeleteSslEndPoint(tep);
             OIC_LOG_V(INFO, NET_SSL_TAG, "Remove Peer:[%s:%d] for %d adapter",
                     endpoint->addr, endpoint->port, endpoint->adapter);
+            DeleteSslEndPoint(tep);
             OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
             return;
         }
@@ -1485,6 +1545,20 @@ CAResult_t CAcloseSslConnection(const CAEndpoint_t *endpoint)
     return CA_STATUS_OK;
 }
 
+#ifdef __TIZEN__
+CAResult_t CAcloseSslConnectionFreeEndpoint(CAEndpoint_t *endpoint)
+{
+    OIC_LOG_V(INFO, NET_SSL_TAG, "In %s", __func__);
+    VERIFY_NON_NULL_RET(endpoint, NET_SSL_TAG, "Param endpoint is NULL" , CA_STATUS_INVALID_PARAM);
+
+    CAResult_t ret = CAcloseSslConnection(endpoint);
+    OICFree(endpoint);
+
+    OIC_LOG_V(INFO, NET_SSL_TAG, "Out %s", __func__);
+    return ret;
+}
+#endif //__TIZEN__
+
 CAResult_t CAcloseSslConnectionUsingUuid(const uint8_t *identity, size_t idLength)
 {
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
@@ -1698,6 +1772,11 @@ static void SetupCipher(mbedtls_ssl_config * config, CATransportAdapter_t adapte
 
     memset(g_cipherSuitesList, 0, sizeof(g_cipherSuitesList));
 
+    if (SSL_CIPHER_MAX < g_caSslContext->cipher)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Maximum ciphersuite index exceeded");
+    }
+
     // Add the preferred ciphersuite first
     if (SSL_CIPHER_MAX != g_caSslContext->cipher)
     {
@@ -2318,6 +2397,83 @@ void CAsetSslHandshakeCallback(CAErrorCallback tlsHandshakeCallback)
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
 }
 
+/**
+ * Check RFC4122 based UUID
+ *
+ * @param uuidString    string representation of UUID
+ * @return true for success, otherwise false
+ */
+static bool CheckUuidFormat(const char uuidString[UUID_STR_SIZE])
+{
+    // Indexes of '-' symbols in string representation of UUID
+    static const int dash_idxs[4] = {8,13,18,23};
+
+    VERIFY_NON_NULL_RET(uuidString, NET_SSL_TAG, "uuidString is NULL" , false);
+
+    // Check for '-' symbols
+    for (int i = 0; i < 4; i++)
+    {
+        if (uuidString[dash_idxs[i]] != '-')
+        {
+            return false;
+        }
+    }
+
+    for (int i = 0; i < UUID_STR_SIZE; i++)
+    {
+        // Skip '-' symbols
+        if (i == dash_idxs[0] || i == dash_idxs[1] || i == dash_idxs[2] || i == dash_idxs[3])
+        {
+            continue;
+        }
+
+        if ((uuidString[i] >= 'a' && uuidString[i] <= 'f')
+                || (uuidString[i] >= 'A' && uuidString[i] <= 'F')
+                || (uuidString[i] >= '0' && uuidString[i] <= '9') )
+        {
+            continue;
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * FindUuid function finds the first entry of RFC4122 based UUID
+ *
+ * @param data  pointer to unformatted data
+ * @param size  data size
+ *
+ * @return pointer to string representation of the found UUID if success, otherwise NULL
+ */
+static const char* FindUuid(const char* data, size_t size)
+{
+    const char* result = NULL;
+
+    VERIFY_NON_NULL_RET(data, NET_SSL_TAG, "data is NULL" , NULL);
+    if (size < UUID_STR_SIZE)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Buffer size is too small");
+        return NULL;
+    }
+
+    const char* currentPtr = data;
+    int currentSize = size;
+    while (!result
+           && (currentPtr = (const char*)memchr((const void*)++currentPtr, '-', currentSize - 1))
+           && ((currentSize = (size - (currentPtr - data))) >= (UUID_STR_SIZE - 8)))
+    {
+        if (currentPtr - data >= 8 && CheckUuidFormat(currentPtr - 8))
+        {
+            result = currentPtr - 8;
+        }
+    }
+
+    return result;
+}
+
 /* Read data from TLS connection
  */
 CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t dataLen)
@@ -2327,6 +2483,12 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
     VERIFY_NON_NULL_RET(sep, NET_SSL_TAG, "endpoint is NULL" , CA_STATUS_INVALID_PARAM);
     VERIFY_NON_NULL_RET(data, NET_SSL_TAG, "Param data is NULL" , CA_STATUS_INVALID_PARAM);
 
+    if (0 == dataLen)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "dataLen is zero");
+        return CA_STATUS_FAILED;
+    }
+
     oc_mutex_lock(g_sslContextMutex);
     if (NULL == g_caSslContext)
     {
@@ -2335,7 +2497,6 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
         return CA_STATUS_FAILED;
     }
 
-
     SslEndPoint_t * peer = GetSslPeer(&sep->endpoint);
     if (NULL == peer)
     {
@@ -2383,15 +2544,14 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
                                                  sizeof(sep->endpoint.addr));
             ret = mbedtls_ssl_handshake_step(&peer->ssl);
         }
-        if (MBEDTLS_SSL_IS_CLIENT == peer->ssl.conf->endpoint)
+        uint32_t flags = mbedtls_ssl_get_verify_result(&peer->ssl);
+        if (0 != flags &&
+           ((MBEDTLS_SSL_IS_CLIENT == peer->ssl.conf->endpoint) ||
+            (MBEDTLS_SSL_IS_SERVER == peer->ssl.conf->endpoint && MBEDTLS_X509_BADCERT_MISSING != flags)))
         {
-            uint32_t flags = mbedtls_ssl_get_verify_result(&peer->ssl);
-            if (0 != flags)
-            {
-                OIC_LOG_BUFFER(ERROR, NET_SSL_TAG, (const uint8_t *) &flags, sizeof(flags));
-                SSL_CHECK_FAIL(peer, flags, "Cert verification failed", 1,
-                                                         CA_STATUS_FAILED, GetAlertCode(flags));
-            }
+            OIC_LOG_BUFFER(ERROR, NET_SSL_TAG, (const uint8_t *) &flags, sizeof(flags));
+            SSL_CHECK_FAIL(peer, flags, "Cert verification failed", 1,
+                                                     CA_STATUS_FAILED, GetAlertCode(flags));
         }
         SSL_CHECK_FAIL(peer, ret, "Handshake error", 1, CA_STATUS_FAILED, MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
         if (MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC == peer->ssl.state)
@@ -2417,21 +2577,34 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
             if (MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 != selectedCipher &&
                 MBEDTLS_TLS_ECDH_ANON_WITH_AES_128_CBC_SHA256 != selectedCipher)
             {
-                char uuid[UUID_LENGTH * 2 + 5] = {0};
-                void * uuidPos = NULL;
-                void * userIdPos = NULL;
                 const mbedtls_x509_crt * peerCert = mbedtls_ssl_get_peer_cert(&peer->ssl);
                 ret = (NULL == peerCert ? -1 : 0);
+                if (g_CertificateVerificationCallback)
+                {
+                    uint32_t flags = mbedtls_ssl_get_verify_result(&peer->ssl);
+                    if (!flags)
+                    {
+                        g_CertificateVerificationCallback(CA_CERTIFICATE_VERIFY_SUCCESS_MUTUAL);
+                    }
+                    else if (MBEDTLS_X509_BADCERT_MISSING == flags)
+                    {
+                        g_CertificateVerificationCallback(CA_CERTIFICATE_VERIFY_NO_CERT);
+                    }
+                    else
+                    {
+                        g_CertificateVerificationCallback(CA_CERTIFICATE_VERIFY_FAILED);
+                    }
+                }
                 //SSL_CHECK_FAIL(peer, ret, "Failed to retrieve cert", 1,
                 //                            CA_STATUS_FAILED, MBEDTLS_SSL_ALERT_MSG_NO_CERT);
                 if (0 == ret)
                 {
-                    uuidPos = memmem(peerCert->subject_raw.p, peerCert->subject_raw.len,
-                                                     UUID_PREFIX, sizeof(UUID_PREFIX) - 1);
-
-                    if (NULL != uuidPos)
+                    const char* uuidptr = FindUuid((const char*)peerCert->subject_raw.p, peerCert->subject_raw.len);
+                    if (uuidptr)
                     {
-                        memcpy(uuid, (char*) uuidPos + sizeof(UUID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
+                        char uuid[UUID_STR_SIZE + 1] = {0};
+                        strncpy(uuid, uuidptr, UUID_STR_SIZE);
+                        uuid[UUID_STR_SIZE] = '\0';
                         OIC_LOG_V(DEBUG, NET_SSL_TAG, "certificate uuid string: %s" , uuid);
                         ret = OCConvertStringToUuid(uuid, peer->sep.identity.id);
                         SSL_CHECK_FAIL(peer, ret, "Failed to convert subject", 1,
@@ -2441,20 +2614,6 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
                     {
                         OIC_LOG(WARNING, NET_SSL_TAG, "uuid not found");
                     }
-
-                    userIdPos = memmem(peerCert->subject_raw.p, peerCert->subject_raw.len,
-                                                 USERID_PREFIX, sizeof(USERID_PREFIX) - 1);
-                    if (NULL != userIdPos)
-                    {
-                        memcpy(uuid, (char*) userIdPos + sizeof(USERID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
-                        ret = OCConvertStringToUuid(uuid, peer->sep.userId.id);
-                        SSL_CHECK_FAIL(peer, ret, "Failed to convert subject alt name", 1,
-                                          CA_STATUS_FAILED, MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT);
-                    }
-                    else
-                    {
-                        OIC_LOG(WARNING, NET_SSL_TAG, "Subject alternative name not found");
-                    }
                 }
             }