Add PKIX API for CA 08/2408/15
authorDmytro Zhuravlev <d.zhuravlev@samsung.com>
Tue, 8 Sep 2015 17:01:22 +0000 (20:01 +0300)
committerSachin Agrawal <sachin.agrawal@intel.com>
Tue, 15 Sep 2015 19:06:22 +0000 (19:06 +0000)
To support X.509 based DTLS in connectivity abstraction

Change-Id: Icea2f13e8fe7be2179dfac5d45b70e9b762c7eef
Signed-off-by: Dmytro Zhuravlev <d.zhuravlev@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2408
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Sachin Agrawal <sachin.agrawal@intel.com>
resource/csdk/connectivity/api/cainterface.h
resource/csdk/connectivity/inc/caadapternetdtls.h
resource/csdk/connectivity/inc/pkix/pki.h
resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c

index 9499cf4..bc2dc98 100644 (file)
@@ -35,6 +35,9 @@
 #ifdef __WITH_DTLS__
 #include "ocsecurityconfig.h"
 #endif
+#ifdef __WITH_X509__
+#include "pki.h"
+#endif //__WITH_X509__
 
 #ifdef __cplusplus
 extern "C"
@@ -87,6 +90,37 @@ typedef struct
 typedef void (*CAGetDTLSCredentialsHandler)(CADtlsPskCredsBlob_t **credInfo);
 #endif //__WITH_DTLS__
 
+#ifdef __WITH_X509__
+/**
+ * Binary structure containing certificate chain and certificate credentials
+ * for this device.
+ */
+typedef struct
+{
+    // certificate message  for DTLS
+    unsigned char certificateChain[MAX_CERT_MESSAGE_LEN];
+    // length of the certificate message
+    uint32_t  certificateChainLen;
+    // number of certificates in  certificate message
+    uint8_t   chainLen;
+    // x component of EC public key
+    uint8_t   rootPublicKeyX[PUBLIC_KEY_SIZE / 2];
+    // y component of EC public key
+    uint8_t   rootPublicKeyY[PUBLIC_KEY_SIZE / 2];
+    // EC private key
+    uint8_t   devicePrivateKey[PRIVATE_KEY_SIZE];
+
+} CADtlsCertCreds_t;
+
+/**
+ * @brief   Callback function type for getting certificate credentials.
+ * @param   credInfo          [OUT] Certificate credentials info. Handler has to allocate new memory for
+ *                                  credInfo which is then freed by CA
+ * @return  NONE
+ */
+typedef void (*CAGetCertCredentialsHandler)(CADtlsCertCreds_t *credInfo);
+#endif //__WITH_X509__
+
 /**
  * Initialize the connectivity abstraction module.
  * It will initialize adapters, thread pool and other modules based on the platform
@@ -139,6 +173,15 @@ void CARegisterHandler(CARequestCallback ReqHandler, CAResponseCallback RespHand
 CAResult_t CARegisterDTLSCredentialsHandler(CAGetDTLSCredentialsHandler GetDTLSCredentials);
 #endif //__WITH_DTLS__
 
+#ifdef __WITH_X509__
+/**
+ * @brief   Register callback to get DTLS Cert credentials.
+ * @param   GetCertCredentials   [IN] GetCert Credetials callback
+ * @return  #CA_STATUS_OK
+ */
+CAResult_t CARegisterCertCredentialsHandler(CAGetCertCredentialsHandler GetCertCredentials);
+#endif //__WITH_X509__
+
 /**
  * Create an endpoint description.
  * @param[in]   flags                 how the adapter should be used.
index d766451..1d2c351 100644 (file)
@@ -253,6 +253,13 @@ CAResult_t CAAdapterNetDtlsDecrypt(const CASecureEndpoint_t *sep,
                                    uint8_t *data,
                                    uint32_t dataLen);
 
+#ifdef __WITH_X509__
+/**
+ * @fn  CADeInitX509
+ * @brief  Deinitializes certificate based credential
+ */
+void CADeInitX509();
+#endif //__WITH_X509__
 #endif /* CA_ADAPTER_NET_DTLS_H_ */
 
 
index 23c6f50..221b6a9 100644 (file)
@@ -33,10 +33,15 @@ extern "C" {
 #include "cert.h"
 
 /**
- * Maximal lengths of certificate chain.
+ * Maximal number of certificates in trust chain.
  */
 #define MAX_CHAIN_LEN    (3)
 
+/**
+ * Maximal length of the TLS certificate message.
+ */
+#define MAX_CERT_MESSAGE_LEN (2048)
+
 #ifdef X509_DEBUG
 /**
  * Prints Certificate to console.
index 780a6aa..bc2dbd0 100644 (file)
 #include "global.h"
 #include <netdb.h>
 
+#ifdef __WITH_X509__
+#include "pki.h"
+#include "cainterface.h"
+#include "credresource.h"
+#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
  * @brief Logging tag for module name
@@ -772,6 +781,176 @@ CAResult_t CADtlsGenerateOwnerPSK(const CAEndpoint_t *endpoint,
     return CA_STATUS_OK;
 }
 
+#ifdef __WITH_X509__
+static CADtlsCertCreds_t g_X509Cred = {{0}, 0, 0, {0}, {0}, {0}};
+
+static int g_IsX509Init = 0;
+
+int CAInitX509()
+{
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CAInitX509");
+    g_IsX509Init = (OC_STACK_OK == GetDtlsCertCredentials(&g_X509Cred));
+
+    OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CAInitX509");
+    return !g_IsX509Init;
+}
+
+
+void CADeInitX509()
+{
+    g_IsX509Init = 0;
+}
+
+
+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;
+    if (!g_IsX509Init)
+    {
+        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;
+    if (!g_IsX509Init)
+    {
+        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;
+    if (!g_IsX509Init)
+    {
+        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];
+
+    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);
+
+
+    if (NULL != ctx->peers && DTLS_SERVER == ctx->peers->role )
+    {
+        stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session;
+        char peerAddr[MAX_ADDR_STR_SIZE_CA] = { 0 };
+        uint16_t port = 0;
+        CAConvertAddrToName(&(addrInfo->addr.st), peerAddr, &port);
+
+        CAResult_t result = CAAddIdToPeerInfoList(peerAddr, port,
+        crtChain[0].subject.data + crtChain[0].subject.len - sizeof(OicUuid_t), sizeof(OicUuid_t));
+        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");
@@ -836,8 +1015,18 @@ 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;
 
+#ifdef __WITH_X509__
+    CAInitX509();
+    if (g_IsX509Init == 0)
+#endif //__WITH_X509__
+    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");