[IOT-2632] Callback to check peer's CN 31/22231/20 1.3.1-RC3
authorOleksii Beketov <ol.beketov@samsung.com>
Thu, 12 Oct 2017 10:33:15 +0000 (13:33 +0300)
committerRandeep Singh <randeep.s@samsung.com>
Fri, 13 Oct 2017 11:09:17 +0000 (11:09 +0000)
Added callback to check peer's certificate Common Name field.

Change-Id: Idb316438a76d70fcc7a91a2e119aadd0c771bde6
Signed-off-by: akk0rd <v.riznyk@samsung.com>
Signed-off-by: Oleksii Beketov <ol.beketov@samsung.com>
resource/csdk/connectivity/api/casecurityinterface.h
resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c
resource/csdk/connectivity/test/ssladapter_test.cpp
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/sample/provisioningclient.c
resource/csdk/security/provisioning/sample/sampleserver_mfg.cpp
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/stack/octbstack_product_secured.def

index 6f9ad80..dbf0044 100644 (file)
@@ -124,6 +124,28 @@ typedef struct
     ByteArray_t crl;    /**< trusted CRLs as binary-encoded DER */
 } PkiInfo_t;
 
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+/**
+ * Callback is used by application layer to check peer's certificate CN field.
+ * If set, this callback will be invoked during handshake after certificate verification.
+ *
+ * @param[out] cn     peer's certificate Common Name field.
+ *                    If common name was not found, cn will be set to NULL.
+ * @param[out] cnLen  peer's certificate Common Name field length.
+ *                    If CN was not found, cnLen will be set to 0.
+ *
+ * @return  CA_STATUS_OK or CA_STATUS_FAIL. In case CA_STATUS_FAIL is returned,
+ *          handshake will be dropped.
+ */
+typedef CAResult_t (*PeerCNVerifyCallback)(const unsigned char *cn, size_t cnLen);
+
+/**
+ * API to set callback that checks peer's certificate Common Name field
+ * @param[in] cb callback to utilize certificate Common Name field
+ */
+void CAsetPeerCNVerifyCallback(PeerCNVerifyCallback cb);
+#endif
+
 /**
  * Register callback to get types of TLS suites.
  * @param[in]   getCredTypesHandler    Get types of TLS suites callback.
index 87cd3a5..361f2e3 100644 (file)
@@ -418,6 +418,13 @@ static oc_mutex g_sslContextMutex = NULL;
  */
 static CAHandshakeErrorCallback g_sslCallback = NULL;
 
+/**
+ * @var g_peerCNVerifyCallback
+ *
+ * @brief callback to utilize peer certificate information
+ */
+static PeerCNVerifyCallback g_peerCNVerifyCallback = NULL;
+
 /**
  * Data structure for holding the data to be received.
  */
@@ -458,6 +465,7 @@ void CAsetPkixInfoCallback(CAgetPkixInfoHandler infoCallback)
     g_getPkixInfoCallback = infoCallback;
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
 }
+
 void CAsetCredentialTypesCallback(CAgetCredentialTypesHandler credTypesCallback)
 {
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
@@ -465,6 +473,17 @@ void CAsetCredentialTypesCallback(CAgetCredentialTypesHandler credTypesCallback)
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
 }
 
+void CAsetPeerCNVerifyCallback(PeerCNVerifyCallback cb)
+{
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "IN %s", __func__);
+    if (NULL == cb)
+    {
+        OIC_LOG(DEBUG, NET_SSL_TAG, "UNSET peerCNVerifyCallback");
+    }
+    g_peerCNVerifyCallback = cb;
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "OUT %s", __func__);
+}
+
 /**
  * Sets SSL result for callback.
  *
@@ -483,6 +502,43 @@ static CAResult_t notifySubscriber(SslEndPoint_t* peer, CAResult_t status)
     return result;
 }
 
+static CAResult_t PeerCertExtractCN(const mbedtls_x509_crt *peerCert)
+{
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "IN %s", __func__);
+
+    CAResult_t res = CA_STATUS_OK;
+
+    mbedtls_asn1_named_data *subject = (mbedtls_asn1_named_data *)&(peerCert->subject);
+    while (NULL != subject)
+    {
+        if (0 == MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &(subject->oid)))
+        {
+            break;
+        }
+        subject = subject->next;
+    }
+
+    if (NULL != g_peerCNVerifyCallback)
+    {
+        if (NULL != subject)
+        {
+            res = g_peerCNVerifyCallback(subject->val.p, subject->val.len);
+        }
+        else
+        {
+            OIC_LOG(DEBUG, NET_SSL_TAG, "Common Name not found");
+            res = g_peerCNVerifyCallback(NULL, 0);
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, NET_SSL_TAG, "g_peerCNVerifyCallback is not set");
+    }
+
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "OUT %s", __func__);
+    return res;
+}
+
 static int GetAdapterIndex(CATransportAdapter_t adapter)
 {
     switch (adapter)
@@ -2038,7 +2094,6 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, size_t dat
         return CA_STATUS_FAILED;
     }
 
-
     SslEndPoint_t * peer = GetSslPeer(&sep->endpoint);
     if (NULL == peer)
     {
@@ -2109,6 +2164,23 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, size_t dat
             OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
             return CA_STATUS_FAILED;
         }
+
+        if (MBEDTLS_SSL_CERTIFICATE_VERIFY == peer->ssl.state)
+        {
+            mbedtls_x509_crt *peerCert = peer->ssl.session_negotiate->peer_cert;
+            if (NULL != peerCert)
+            {
+                ret = PeerCertExtractCN(peerCert);
+                if (CA_STATUS_OK != ret)
+                {
+                    oc_mutex_unlock(g_sslContextMutex);
+                    OIC_LOG_V(ERROR, NET_SSL_TAG, "ProcessPeerCert failed with %d", ret);
+                    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+                    return CA_STATUS_FAILED;
+                }
+            }
+        }
+
         if (MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC == peer->ssl.state)
         {
             memcpy(peer->master, peer->ssl.session_negotiate->master, sizeof(peer->master));
index 09acbfa..1d54125 100644 (file)
@@ -48,6 +48,7 @@
 #define GetCASecureEndpointData GetCASecureEndpointDataTest
 #define SetCASecureEndpointAttribute SetCASecureEndpointAttributeTest
 #define GetCASecureEndpointAttributes GetCASecureEndpointAttributesTest
+#define CAsetPeerCNVerifyCallback CAsetPeerCNVerifyCallbackTest
 
 #include "../src/adapter_util/ca_adapter_net_ssl.c"
 
index 1853072..e3c2738 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "octypes.h"
 #include "pmtypes.h"
+#include "casecurityinterface.h"
 #include "ownershiptransfermanager.h"
 #ifdef MULTIPLE_OWNER
 #include "experimental/securevirtualresourcetypes.h"
@@ -690,6 +691,18 @@ OCStackResult OC_CALL OCReadTrustCertChain(uint16_t credId, uint8_t **trustCertC
 OCStackResult OC_CALL OCSelectOwnershipTransferMethod(const OicSecOxm_t *supportedMethods,
         size_t numberOfMethods, OicSecOxm_t *selectedMethod, OwnerType_t ownerType);
 
+/**
+ * Function to set callback to check peer's Common Name field.
+ *
+ * @param[in] cb callback to utilize peer's certificate Common Name information.
+ *            If set, callback is invoked during handshake after certificate
+ *            verification. It takes peer's certificate CN field and provides
+ *            it to application level. Application is to decide whether CN is
+ *            valid or not. In case CA_STATUS_FAIL is returned, handshake will
+ *            be dropped.
+ */
+void OC_CALL OCSetPeerCNVerifyCallback(PeerCNVerifyCallback cb);
+
 #endif // __WITH_DTLS__ || __WITH_TLS__
 
 
