From 0bc5b91e15a5b22a4eadf3a87505be47484c7c52 Mon Sep 17 00:00:00 2001 From: Sachin Agrawal Date: Mon, 2 Feb 2015 12:26:18 -0800 Subject: [PATCH] Updated security config blob for extensibility 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 Reviewed-on: https://gerrit.iotivity.org/gerrit/242 Tested-by: jenkins-iotivity Reviewed-by: Doug Hudson Reviewed-by: Sashi Penta Reviewed-by: Sudarshan Prasad --- .../security/include/internal/ocsecurityinternal.h | 3 + resource/csdk/security/include/ocsecurity.h | 8 +- resource/csdk/security/include/ocsecurityconfig.h | 63 ++++++-- resource/csdk/security/src/ocsecurity.c | 162 ++++++++++++++++++--- .../csdk/stack/samples/linux/secure/common.cpp | 2 +- .../stack/samples/linux/secure/gen_sec_bin.cpp | 128 ++++++++++------ 6 files changed, 291 insertions(+), 75 deletions(-) diff --git a/resource/csdk/security/include/internal/ocsecurityinternal.h b/resource/csdk/security/include/internal/ocsecurityinternal.h index 6a2f638..8f09546 100644 --- a/resource/csdk/security/include/internal/ocsecurityinternal.h +++ b/resource/csdk/security/include/internal/ocsecurityinternal.h @@ -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 * diff --git a/resource/csdk/security/include/ocsecurity.h b/resource/csdk/security/include/ocsecurity.h index 16f42b7..eceaabb 100644 --- a/resource/csdk/security/include/ocsecurity.h +++ b/resource/csdk/security/include/ocsecurity.h @@ -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 diff --git a/resource/csdk/security/include/ocsecurityconfig.h b/resource/csdk/security/include/ocsecurityconfig.h index c18e9f7..8b3bda8 100644 --- a/resource/csdk/security/include/ocsecurityconfig.h +++ b/resource/csdk/security/include/ocsecurityconfig.h @@ -26,16 +26,21 @@ #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 diff --git a/resource/csdk/security/src/ocsecurity.c b/resource/csdk/security/src/ocsecurity.c index 327bfc9..98187fe 100644 --- a/resource/csdk/security/src/ocsecurity.c +++ b/resource/csdk/security/src/ocsecurity.c @@ -24,56 +24,180 @@ #include "ocsecurityconfig.h" #include -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 ( ;(inumBlob) && 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 ( ;(inumBlob) && 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; } diff --git a/resource/csdk/stack/samples/linux/secure/common.cpp b/resource/csdk/stack/samples/linux/secure/common.cpp index 16dd8a8..ebd6c64 100644 --- a/resource/csdk/stack/samples/linux/secure/common.cpp +++ b/resource/csdk/stack/samples/linux/secure/common.cpp @@ -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 diff --git a/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp b/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp index 2a259ac..89b8369 100644 --- a/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp +++ b/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp @@ -24,78 +24,124 @@ #include #include #include +#include #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); } -- 2.7.4