Updated security config blob for extensibility
authorSachin Agrawal <sachin.agrawal@intel.com>
Mon, 2 Feb 2015 20:26:18 +0000 (12:26 -0800)
committerSudarshan Prasad <sudarshan.prasad@intel.com>
Mon, 9 Feb 2015 22:04:45 +0000 (22:04 +0000)
Until now, security blob could contain only PSK credentials.
New features such as bootstrapping and certificate support would
require us to store different types of blob in configuration blob.
This change is an attempt to extend configuration blob format into
a TLV(Type-Length-Value) format which can be useful for multiple
purposes.

Change-Id: Icbc3d07ccae59579420276dbf5376f939c9bf7a4
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/242
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Doug Hudson <douglas.hudson@intel.com>
Reviewed-by: Sashi Penta <sashi.kumar.penta@intel.com>
Reviewed-by: Sudarshan Prasad <sudarshan.prasad@intel.com>
resource/csdk/security/include/internal/ocsecurityinternal.h
resource/csdk/security/include/ocsecurity.h
resource/csdk/security/include/ocsecurityconfig.h
resource/csdk/security/src/ocsecurity.c
resource/csdk/stack/samples/linux/secure/common.cpp
resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp

index 6a2f638604e23d0f421dcea2e8f79045ea23b85c..8f09546ad145818324a30d6190982a4a81e4bef1 100644 (file)
@@ -27,6 +27,9 @@
  * This callback is used by lower stack (i.e. CA layer) to retrieve PSK
  * credentials from RI security layer.
  *
+ * Note: When finished, caller should initialize memory to zeroes and
+ * invoke OCFree to delete @p credInfo.
+ *
  * @param credInfo
  *     binary blob containing PSK credentials
  *