index d59dc42..363c87d 100644 (file)
@@ -2509,6 +2509,20 @@ static FILE* fopen_prvnMng(const char* path, const char* mode)
     }
 }
 
+static CAResult_t peerCNVerifyCallback(const unsigned char *cn, size_t cnLen)
+{
+    if (NULL != cn && 0 != cnLen)
+    {
+        OIC_LOG(INFO, TAG, "peer certificate CN: ");
+        OIC_LOG_BUFFER(INFO, TAG, cn, cnLen);
+        return CA_STATUS_OK;
+    }
+    else
+    {
+        return CA_STATUS_FAILED;
+    }
+}
+
 static int waitCallbackRet(void)
 {
     for (int i = 0; !g_doneCB && (CALLBACK_TIMEOUT > i); ++i)
@@ -2742,6 +2756,9 @@ int main()
     SetDisplayNumCB(NULL, displayNumCB);
     SetUserConfirmCB(NULL, confirmNumCB);
 
+    // set callback for checking peer certificate information
+    OCSetPeerCNVerifyCallback(peerCNVerifyCallback);
+
 #ifdef MULTIPLE_OWNER
     SetPreconfigPin("12341234", 8);
 #endif //MULTIPLE_OWNER
index 00fab0c..c081220 100644 (file)
@@ -33,6 +33,7 @@
 #include <signal.h>
 #include "ocstack.h"
 #include "ocpayload.h"
+#include "ocprovisioningmanager.h"
 
 #ifdef HAVE_WINDOWS_H
 #include <windows.h>
@@ -416,6 +417,20 @@ FILE* server_fopen(const char *path, const char *mode)
     }
 }
 
+static CAResult_t peerCNVerifyCallback(const unsigned char *cn, size_t cnLen)
+{
+    if (NULL != cn && 0 != cnLen)
+    {
+        OIC_LOG(INFO, TAG, "peer certificate CN: ");
+        OIC_LOG_BUFFER(INFO, TAG, cn, cnLen);
+        return CA_STATUS_OK;
+    }
+    else
+    {
+        return CA_STATUS_FAILED;
+    }
+}
+
 int main()
 {
     struct timespec timeout;
@@ -427,6 +442,9 @@ int main()
 
     OCRegisterPersistentStorageHandler(&ps);
 
+    // set callback for checking peer certificate information
+    OCSetPeerCNVerifyCallback(peerCNVerifyCallback);
+
     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
     {
         OIC_LOG(ERROR, TAG, "OCStack init error");
index 17835a7..26361ea 100644 (file)
@@ -1581,5 +1581,15 @@ void OC_CALL OCRemoveTrustCertChainNotifier()
 {
     SRPRemoveTrustCertChainNotifier();
 }
+
+/**
+ * Function to set the callback to utilize peer certificate Common Name field
+ */
+void OC_CALL OCSetPeerCNVerifyCallback(PeerCNVerifyCallback cb)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+    CAsetPeerCNVerifyCallback(cb);
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+}
 #endif // __WITH_DTLS__ || __WITH_TLS__
 
index 9b3f8c3..2bc6408 100644 (file)
@@ -51,6 +51,7 @@ OCSelectOwnershipTransferMethod
 OCSaveOwnRoleCert
 OCSetOwnerTransferCallbackData
 OCSetOxmAllowStatus
+OCSetPeerCNVerifyCallback
 OCUnlinkDevices
 OCVerifyCSRSignature