index 16f42b7fad59f3efc5d756031f93065f9625c95d..eceaabbf10041a3d0303213a37d9b582836bd32c 100644 (file)
@@ -30,16 +30,16 @@ extern "C" {
 #endif // __cplusplus
 
 /**
- * Provides the DTLS PSK credetials blob to OC stack.
+ * Provides the Security Configuration data to OC stack.
  *
- * @param credInfo
- *     binary blob containing credentials
+ * @param cfgData
+ *     binary blob containing config data
  * @param len
  *     length of binary blob
  *
  * @retval OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult OCSetDtlsPskCredentials(const OCDtlsPskCredsBlob *credInfo,
+OCStackResult OCSecSetConfigData(const OCSecConfigData *cfgData,
                 size_t len);
 
 #ifdef __cplusplus
index c18e9f707503cd13bb87011f2aa960b4f7327a26..8b3bda83ef2a0c1d3ef3faa9a5feeec65a07d837 100644 (file)
 #define DTLS_PSK_ID_LEN 16
 #define DTLS_PSK_PSK_LEN 16
 
-#define DtlsPskCredsBlobVer_1 1 /**< Credentials stored in plaintext */
-#define DtlsPskCredsBlobVer_CurrentVersion DtlsPskCredsBlobVer_1
+#define OCSecConfigVer_1 1 /**< Initial version supporting PSK Credentials */
+#define OCSecConfigVer_CurrentVersion OCSecConfigVer_1
+
+typedef enum{
+    OC_BLOB_TYPE_PSK = 1,   /**< Security blob holding PSK data */
+} OCBlobType;
+
 
 /**
- * Credentials for a device. Includes identity and the associated PSK.
+ * Credentials of a peer device. Includes identity and the associated PSK.
  */
 typedef struct
 {
-   unsigned char id[DTLS_PSK_ID_LEN];
-   unsigned char psk[DTLS_PSK_PSK_LEN];
+    unsigned char id[DTLS_PSK_ID_LEN];      /**< identity of the peer device */
+    unsigned char psk[DTLS_PSK_PSK_LEN];    /**< psk of the peer device */
 } OCDtlsPskCreds;
 
 
@@ -45,15 +50,53 @@ typedef struct
  */
 typedef struct
 {
-   uint16_t blobVer;                        /**< version of the blob */
-   uint16_t reserved;                       /**< reserved for future use */
-   unsigned char identity[DTLS_PSK_ID_LEN]; /**< identity of self */
-   uint32_t num;                            /**< number of credentials in this blob */
-   OCDtlsPskCreds creds[1];                 /**< list of credentials. Size of this
+    unsigned char identity[DTLS_PSK_ID_LEN]; /**< identity of self */
+    uint32_t num;                            /**< number of credentials in this blob */
+    OCDtlsPskCreds creds[1];                 /**< list of credentials. Size of this
                                                  array is determined by 'num' variable. */
 } OCDtlsPskCredsBlob;
 
 
+/**
+ * Generic definition of a security blob. A security blob can contain
+ * info of various types, such as : PSK info, certificates,
+ * access control lists(ACL) etc.
+ */
+typedef struct
+{
+    uint16_t  type;     /**< Type of blob */
+    uint16_t  len;   /**< length of blob data */
+    uint8_t   val[1];   /**< A variable size array holding blob data */
+} OCSecBlob;
+
+
+/**
+ * This structure defines the security related configuration data for
+ * Iotivity applications.
+ */
+typedef struct
+{
+   uint16_t    version;  /**< version of the config data */
+   uint16_t    numBlob;  /**< number of security blobs in this config data */
+   uint8_t     blob[1];  /**< A variable size array holding a blob */
+} OCSecConfigData;
+
+/**
+ * Interprets @p blob as pointer to a OCSecBlob and advances to
+ * the next blob in the OCSecConfigData
+ */
+#define config_data_next_blob(blob) \
+            ((OCSecBlob*)((blob)->val + (blob)->len));
+
+/**
+ * Configuration data for security will be stored in below fashion in a
+ * flat file on persistent storage.
+ *
+ *  --------------------------------------------------------------
+ *  | OCSecConfigData| OCSecBlob #1 | OCSecBlob #2 | OCSecBlob #3|
+ *  --------------------------------------------------------------
+ */
+
 #endif //OC_SECURITY_CONFIG_H
 
 
index 327bfc9a0d60461c8c0320ffdf7c138dc3b9a2e9..98187fe1ad972c7614d81fe88b5b87104b7d9e85 100644 (file)
 #include "ocsecurityconfig.h"
 #include <string.h>
 
-static OCDtlsPskCredsBlob* pskCredsBlob;
-static int pskCredsBlobLen;
+static OCSecConfigData* secConfigData;
+static int secConfigDataLen;
 
-// Internal API. Invoked by OC stack to cleanup memory
+/**
+ * This internal API removes/clears the global variable holding the security
+ * config data. This needs to be invoked when OIC stack is shutting down.
+ *
+ * @retval none
+ */
 void DeinitOCSecurityInfo()
 {
-    if (pskCredsBlob)
+    if (secConfigData)
     {
         // Initialize sensitive data to zeroes before freeing.
-        memset(pskCredsBlob, 0, pskCredsBlobLen);
+        memset(secConfigData, 0, secConfigDataLen);
 
-        OCFree(pskCredsBlob);
-        pskCredsBlob = NULL;
+        OCFree(secConfigData);
+        secConfigData = NULL;
     }
 }
 
-// Internal API. Invoked by OC stack to retrieve credentials from this module
+/**
+ * This internal callback is used by lower stack (i.e. CA layer) to
+ * retrieve PSK credentials from RI security layer.
+ *
+ * Note: When finished, caller should initialize memory to zeroes and
+ * invoke OCFree to delete @p credInfo.
+ *
+ * @param credInfo
+ *     binary blob containing PSK credentials
+ *
+ * @retval none
+ */
 void GetDtlsPskCredentials(OCDtlsPskCredsBlob **credInfo)
 {
-    *credInfo = pskCredsBlob;
+    if(secConfigData && credInfo)
+    {
+        unsigned int i = 0;
+        OCSecBlob * osb = (OCSecBlob*)secConfigData->blob;
+        for ( ;(i<secConfigData->numBlob) && osb; i++)
+        {
+            if (osb->type == OC_BLOB_TYPE_PSK)
+            {
+                OCDtlsPskCredsBlob * blob;
+                blob = (OCDtlsPskCredsBlob *)OCMalloc(osb->len);
+                if (blob)
+                {
+                    memcpy(blob, osb->val, osb->len);
+                    *credInfo = blob;
+                    break;
+                }
+            }
+            osb = config_data_next_blob(osb);
+        }
+    }
 }
 
+
 /**
- * Provides the DTLS PSK credetials blob to OC stack.
+ * This method validates the sanctity of OCDtlsPskCredsBlob.
  *
- * @param credInfo
- *     binary blob containing credentials
+ * @param secBlob
+ *     binary blob containing PSK credentials
+ *
+ * @retval OC_STACK_OK for Success, otherwise some error value
+ */
+static
+OCStackResult ValidateBlobTypePSK(const OCSecBlob *secBlob)
+{
+    OCDtlsPskCredsBlob *pskCredsBlob;
+    uint16_t validLen;
+
+    if(secBlob->len == 0)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    pskCredsBlob = (OCDtlsPskCredsBlob *)secBlob->val;
+
+    //calculate the expected length of PSKCredsBlob
+    if(pskCredsBlob->num >= 1)
+    {
+        validLen = sizeof(OCDtlsPskCredsBlob) +
+            (pskCredsBlob->num - 1) * sizeof(OCDtlsPskCredsBlob);
+    }
+    else
+    {
+        validLen = sizeof(OCDtlsPskCredsBlob);
+    }
+
+    if(secBlob->len != validLen)
+        return OC_STACK_INVALID_PARAM;
+
+    return OC_STACK_OK;
+}
+
+
+/**
+ * This method validates the sanctity of configuration data provided
+ * by application to OC stack.
+ *
+ * @param cfgdata
+ *     binary blob containing credentials and other config data
  * @param len
  *     length of binary blob
  *
  * @retval OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult OCSetDtlsPskCredentials(const OCDtlsPskCredsBlob *credInfo,
+static
+OCStackResult ValidateSecConfigData(const OCSecConfigData *cfgData,
                 size_t len)
 {
-    if(credInfo && len > 0)
+    OCStackResult ret = OC_STACK_OK;
+    unsigned int i = 0;
+    OCSecBlob * osb = NULL;
+
+    if (!cfgData || (len == 0))
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (cfgData->version != OCSecConfigVer_CurrentVersion)
     {
-        if (credInfo->blobVer != DtlsPskCredsBlobVer_CurrentVersion)
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    osb = (OCSecBlob*)cfgData->blob;
+    for ( ;(i<cfgData->numBlob) && osb; i++)
+    {
+        if (osb->type == OC_BLOB_TYPE_PSK)
+        {
+            ret = ValidateBlobTypePSK(osb);
+        }
+        else
         {
             return OC_STACK_INVALID_PARAM;
         }
 
+        if (ret != OC_STACK_OK)
+        {
+            return ret;
+        }
+        osb = config_data_next_blob(osb);
+    }
+
+    return ret;
+}
+
+
+
+/**
+ * Provides the Security configuration data to OC stack.
+ *
+ * @param cfgdata
+ *     binary blob containing credentials and other config data
+ * @param len
+ *     length of binary blob
+ *
+ * @retval OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult OCSecSetConfigData(const OCSecConfigData *cfgData,
+                size_t len)
+{
+    // Validate the data inside blob before consuming
+    if (cfgData && ValidateSecConfigData(cfgData, len) == OC_STACK_OK)
+    {
         // Remove existing blob
         DeinitOCSecurityInfo();
         // Allocate storage for new blob
-        pskCredsBlob = (OCDtlsPskCredsBlob*)OCMalloc(len);
-        if (pskCredsBlob)
+        secConfigData = (OCSecConfigData*)OCMalloc(len);
+        if (secConfigData)
         {
-            memcpy(pskCredsBlob, credInfo, len);
-            pskCredsBlobLen = len;
+            memcpy(secConfigData, cfgData, len);
+            secConfigDataLen = len;
             return OC_STACK_OK;
         }
 
index 16dd8a874bd4454e089d426ae104549f16fc1a75..ebd6c646b7c9888594803442da8457a4baf561f7 100644 (file)
@@ -46,7 +46,7 @@ OCStackResult SetCredentials(const char* filename) {
                 if (fread(data, 1, st.st_size, fp) == (size_t)st.st_size)
                 {
                     // Provide credentials to OC Stack
-                    ret = OCSetDtlsPskCredentials((OCDtlsPskCredsBlob *)data,
+                    ret = OCSecSetConfigData((OCSecConfigData *)data,
                             st.st_size);
                 }
                 else
index 2a259aca12f83da5ad5969de88d62e95843edf5c..89b8369acc0a2810cabd8376a12e2f87d18862c3 100644 (file)
 #include <time.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 
 #define TAG "gen_sec_bin"
 
-void printStruct(const char * device, OCDtlsPskCredsBlob* s)
+//scratch buffer
+const int WORK_BUF_LEN = 512;
+
+const char SERVER_CRED_FILE[] = "server_cred.bin";
+const char CLIENT_CRED_FILE[] = "client_cred.bin";
+
+static void printStruct(const char * device, OCSecConfigData* s)
 {
-    OC_LOG(INFO, TAG, device);
-    OC_LOG_V(INFO, TAG, "Version - %d", s->blobVer);
-    OC_LOG(INFO, TAG, "My Identity :");
-    OC_LOG_BUFFER(INFO, TAG, s->identity, DTLS_PSK_ID_LEN);
-
-    OC_LOG_V(INFO, TAG, "Number of trusted Peers  - %d", s->num);
-    OC_LOG(INFO, TAG, "Peer Identity :");
-    OC_LOG_BUFFER(INFO, TAG, s->creds[0].id, DTLS_PSK_ID_LEN);
-    OC_LOG(INFO, TAG, "Peer Psk :");
-    OC_LOG_BUFFER(INFO, TAG, s->creds[0].psk, DTLS_PSK_PSK_LEN);
+    if (device && s)
+    {
+        OC_LOG(INFO, TAG, device);
+        OC_LOG_V(INFO, TAG, "Version - %d", s->version);
+        OC_LOG_V(INFO, TAG, "Number of blobs - %d", s->numBlob);
+
+        OCSecBlob* osb = (OCSecBlob*)(s->blob);
+        OC_LOG_V(INFO, TAG, "Blob Type - %d", osb->type);
+        OC_LOG_V(INFO, TAG, "Blob Data Length - %d", osb->len);
+
+        OCDtlsPskCredsBlob* odpcb = (OCDtlsPskCredsBlob*)(osb->val);
+        OC_LOG(INFO, TAG, "My Identity :");
+        OC_LOG_BUFFER(INFO, TAG, odpcb->identity, DTLS_PSK_ID_LEN);
+
+        OC_LOG_V(INFO, TAG, "Number of trusted Peers  - %d", odpcb->num);
+        OC_LOG(INFO, TAG, "Peer Identity :");
+        OC_LOG_BUFFER(INFO, TAG, odpcb->creds[0].id, DTLS_PSK_ID_LEN);
+        OC_LOG(INFO, TAG, "Peer Psk :");
+        OC_LOG_BUFFER(INFO, TAG, odpcb->creds[0].psk, DTLS_PSK_PSK_LEN);
+    }
 }
 
 
-int main()
+static int SizeOfOCConfigData (OCSecConfigData *oscd)
 {
-    OCDtlsPskCredsBlob * s = NULL;
-    OCDtlsPskCredsBlob * c = NULL;
-    FILE* fps, *fpc;
+    int len = 0;
+    if(oscd)
+    {
+        int i = 0;
+        OCSecBlob * osb;
+        len = len + sizeof(OCSecConfigData) - sizeof(uint8_t);
+
+        //go to first blob
+        osb = (OCSecBlob*)(oscd->blob);
+        for( i =0; i < oscd->numBlob; i++)
+        {
+            len += (sizeof(OCSecBlob) - sizeof(uint8_t) + osb->len);
+            osb = config_data_next_blob(osb);
+        }
+    }
+    return len;
+}
 
-    int i;
+int main()
+{
+    unsigned char buf_s[WORK_BUF_LEN];
+    unsigned char buf_c[WORK_BUF_LEN];
 
     srand(time(NULL));
 
-    s = (OCDtlsPskCredsBlob*) malloc(sizeof(OCDtlsPskCredsBlob));
-    c = (OCDtlsPskCredsBlob*) malloc(sizeof(OCDtlsPskCredsBlob));
+    OCSecConfigData * oscd_s = (OCSecConfigData*)buf_s;
+    OCSecConfigData * oscd_c = (OCSecConfigData*)buf_c;
+    oscd_s->version = oscd_c->version = OCSecConfigVer_CurrentVersion;
 
-    memset(s, 0, sizeof(OCDtlsPskCredsBlob));
-    memset(c, 0, sizeof(OCDtlsPskCredsBlob));
+    //Only storing 1 blob of type 'OC_BLOB_TYPE_PSK'
+    oscd_s->numBlob = oscd_c->numBlob = 1;
 
-    s->blobVer = DtlsPskCredsBlobVer_CurrentVersion;
-    c->blobVer = DtlsPskCredsBlobVer_CurrentVersion;
+    OCSecBlob * osb_s = (OCSecBlob*)oscd_s->blob;
+    OCSecBlob * osb_c = (OCSecBlob*)oscd_c->blob;
+    osb_s->type = osb_c->type = OC_BLOB_TYPE_PSK;
+    //length of this blob will be the length to contain PSK credentials
+    // for '1' peer device
+    osb_s->len = osb_c->len = sizeof(OCDtlsPskCredsBlob);
 
-    s->num = c->num = 1;
+    OCDtlsPskCredsBlob * odpcb_s = (OCDtlsPskCredsBlob*)(osb_s->val);
+    OCDtlsPskCredsBlob * odpcb_c = (OCDtlsPskCredsBlob*)(osb_c->val);
 
-    for(i = 0; i < DTLS_PSK_ID_LEN; i++)
+    odpcb_s->num = odpcb_c->num = 1;
+
+    for(int i = 0; i < DTLS_PSK_ID_LEN; i++)
     {
-        c->creds[0].id[i] = s->identity[i] = rand() % (2^8);
+        odpcb_c->creds[0].id[i] = odpcb_s->identity[i] = rand() % (2^8);
 
-        s->creds[0].id[i] = c->identity[i] = rand() % (2^8);
+        odpcb_s->creds[0].id[i] = odpcb_c->identity[i] = rand() % (2^8);
 
-        c->creds[0].psk[i] = s->creds[0].psk[i] = rand() % (2^8);
+        odpcb_c->creds[0].psk[i] = odpcb_s->creds[0].psk[i] = rand() % (2^8);
     }
 
     // Print Credentials
-    printStruct("Server", s);
-    printStruct("Client", c);
+    printStruct("Server", oscd_s);
+    printStruct("Client", oscd_c);
 
     // Write to files
+    FILE* fps, *fpc;
     if ((fps = (FILE*) fopen("server_cred.bin", "wb")) != NULL)
     {
-        fwrite(s, sizeof(OCDtlsPskCredsBlob), 1, fps);
+        fwrite(oscd_s, SizeOfOCConfigData(oscd_s), 1, fps);
         fclose(fps);
     }
 
 
     if ((fpc = (FILE*) fopen("client_cred.bin", "wb")) != NULL)
     {
-        fwrite(c, sizeof(OCDtlsPskCredsBlob), 1, fpc);
+        fwrite(oscd_c, SizeOfOCConfigData(oscd_c), 1, fps);
         fclose(fpc);
     }
 
-    memset(s, 0, sizeof(OCDtlsPskCredsBlob));
-    memset(c, 0, sizeof(OCDtlsPskCredsBlob));
+    struct stat st;
+    memset(buf_s, 0, sizeof(buf_s));
+    memset(buf_c, 0, sizeof(buf_c));
     // Read from files; print and verify manually
-    if ((fps = (FILE*) fopen("server_cred.bin", "rb")) != NULL)
+    if ((fps = (FILE*) fopen(SERVER_CRED_FILE, "rb")) != NULL)
     {
-        if (sizeof(OCDtlsPskCredsBlob) != fread(s, 1, sizeof(OCDtlsPskCredsBlob), fps))
+        stat(SERVER_CRED_FILE, &st);
+        if ((sizeof(buf_s) < (unsigned int)st.st_size) ||
+            (fread(buf_s, 1, st.st_size, fps) != (unsigned int)st.st_size))
         {
             OC_LOG(INFO, TAG, PCF("Reading from the file failed."));
         }
@@ -103,9 +149,11 @@ int main()
     }
 
 
-    if ((fpc = (FILE*) fopen("client_cred.bin", "rb")) != NULL)
+    if ((fpc = (FILE*) fopen(CLIENT_CRED_FILE, "rb")) != NULL)
     {
-        if (sizeof(OCDtlsPskCredsBlob) != fread(c, 1, sizeof(OCDtlsPskCredsBlob), fpc))
+        stat(CLIENT_CRED_FILE, &st);
+        if ((sizeof(buf_c) < (unsigned int)st.st_size) ||
+            (fread(buf_c, 1, st.st_size, fpc) != (unsigned int)st.st_size))
         {
             OC_LOG(INFO, TAG, PCF("Reading from the file failed."));
         }
@@ -114,10 +162,8 @@ int main()
 
     printf("\n\n");
     OC_LOG(INFO, TAG, PCF("Reading from file and printing again to verify manually"));
-    printStruct("Server", s);
-    printStruct("Client", c);
+    printStruct("Server", (OCSecConfigData*)buf_s);
+    printStruct("Client", (OCSecConfigData*)buf_c);
 
-    free(s);
-    free(c);
 }