Security Profile Resource Implementation 37/24337/12
authorSteven Saunders <s.saunders-contractor@cablelabs.com>
Tue, 6 Mar 2018 23:18:21 +0000 (16:18 -0700)
committerNathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Fri, 23 Mar 2018 20:13:24 +0000 (20:13 +0000)
Change-Id: I6aab60b562272f0c4f34233d89c2b8884677c42a
Signed-off-by: Steven Saunders <s.saunders-contractor@cablelabs.com>
23 files changed:
resource/csdk/security/SConscript
resource/csdk/security/include/experimental/securevirtualresourcetypes.h
resource/csdk/security/include/internal/security_internals.h
resource/csdk/security/include/internal/spresource.h [new file with mode: 0644]
resource/csdk/security/include/internal/srmresourcestrings.h
resource/csdk/security/provisioning/include/internal/secureresourceprovider.h
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/include/pmtypes.h
resource/csdk/security/provisioning/sample/oic_svr_db_server_mfg.dat
resource/csdk/security/provisioning/sample/oic_svr_db_server_mfg.json
resource/csdk/security/provisioning/sample/provisioningclient.c
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c
resource/csdk/security/src/resourcemanager.c
resource/csdk/security/src/secureresourcemanager.c
resource/csdk/security/src/spresource.c [new file with mode: 0644]
resource/csdk/security/src/srmresourcestrings.c
resource/csdk/security/src/srmutility.c
resource/csdk/security/tool/json2cbor.c
resource/csdk/security/unittest/SConscript
resource/csdk/security/unittest/spresource.cpp [new file with mode: 0644]
resource/csdk/stack/include/ocpayload.h
resource/csdk/stack/octbstack_product_secured.def

index 1d6cd31..8204141 100644 (file)
@@ -97,6 +97,7 @@ libocsrm_src = [
     OCSRM_SRC + 'aclresource.c',
     OCSRM_SRC + 'amaclresource.c',
     OCSRM_SRC + 'pstatresource.c',
+    OCSRM_SRC + 'spresource.c',
     OCSRM_SRC + 'doxmresource.c',
     OCSRM_SRC + 'credresource.c',
     OCSRM_SRC + 'policyengine.c',
index e3bb8ed..3ed0da1 100644 (file)
@@ -184,6 +184,8 @@ typedef struct OicSecAmacl OicSecAmacl_t;
 
 typedef struct OicSecCred OicSecCred_t;
 
+typedef struct OicSecSp OicSecSp_t;
+
 /**
  * Aid for assigning/testing vals with OicSecCredType_t.
  * Example:
@@ -303,6 +305,7 @@ enum
     OIC_R_CSR_TYPE,
     OIC_R_ACL2_TYPE,
     OIC_R_ROLES_TYPE,
+    OIC_R_SP_TYPE,
     OIC_SEC_SVR_TYPE_COUNT, //define the value to number of SVR
     NOT_A_SVR_RESOURCE = 99
 };
@@ -627,6 +630,16 @@ struct OicSecPstat
     OicUuid_t           rownerID;       // 7:R:S:Y:oic.uuid
 };
 
+/**
+ * /oic/sec/sp (Security Profile) data type.
+ */
+struct OicSecSp
+{
+    size_t          supportedLen;       // the number of supported profiles
+    char          **supportedProfiles;  // Array of supported security profiles
+    char           *activeProfile;      // active security profile
+    uint16_t        credid;             // Cred supporting asserted support of active_profile
+};
 
 #if defined(__WITH_DTLS__) ||  defined(__WITH_TLS__)
 struct OicSecCrl
index a5802e9..ff80c1b 100644 (file)
@@ -69,6 +69,19 @@ void DeleteSVCList(OicSecSvc_t* svc);
  */
 OCStackResult CreatePstatResource();
 
+/**
+ * Create SP resource after default SP initialization is done.
+ */
+OCStackResult CreateSpResource();
+
+/**
+ * This internal method is the entity handler for sp resources
+ * to handle REST request (PUT/POST)
+ */
+OCEntityHandlerResult SpEntityHandler(OCEntityHandlerFlag flag,
+                                      OCEntityHandlerRequest * ehRequest,
+                                      void* callbackParameter);
+
 /**
  * This internal method is the entity handler for PSTAT resources and
  * will handle REST request (GET/PUT/POST/DEL) for them.
diff --git a/resource/csdk/security/include/internal/spresource.h b/resource/csdk/security/include/internal/spresource.h
new file mode 100644 (file)
index 0000000..bed292a
--- /dev/null
@@ -0,0 +1,198 @@
+//******************************************************************
+// Copyright 2018 Cable Television Laboratories, Inc.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific lan guage governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef IOTVT_SRM_SPR_H
+#define IOTVT_SRM_SPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    SP_SUPPORTED_PROFILES = 0,
+    SP_ACTIVE_PROFILE,
+    SP_CRED_ID,
+    SP_PROPERTY_COUNT
+} SpProperty_t;
+
+
+/**
+ * Initialize credentiaspl resource by loading data from persistent storage.
+ *
+ * @return ::OC_STACK_OK, if initialization is successful, else ::OC_STACK_ERROR if
+ * initialization fails.
+ */
+OCStackResult InitSpResource();
+
+/**
+ * Perform cleanup for sp resources.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+ */
+OCStackResult DeInitSpResource();
+
+/**
+ * This function deallocates the memory for OicSecSp_t.
+ *
+ * @param sp is the pointer to @ref OicSecSp_t.
+ */
+void DeleteSpBinData(OicSecSp_t* sp);
+
+/**
+ * Converts SP into the cbor payload, including all Properties for a
+ * full representation.
+ *
+ * @param sp       pointer to the initialized sp structure.
+ * @param payload  pointer to sp cbor payload. OICFree(sp) must be called when done
+ * @param size     size of the cbor payload converted.
+ *                 0 in case of error, else a positive value if successful.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+ */
+OCStackResult SpToCBORPayload(const OicSecSp_t *sp,
+                              uint8_t **payload, size_t *size);
+
+/**
+ * Converts SP into the cbor payload, including only the
+ * Properties marked "true" in the propertiesToInclude array.
+ *
+ * @param sp       pointer to the initialized sp structure.
+ * @param payload  pointer to sp cbor payload. OICFree(sp) must be called when done
+ * @param size     size of the cbor payload converted.
+ *                 0 in case of error, else a positive value if successful.
+ * @param propertiesToInclude Array of bools, size "SP_PROPERTY_COUNT",
+ *                            where "true" indicates the corresponding property should
+ *                            be included in the CBOR representation that is created.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+ */
+OCStackResult SpToCBORPayloadPartial(const OicSecSp_t *sp,
+                                     uint8_t **payload, size_t *size,
+                                     const bool *propertiesToInclude);
+
+
+/**
+ * This method converts cbor into SP data.
+ *
+ * @param [i] cborPayload is the sp data in cbor format.
+ * @param [i] size of the cborPayload. In case 0 is provided it assigns CBOR_SIZE (255) value.
+ * @param [o] sp pointer to @ref OicSecSp_t to be populated with data
+ * @param [o] decodedProperties Array of bools, size "SP_PROPERTY_COUNT",
+ *                              where "true" indicates the corresponding property was
+ *                              found in the CBOR and succesfully decoded and added to sp.
+ *                              Can be NULL if you don't need these results
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+*/
+OCStackResult CBORPayloadToSp(const uint8_t *cborPayload,
+                              const size_t size,
+                              OicSecSp_t **sp,
+                              bool *decodedProperties);
+
+
+/**
+ * Determine if a particular security profile requires a supporting credential
+ *
+ * @param [i] spName    securituy profile name
+ *
+ * @return          true if supporting cred required, otherwise false
+ */
+bool SpRequiresCred(char* spName);
+
+/**
+ * Return the index of a profile withing a list of supported profiles
+ *
+ * @param [i] supportedLen       number of entries in the supportedProfiles array
+ * @param [i] supportedProfiles  array of supported profiles
+ * @param [i] profileName        profile to find in supportedProfiles
+ *
+ * @return    index of the profileName withing supportedProfiles
+ *            -1 if profileName not in supportedProfiles
+ */
+int ProfileIdx( size_t supportedLen, char **supportedProfiles, char *profileName);
+
+
+/**
+ * determine if required sp properties are present and valid
+ *
+ * @param [i] sp                sp structure against which to check props
+ * @param [i] propertiesPresent array of bools, size "SP_PROPERTY_COUNT", where "true"
+ *                              indicates that the property value has been set in sp
+ *
+ * @return ::true if required properties are present and valid, otherwise false
+*/
+bool RequiredSpPropsPresentAndValid(OicSecSp_t* sp, bool *propertiesPresent);
+
+/**
+ * Log the contents of an sp resource
+ *
+ * @param sp    sp structure to log
+ * @param level logging level to use
+ * @param tag   logging tag to use
+ * @param msg   message to log prior to logging the SP values
+ *              can be NULL for no message
+ */
+void LogSp(OicSecSp_t* sp, int level, const char* tag, const char* msg);
+
+/**
+ * Compare the contents of two sp property arrays for equality
+ *
+ * @param spProps1 first array with prop state (size "SP_PROPERTY_COUNT")
+ * @param spProps2 first array with prop state (size "SP_PROPERTY_COUNT")
+ *
+ * @return true if contents of sp1 and sp2 are the same, otherwise false
+ */
+bool IsPropArraySame(bool* spProps1, bool* spProps2);
+
+/**
+ * Compare the contents of two sp structs for equality
+ *
+ * @param sp1 first sp for compare
+ * @param sp2 second sp for compare
+ * @param propertiesToCheck properties to check for equality (or NULL to check all properties)
+ *                          size "SP_PROPERTY_COUNT", entries = true for props to compare
+ *
+ * @return true if the requested props of sp1 and sp2 are the same, otherwise false
+ */
+bool IsSpSame(OicSecSp_t* sp1, OicSecSp_t* sp2,  bool *propertiesToCheck);
+
+/**
+ * Set all of the values in an sp props array to either true or false
+ *
+ * @param spProps security profiles property array (size "SP_PROPERTY_COUNT")
+ * @param setTo value to set all entries in the array to
+ *
+ */
+void SetAllSpProps(bool* spProps, bool setTo);
+
+/**
+ * Make a copy of testSp, and install it as the SP resource.
+ * Only for testing (does not update persitant storage)
+ *
+ * @param testSp sp resource to install
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+*/
+OCStackResult InstallTestSp(OicSecSp_t* testSp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IOTVT_SRM_SPR_H
index bdb463f..11dc28d 100644 (file)
@@ -60,6 +60,11 @@ extern const char * OIC_RSRC_TYPE_SEC_DOXM;
 extern const char * OIC_RSRC_DOXM_URI;
 extern const char * OIC_JSON_DOXM_NAME;
 
+// sp
+extern const char * OIC_RSRC_TYPE_SEC_SP;
+extern const char * OIC_RSRC_SP_URI;
+extern const char * OIC_JSON_SP_NAME;
+
 //cred
 extern const char * OIC_RSRC_TYPE_SEC_CRED;
 extern const char * OIC_RSRC_CRED_URI;
@@ -145,6 +150,9 @@ extern const char * OIC_JSON_CM_NAME;
 extern const char * OIC_JSON_TM_NAME;
 extern const char * OIC_JSON_OM_NAME;
 extern const char * OIC_JSON_SM_NAME;
+extern const char * OIC_JSON_SUPPORTED_SP_NAME;
+extern const char * OIC_JSON_ACTIVE_SP_NAME;
+extern const char * OIC_JSON_SP_CREDID_NAME;
 extern const char * OIC_JSON_SERVICE_DEVICE_ID;
 extern const char * OIC_JSON_SERVICE_TYPE;
 extern const char * OIC_JSON_SUPPORTED_CRED_TYPE_NAME;
index f5cdea3..e2d1860 100644 (file)
@@ -34,6 +34,7 @@ typedef enum
     ACL_TYPE,                             /**< Access control list.**/
     PSK_TYPE,                             /**< Pre-Shared Key.**/
     CERT_TYPE,                            /**< X.509 certificate.**/
+    SP_TYPE,                              /**< Security Profiles. **/
     MOT_TYPE                              /**< Multiple Ownership Transfer.**/
 } DataType_t;
 
@@ -112,6 +113,18 @@ OCStackResult SRPGetACLResource(void *ctx, const OCProvisionDev_t *selectedDevic
 OCStackResult SRPGetCSRResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
                                 OCGetCSRResultCB resultCallback);
 
+/**
+ * API to request the Security Profile (SP) resource.
+ *
+ * @param[in] ctx Application context to be returned in result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult SRPGetSpResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                OCGetSpResultCB resultCallback);
+
 /**
  * API to request the Roles resource.
  *
@@ -155,6 +168,20 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
                                       const OCProvisionDev_t *selectedDeviceInfo,
                                       OCProvisionResultCB resultCallback);
 
+/**
+ * function to provision security profile info
+ *
+ * @param[in] ctx Application context to be returned in result callback.
+ * @param[in] sp security profile to be provisioned
+ * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request recieves a response from first resource server.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult SRPProvisionSecurityProfileInfo(void *ctx, OicSecSp_t *sp,
+                                              const OCProvisionDev_t *selectedDeviceInfo,
+                                              OCProvisionResultCB resultCallback);
+
 /**
  * function to save Trust certificate chain into Cred of SVR.
  *
index e3c2738..c25daf9 100644 (file)
@@ -310,6 +310,19 @@ OCStackResult OC_CALL OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selec
 OCStackResult OC_CALL OCGetCSRResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
                                OCGetCSRResultCB resultCallback);
 
+
+/**
+ * This function requests the device provide its security profile (SP).
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
+              request recieves a response from resource server.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OC_CALL OCGetSpResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                               OCGetSpResultCB resultCallback);
+
 /**
  * This function requests the device provide its roles resource, listing the role certificates
  * it has for the local requestor.
@@ -361,7 +374,7 @@ OCStackResult OC_CALL OCProvisionCredentials(void *ctx, OicSecCredType_t type, s
  * @param[in] type Type of credentials to be provisioned to the device.
  * @param[in] keySize size of key
  * @param[in] pDev1 Pointer to OCProvisionDev_t instance, representing the resource to be provisioned.
- * @param[in] pDev2 Pointer to OCProvisionDev_t instance, representing the resource to be provisioned. 
+ * @param[in] pDev2 Pointer to OCProvisionDev_t instance, representing the resource to be provisioned.
  *                  Use NULL to indicate the local device.
  * @param[in] role1 The role which the device indicated by pDev1 will have when communicating with pDev2.
  *                  Use NULL to associate no role with this credential.
@@ -621,6 +634,21 @@ OCStackResult OC_CALL OCProvisionCRL(void* ctx, const OCProvisionDev_t *selected
 OCStackResult OC_CALL OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
                                       const OCProvisionDev_t *selectedDeviceInfo,
                                       OCProvisionResultCB resultCallback);
+
+/**
+ * function to provision a security profile resource to devices.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] sp security profile to be provisioned
+ * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provisioned.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request recieves a response from first resource server.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OC_CALL OCProvisionSecurityProfileInfo(void *ctx, OicSecSp_t *sp,
+                                      const OCProvisionDev_t *selectedDeviceInfo,
+                                      OCProvisionResultCB resultCallback);
+
 /**
  * function to save Trust certificate chain into Cred of SVR.
  *
index ca152de..9d0e3da 100644 (file)
@@ -95,6 +95,13 @@ typedef struct OCPMGetCsrResult
     OicEncodingType_t   encoding; /* Determines contents of csr; either OIC_ENCODING_DER or OIC_ENCODING_PEM */
 } OCPMGetCsrResult_t;
 
+typedef struct OCPMGetSpResult
+{
+    OicUuid_t           deviceId;
+    OCStackResult       res;
+    OicSecSp_t         *sp;
+} OCPMGetSpResult_t;
+
 typedef struct OCPMRoleCertChain
 {
     uint64_t            credId;         /**< credential ID */
@@ -159,6 +166,19 @@ typedef void (*OCProvisionResultCB)(void* ctx, size_t nOfRes, OCProvisionResult_
  */
 typedef void (*OCGetCSRResultCB)(void* ctx, size_t nOfRes, OCPMGetCsrResult_t *arr, bool hasError);
 
+/**
+ * Callback function definition of SP retrieve API
+ *
+ * @param[OUT] ctx - If user set a context, it will be returned here.
+ * @param[OUT] nOfRes - total number of results
+ * @param[OUT] arr - Array of OCPMGetSpResult_t, containing one entry for each target device. If an entry's res
+ *                   member is OC_STACK_OK, This memory is only valid while the callback is executing;
+ *                   callers must make copies if the data needs to be kept longer.
+ * @param[OUT] hasError - If all calls succeded, this will be false. One or more errors, and this will
+ *                        be true. Examine the elements of arr to discover which failed.
+ */
+typedef void (*OCGetSpResultCB)(void* ctx, size_t nOfRes, OCPMGetSpResult_t *arr, bool hasError);
+
 /**
  * Callback function definition of roles retrieve API
  *
index 291313c..3144b4c 100644 (file)
Binary files a/resource/csdk/security/provisioning/sample/oic_svr_db_server_mfg.dat and b/resource/csdk/security/provisioning/sample/oic_svr_db_server_mfg.dat differ
index 0f9df48..6a48dca 100644 (file)
@@ -1,4 +1,12 @@
 {
+    "sp": {
+        "supported_profiles": [ "oic.sec.sp.black", "oic.sec.sp.blue", "oic.sec.sp.baseline" ],
+        "active_profile": "oic.sec.sp.black",
+        "credid": 1,
+        "rowneruuid": "00000000-0000-0000-0000-000000000000",
+        "rt": ["oic.r.ps"],
+        "if": ["oic.if.baseline"]
+    },
     "cred": {
         "creds": [
             {
                     { "href": "/oic/sec/roles" }
                 ],
                 "permission": 14
+            },
+            {
+                "aceid": 5,
+                "subject": { "uuid": "11111111-1111-1111-1111-111111111111" },
+                "resources": [
+                    { "href": "/oic/sec/acl2" },
+                    { "href": "/oic/sec/cred" },
+                    { "href": "/oic/sec/doxm" },
+                    { "href": "/oic/sec/pstat" },
+                    { "href": "/oic/sec/csr" },
+                    { "href": "/oic/sec/sp" }
+                ],
+                "permission": 15
             }
+
         ],
       "rowneruuid": "00000000-0000-0000-0000-000000000000",
       "rt": ["oic.r.acl"],
index 9a0c36b..cb0d782 100644 (file)
@@ -34,6 +34,7 @@
 #include "oxmjustworks.h"
 #include "oxmrandompin.h"
 #include "srmutility.h"
+#include "spresource.h"
 #include "pmtypes.h"
 #include "oxmverifycommon.h"
 #include "mbedtls/config.h"
@@ -77,6 +78,7 @@ extern "C"
 #ifdef WITH_CLOUD
 #define _36_PROVIS_CLOUD_CONF_      36
 #endif //WITH_CLOUD
+#define _37_PROVIS_SEC_PROFILE             37
 #define _40_UNLINK_PAIR_DEVS_       40
 #define _50_REMOVE_SELEC_DEV_       50
 #define _51_REMOVE_DEV_WITH_UUID_   51
@@ -85,6 +87,7 @@ extern "C"
 #define _60_GET_CRED_               60
 #define _61_GET_ACL_                61
 #define _62_GET_CSR_                62
+#define _63_GET_SP_                 63
 #ifdef MULTIPLE_OWNER
 #define _70_MOT_CHANGE_MOM_         70
 #define _71_MOT_PROV_PRECONF_PIN_   71
@@ -147,6 +150,25 @@ static FILE* fopen_prvnMng(const char*, const char*);
 static int waitCallbackRet(void);
 static int selectTwoDiffNum(int*, int*, const int, const char*);
 
+char * gSupportedProfilesDefault[] = { "oic.sec.sp.baseline" };
+OicSecSp_t gSpDefault =
+{
+    1,                          // supportedLen
+    gSupportedProfilesDefault,  // supportedProfiles[0]
+    "oic.sec.sp.baseline",      // activeProfile
+    0                           // credid
+};
+
+char * gSupportedProfilesAll[] = { "oic.sec.sp.black", "oic.sec.sp.blue", "oic.sec.sp.baseline",  };
+OicSecSp_t gSpAll =
+{
+    3,                      // supportedLen
+    gSupportedProfilesAll,  // supportedProfiles[0]
+    "oic.sec.sp.black",     // activeProfile
+    1                       // credid (arbitrary for testing)
+};
+
+
 /* At a few places in this file, warning 4028 is incorrectly produced, disable it for the whole file. */
 #ifdef _MSC_VER
 #pragma warning( disable : 4028)
@@ -353,6 +375,25 @@ static void getCsrCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool has
     g_doneCB = true;
 }
 
+static void getSpCB(void* ctx, size_t nOfRes, OCPMGetSpResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "getSpCB SUCCEEDED - ctx: %s", (char*) ctx);
+        OIC_LOG(INFO, TAG, "Retrieved Security Profile(s)");
+        for (size_t i = 0; i < nOfRes; i++)
+        {
+            LogSp((arr[i]).sp, INFO, TAG, NULL);
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "getSpCB FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
 static void getCsrForCertProvCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool hasError)
 {
     g_successCB = false;
@@ -1280,6 +1321,92 @@ static int provisionCert(void)
     return 0;
 }
 
+static int provisionSecurityProfileInfo(void)
+{
+    // make sure we own at least one device to provision
+    if (!g_own_list || g_own_cnt == 0)
+    {
+        printf("   > Owned Device List, to Provision Security Profile Info, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for provisioning security profile
+    int dev_num = 0;
+    if (g_own_cnt == 1)
+    {
+        dev_num = 1;
+    }
+    else
+    {
+        for (; ; )
+        {
+            printf("   > Enter Device Number, for security profile provisioning: ");
+            for (int ret = 0; 1 != ret; )
+            {
+                ret = scanf("%d", &dev_num);
+                for (; 0x20 <= getchar(); );  // for removing overflow garbages
+                                              // '0x20<=code' is character region
+            }
+            if (0<dev_num && g_own_cnt >= dev_num)
+            {
+                break;
+            }
+            printf("     Entered Wrong Number. Please Enter Again\n");
+        }
+    }
+
+    OCProvisionDev_t* targetDevice = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+    if (targetDevice == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Error, invalid device %d");
+        return -1;
+    }
+
+    int sp_selection = 0;
+    for (; ; )
+    {
+        printf("   > Enter (1) for SP defaults or (2) for SP containing all profiles: ");
+        for (int ret = 0; 1 != ret; )
+        {
+            ret = scanf("%d", &sp_selection);
+            for (; 0x20 <= getchar(); );  // for removing overflow garbages
+                                          // '0x20<=code' is character region
+        }
+        if ((1 == sp_selection) || (2 >= sp_selection))
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    printf("   > Posting new security profile info to device ...\n");
+    g_doneCB = false;
+
+    OicSecSp_t *sp = (sp_selection == 1) ? &gSpDefault : &gSpAll;
+    OCStackResult rst = OCProvisionSecurityProfileInfo(
+        (void*)g_ctx, sp, targetDevice, (OCProvisionResultCB)&provisionTrustChainCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "provisionSecurityProfileInfo returned error: %d", rst);
+        return -1;
+    }
+
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "provisionSecurityProfileInfo callback error");
+        return -1;
+    }
+    if (!g_successCB)
+    {
+        return -1;
+    }
+
+    printf("   > Provisioned security profile info\n");
+
+    return 0;
+}
+
 #ifdef WITH_CLOUD
 static int provisionCloudConfig(void)
 {
@@ -1846,6 +1973,67 @@ GETCSR_ERROR:
     return -1;
 }
 
+static int getSp(void)
+{
+    // check |own_list| for retrieving SP
+    if(!g_own_list || 1>g_own_cnt)
+    {
+        printf("   > Owned Device List, to retrieve SP, is Empty\n");
+        printf("   > Please Register Unowned Devices first, with [20] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for retrieving SP
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for retrieving SP: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    // call |getDevInst| API
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
+    if(!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        goto GETSP_ERROR;
+    }
+    OCStackResult rst = OCGetSpResource((void*) g_ctx, dev, getSpCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGetSpResource API error: %d", rst);
+
+        goto GETSP_ERROR;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCGetSpResource callback error");
+        goto GETSP_ERROR;
+    }
+
+    // display the result of get credential
+    printf("   > Get SP SUCCEEDED\n");
+
+    return 0;
+
+GETSP_ERROR:
+    return -1;
+}
+
 static int unlinkPairwise(void)
 {
     // check |own_list| for unlinking pairwise devices
@@ -2942,7 +3130,8 @@ static void printMenu(void)
     printf("** 33. Check Linked Status of the Selected Device on PRVN DB\n");
     printf("** 34. Save the Selected Access Control List(ACL) into local SVR DB\n");
     printf("** 35. Provision certificate credential\n");
-    printf("** 36. Provision cloud credential\n\n");
+    printf("** 36. Provision cloud credential\n");
+    printf("** 37. Provision security profile info\n\n");
 
 
     printf("** [D] UNLINK PAIRWISE THINGS\n");
@@ -2957,7 +3146,8 @@ static void printMenu(void)
     printf("** [F] GET SECURITY RESOURCE FOR DEBUGGING ONLY\n");
     printf("** 60. Get the Credential resources of the Selected Device\n");
     printf("** 61. Get the ACL resources of the Selected Device\n");
-    printf("** 62. Get the CSR of the Selected Device\n\n");
+    printf("** 62. Get the CSR of the Selected Device\n");
+    printf("** 63. Get the SP of the Selected Device\n\n");
 
 #ifdef MULTIPLE_OWNER
     printf("** [G] UPDATE THE MULTIPLE OWNERSHIP TRANSFER RELATED VALUE\n");
@@ -3135,6 +3325,12 @@ int main()
             }
             break;
 #endif //WITH_CLOUD
+        case _37_PROVIS_SEC_PROFILE:
+            if (provisionSecurityProfileInfo())
+            {
+                OIC_LOG(ERROR, TAG, "_37_PROVIS_SEC_PROFILE: error");
+            }
+            break;
         case _40_UNLINK_PAIR_DEVS_:
             if(unlinkPairwise())
             {
@@ -3183,6 +3379,12 @@ int main()
                 OIC_LOG(ERROR, TAG, "_62_GET_CSR_: error");
             }
             break;
+        case _63_GET_SP_:
+            if(getSp())
+            {
+                OIC_LOG(ERROR, TAG, "_63_GET_SP_: error");
+            }
+            break;
 #ifdef MULTIPLE_OWNER
         case _70_MOT_CHANGE_MOM_:
             if(changeMultipleOwnershipTrnasferMode())
index 8fd567d..d52bd92 100644 (file)
@@ -467,6 +467,12 @@ OCStackResult OC_CALL OCGetCSRResource(void* ctx, const OCProvisionDev_t *select
     return SRPGetCSRResource(ctx, selectedDeviceInfo, resultCallback);
 }
 
+OCStackResult OC_CALL OCGetSpResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                       OCGetSpResultCB resultCallback)
+{
+    return SRPGetSpResource(ctx, selectedDeviceInfo, resultCallback);
+}
+
 OCStackResult OC_CALL OCGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
                                          OCGetRolesResultCB resultCallback)
 {
@@ -1506,6 +1512,23 @@ OCStackResult OC_CALL OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type
                                       selectedDeviceInfo, resultCallback);
 }
 
+/**
+ * function to provision a security profile resource to devices.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] sp security profile to be provisioned
+ * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provisioned.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request recieves a response from first resource server.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OC_CALL OCProvisionSecurityProfileInfo(void *ctx, OicSecSp_t *sp,
+                                      const OCProvisionDev_t *selectedDeviceInfo,
+                                      OCProvisionResultCB resultCallback)
+{
+    return SRPProvisionSecurityProfileInfo(ctx, sp, selectedDeviceInfo, resultCallback);
+}
+
 /**
  * function to save Trust certificate chain into Cred of SVR.
  *
index c05c688..45eb0e2 100644 (file)
@@ -34,6 +34,7 @@
 #include "pstatresource.h"
 #include "srmresourcestrings.h"
 #include "credresource.h"
+#include "spresource.h"
 #include "csrresource.h"
 #include "rolesresource.h"
 #include "experimental/doxmresource.h"
@@ -118,6 +119,19 @@ typedef struct CertData
     const char* cert;                           /**< The certificate.**/
 } CertData_t;
 
+/**
+ * Structure to carry security profiles provision API data to callback.
+ */
+typedef struct SpData
+{
+    void *ctx;                                  /**< Pointer to user context.**/
+    const OCProvisionDev_t *targetDev;          /**< Pointer to OCProvisionDev_t.**/
+    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
+    OCProvisionResult_t *resArr;                /**< Result array.**/
+    int numOfResults;                           /**< Number of results in result array.**/
+    OicSecSp_t *sp;
+} SpData_t;
+
 // Structure to carry get security resource APIs data to callback.
 typedef struct GetSecData GetSecData_t;
 struct GetSecData {
@@ -137,6 +151,16 @@ struct GetCsrData {
     size_t numOfResults;                        /**< Number of results in result array.**/
 };
 
+typedef struct GetSpData GetSpData_t;
+struct GetSpData {
+    void *ctx;
+    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
+    OCGetSpResultCB resultCallback;             /**< Pointer to result callback.**/
+    OCPMGetSpResult_t *resArr;                  /**< Result array.**/
+    size_t numOfResults;                        /**< Number of results in result array.**/
+};
+
+
 typedef struct GetRolesData GetRolesData_t;
 struct GetRolesData {
     void *ctx;                                  /**< User-provided context **/
@@ -225,6 +249,13 @@ void FreeData(Data_t *data)
                 OICFree(chainData);
                 break;
             }
+        case SP_TYPE:
+            {
+                SpData_t *spData = (SpData_t *) data->ctx;
+                OICFree(spData->resArr);
+                OICFree(spData);
+                break;
+            }
         case ACL_TYPE:
             {
                 ACLData_t *aclData = (ACLData_t *) data->ctx;
@@ -746,6 +777,16 @@ OCStackApplicationResult SetReadyForNormalOperationCB(void *ctx, OCDoHandle hand
             dataCtx = chainData->ctx;
             break;
         }
+        case SP_TYPE:
+        {
+            SpData_t *spData = (SpData_t *) ((Data_t *) ctx)->ctx;
+            resultCallback = spData->resultCallback;
+            targetDev = spData->targetDev;
+            resArr = spData->resArr;
+            numOfResults = &(spData->numOfResults);
+            dataCtx = spData->ctx;
+            break;
+        }
         case ACL_TYPE:
         {
             ACLData_t *aclData = (ACLData_t *) ((Data_t *) ctx)->ctx;
@@ -841,6 +882,11 @@ OCStackResult SetDOS(const Data_t *data, OicSecDeviceOnboardingState_t dos,
             pTargetDev = ((TrustChainData_t *)data->ctx)->targetDev;
             break;
         }
+        case SP_TYPE:
+        {
+            pTargetDev = ((SpData_t *)data->ctx)->targetDev;
+            break;
+        }
         case ACL_TYPE:
         {
             pTargetDev = ((ACLData_t *)data->ctx)->deviceInfo;
@@ -1167,6 +1213,86 @@ static OCStackApplicationResult ProvisionTrustChainCB(void *ctx, OCDoHandle UNUS
     return OC_STACK_OK;
 }
 
+/**
+ * Callback for Security Profile provisioning.
+ */
+static OCStackApplicationResult ProvisionSecurityProfileInfoCB(void *ctx, OCDoHandle UNUSED,
+        OCClientResponse *clientResponse)
+{
+    OIC_LOG_V(INFO, TAG, "IN %s", __func__);
+    (void) UNUSED;
+    if (NULL == ctx)
+    {
+        OIC_LOG(ERROR, TAG, "Context is NULL");
+        return OC_STACK_INVALID_PARAM;
+    }
+    if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+    {
+        Data_t *data = (Data_t *) ctx;
+        if (SP_TYPE != data->type)
+        {
+            OIC_LOG(ERROR, TAG, "Invalid type");
+            return OC_STACK_INVALID_PARAM;
+        }
+        SpData_t *spData = (SpData_t *) (data->ctx);
+
+        OCSecurityPayload *secPayload = (OCSecurityPayload *)OICCalloc(1, sizeof(OCSecurityPayload));
+        if (!secPayload)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to allocate memory");
+            return OC_STACK_NO_MEMORY;
+        }
+
+        secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+        if (OC_STACK_OK != SpToCBORPayload(spData->sp, &secPayload->securityData,
+                                           &secPayload->payloadSize))
+        {
+            OCPayloadDestroy((OCPayload *)secPayload);
+            OIC_LOG(ERROR, TAG, "Failed to SpToCBORPayload");
+            return OC_STACK_NO_MEMORY;
+        }
+        OIC_LOG(DEBUG, TAG, "Created payload for SP:");
+        OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+
+        char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+        if (!PMGenerateQuery(true,
+                             spData->targetDev->endpoint.addr,
+                             spData->targetDev->securePort,
+                             spData->targetDev->connType,
+                             query, sizeof(query), OIC_RSRC_SP_URI))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to generate query");
+            OCPayloadDestroy((OCPayload *)secPayload);
+            return OC_STACK_ERROR;
+        }
+        OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+        OCCallbackData cbData =  {.context = NULL, .cb = NULL, .cd = NULL};
+        cbData.cb = ProvisionCB;
+        cbData.context = ctx;
+        cbData.cd = NULL;
+        OCMethod method = OC_REST_POST;
+        OCDoHandle handle = NULL;
+        OIC_LOG(DEBUG, TAG, "Sending SP info to resource server");
+        OCStackResult ret = OCDoResource(&handle, method, query,
+                                         &spData->targetDev->endpoint, (OCPayload *)secPayload,
+                                         spData->targetDev->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+        if (ret != OC_STACK_OK)
+        {
+            OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
+            return ret;
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "OUT %s", __func__);
+        return OC_STACK_ERROR;
+    }
+
+    OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
+    return OC_STACK_OK;
+}
+
 OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
         const OCProvisionDev_t *selectedDeviceInfo, OCProvisionResultCB resultCallback)
 {
@@ -1216,6 +1342,62 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
     return OC_STACK_OK;
 }
 
+/**
+ * function to provision security profile info
+ *
+ * @param[in] ctx Application context to be returned in result callback.
+ * @param[in] sp security profile to be provisioned
+ * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request recieves a response from first resource server.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult SRPProvisionSecurityProfileInfo(void *ctx, OicSecSp_t *sp,
+                                              const OCProvisionDev_t *selectedDeviceInfo,
+                                              OCProvisionResultCB resultCallback)
+{
+    OIC_LOG_V(INFO, TAG, "IN %s", __func__);
+    VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
+
+    SpData_t *spData = (SpData_t *) OICCalloc(1, sizeof(SpData_t));
+    if (NULL == spData)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation problem");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    spData->targetDev = selectedDeviceInfo;
+    spData->resultCallback = resultCallback;
+    spData->ctx = ctx;
+    spData->numOfResults = 0;
+    spData->sp = sp;
+
+    int noOfRiCalls = 1;
+    spData->resArr = (OCProvisionResult_t *)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
+    if (spData->resArr == NULL)
+    {
+        OICFree(spData);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    Data_t *data = (Data_t *) OICCalloc(1, sizeof(Data_t));
+    VERIFY_NOT_NULL_RETURN(TAG, data, ERROR, OC_STACK_NO_MEMORY);
+    data->type = SP_TYPE;
+    data->ctx = spData;
+
+    if (SetDOS(data, DOS_RFPRO, ProvisionSecurityProfileInfoCB) != OC_STACK_OK)
+    {
+        FreeData(data);
+        OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
+        return OC_STACK_ERROR;
+    }
+
+    OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
+    return OC_STACK_OK;
+}
+
 OCStackResult SRPSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,
                                             OicEncodingType_t encodingType, uint16_t *credId)
 {
@@ -3584,6 +3766,96 @@ static OCStackApplicationResult SRPGetCSRResourceCB(void *ctx, OCDoHandle UNUSED
     return OC_STACK_DELETE_TRANSACTION;
 }
 
+/**
+ * Internal Function to store results in result array during GetSpResourceCB.
+ */
+static void registerResultForGetSpResourceCB(GetSpData_t *getSpData,
+                                             OCStackResult stackresult,
+                                             const uint8_t *payload,
+                                             size_t payloadSize)
+{
+    /* SRPGetSpResource allocates the memory for getSpData. When it calls this callback,
+     * numOfResults points to the current entry we're filling out. Later when this structure
+     * gets returned to the caller, that's when it actually reflects the number of
+     * results returned.
+     */
+    OCPMGetSpResult_t* currentEntry = &getSpData->resArr[getSpData->numOfResults];
+    OIC_LOG_V(INFO, TAG, "Inside registerResultForGetSpResourceCB "
+        "getSpData->numOfResults is %zu\n", getSpData->numOfResults);
+    memcpy(currentEntry->deviceId.id,
+        getSpData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
+    currentEntry->res = stackresult;
+
+    OicSecSp_t *sp = NULL;
+
+    if (OC_STACK_OK == stackresult)
+    {
+        OCStackResult res = CBORPayloadToSp(payload, payloadSize, &sp, NULL);
+        if (OC_STACK_OK == res)
+        {
+            currentEntry->sp = sp;
+        }
+        else
+        {
+            currentEntry->sp = NULL;
+        }
+    }
+
+    ++(getSpData->numOfResults);
+}
+
+/**
+ * Callback handler of SRPGetSpResource.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult SRPGetSpResourceCB(void *ctx, OCDoHandle UNUSED,
+    OCClientResponse *clientResponse)
+{
+    OIC_LOG_V(INFO, TAG, "IN %s", __func__);
+    OC_UNUSED(UNUSED);
+    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    GetSpData_t *getSpData = (GetSpData_t*)ctx;
+    OCGetSpResultCB resultCallback = getSpData->resultCallback;
+
+    if (clientResponse)
+    {
+        if (OC_STACK_OK == clientResponse->result)
+        {
+            uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
+            size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
+
+            OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
+
+            registerResultForGetSpResourceCB(getSpData, OC_STACK_OK, payload, size);
+        }
+    }
+    else
+    {
+        registerResultForGetSpResourceCB(getSpData, OC_STACK_ERROR, NULL, 0);
+    }
+
+    ((OCGetSpResultCB)(resultCallback))(getSpData->ctx, getSpData->numOfResults,
+        getSpData->resArr,
+        false);
+    OIC_LOG_V(ERROR, TAG, "%s: received Null clientResponse", __func__);
+
+    for (size_t i = 0; i < getSpData->numOfResults; i++)
+    {
+        DeleteSpBinData((getSpData->resArr[i]).sp);
+    }
+
+    OICFree(getSpData->resArr);
+    OICFree(getSpData);
+    OIC_LOG_V(INFO, TAG, "OUT %s", __func__);
+
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
 OCStackResult SRPGetCSRResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
         OCGetCSRResultCB resultCallback)
 {
@@ -3640,6 +3912,62 @@ OCStackResult SRPGetCSRResource(void *ctx, const OCProvisionDev_t *selectedDevic
     return ret;
 }
 
+OCStackResult SRPGetSpResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+        OCGetSpResultCB resultCallback)
+{
+    VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    if (!PMGenerateQuery(true,
+                        selectedDeviceInfo->endpoint.addr,
+                        selectedDeviceInfo->securePort,
+                        selectedDeviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_SP_URI))
+    {
+        OIC_LOG(ERROR, TAG, "SRPGetSpResource : Failed to generate query");
+        return OC_STACK_ERROR;
+    }
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &SRPGetSpResourceCB;
+    GetSpData_t* getSpData = (GetSpData_t*)OICCalloc(1, sizeof(GetSpData_t));
+    if (NULL == getSpData)
+    {
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    getSpData->deviceInfo = selectedDeviceInfo;
+    getSpData->resultCallback = resultCallback;
+    getSpData->numOfResults=0;
+    getSpData->ctx = ctx;
+
+    int noOfRiCalls = 1;
+    getSpData->resArr = (OCPMGetSpResult_t*)OICCalloc(noOfRiCalls, sizeof(OCPMGetSpResult_t));
+    if (NULL == getSpData->resArr)
+    {
+        OICFree(getSpData);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    cbData.context = (void *)getSpData;
+    OCMethod method = OC_REST_GET;
+    OCDoHandle handle = NULL;
+    OIC_LOG(DEBUG, TAG, "Sending Get SP to resource server");
+    OCStackResult ret = OCDoResource(&handle, method, query, NULL, NULL,
+            selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack resource error");
+        OICFree(getSpData->resArr);
+        OICFree(getSpData);
+    }
+    OIC_LOG(DEBUG, TAG, "OUT SRPGetSpResource");
+
+    return ret;
+}
+
 /**
  * Internal Function to store results in result array during GetRolesResourceCB.
  */
@@ -3654,7 +3982,7 @@ static void registerResultForGetRolesResourceCB(GetRolesData_t *getRolesData,
      * results returned.
      */
     OCPMGetRolesResult_t* currentEntry = &getRolesData->resArr[getRolesData->numOfResults];
-    OIC_LOG_V(INFO, TAG, "Inside registerResultForGetCSRResourceCB "
+    OIC_LOG_V(INFO, TAG, "Inside registerResultForGetRolesResourceCB "
         "getRolesData->numOfResults is %zu\n", getRolesData->numOfResults);
     memcpy(currentEntry->deviceId.id,
         getRolesData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
index b39d5ab..c2cfeee 100644 (file)
@@ -24,6 +24,7 @@
 #include "pstatresource.h"
 #include "experimental/doxmresource.h"
 #include "credresource.h"
+#include "spresource.h"
 #include "amaclresource.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
@@ -80,9 +81,16 @@ OCStackResult InitSecureResources( )
         ret = InitPstatResource();
     }
     if(OC_STACK_OK == ret)
+    {
+        ret = InitSpResource();
+    }
+    if(OC_STACK_OK == ret)
     {
         ret = InitACLResource();
     }
+
+    // Warning: InitCredResource() alters the database.
+    // Initialization for any newly added resources should likely happen before this.
     if(OC_STACK_OK == ret)
     {
         ret = InitCredResource();
index 727e3b9..cb745b4 100644 (file)
@@ -566,6 +566,15 @@ OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
         }
     }
 
+    svrLen = strlen(OIC_RSRC_SP_URI);
+    if (uriLen == svrLen)
+    {
+        if (0 == strncmp(uri, OIC_RSRC_SP_URI, svrLen))
+        {
+            return OIC_R_SP_TYPE;
+        }
+    }
+
     svrLen = strlen(OIC_RSRC_DOXM_URI);
     if (uriLen == svrLen)
     {
diff --git a/resource/csdk/security/src/spresource.c b/resource/csdk/security/src/spresource.c
new file mode 100644 (file)
index 0000000..5db5df6
--- /dev/null
@@ -0,0 +1,1111 @@
+//******************************************************************
+// Copyright 2018 Cable Television Laboratories, Inc.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific lan guage governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "iotivity_config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ocstack.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "ocpayload.h"
+#include "ocpayloadcbor.h"
+#include "experimental/payload_logging.h"
+#include "psinterface.h"
+#include "resourcemanager.h"
+#include "spresource.h"
+#include "srmutility.h"
+#include "srmresourcestrings.h"
+
+#define TAG  "OIC_SRM_SP"
+
+#define OIC_CBOR_SP_NAME "sp"
+
+static OCResourceHandle    gSpHandle  = NULL;
+static OicSecSp_t         *gSp        = NULL;
+
+// Default sp values
+char * gSupportedProfiles[] = { "oic.sec.sp.baseline" };
+OicSecSp_t gDefaultSp =
+{
+    1,                     // supportedLen
+    gSupportedProfiles,    // supportedProfiles[0]
+    "oic.sec.sp.baseline", // activeProfile
+    0                      // credid
+};
+
+bool gAllProps[SP_PROPERTY_COUNT] = { true, true, true};
+
+// Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
+// The value of payload size is increased until reaching below max cbor size.
+static const uint16_t CBOR_SIZE = 512;
+
+// Max cbor size payload.
+static const uint16_t CBOR_MAX_SIZE = 4400;
+
+// Minimum SP map size (rt, if)
+static const uint8_t SP_MIN_MAP_SIZE = 2;
+
+OCStackResult SpToCBORPayload(const OicSecSp_t *sp, uint8_t **payload, size_t *size)
+{
+    bool allProps[SP_PROPERTY_COUNT];
+    SetAllSpProps(allProps, true);
+
+    if (false == SpRequiresCred(sp->activeProfile))
+    {
+        allProps[SP_CRED_ID] = false;
+    }
+
+    return SpToCBORPayloadPartial(sp, payload, size, allProps);
+}
+
+OCStackResult SpToCBORPayloadPartial(const OicSecSp_t *sp,
+                                     uint8_t **payload, size_t *size,
+                                     const bool *propertiesToInclude)
+{
+    if (NULL == sp || NULL == payload || NULL != *payload || NULL == size)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    size_t cborLen = *size;
+    if (0 == cborLen)
+    {
+        cborLen = CBOR_SIZE;
+    }
+
+    *payload = NULL;
+    *size = 0;
+
+    OCStackResult ret = OC_STACK_ERROR;
+    int64_t cborEncoderResult = CborNoError;
+
+    CborEncoder encoder;
+    CborEncoder spMap;
+
+    // Calculate map size
+    size_t spMapSize = SP_MIN_MAP_SIZE;
+    for (int i = 0; i < SP_PROPERTY_COUNT; i++)
+    {
+        if (propertiesToInclude[i])
+        {
+            spMapSize++;
+        }
+    }
+
+    uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
+    VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_ERROR);
+
+    cbor_encoder_init(&encoder, outPayload, cborLen, 0);
+    cborEncoderResult = cbor_encoder_create_map(&encoder, &spMap, spMapSize);
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding sp Map.");
+
+    // supported_profiles
+    if (propertiesToInclude[SP_SUPPORTED_PROFILES])
+    {
+        VERIFY_OR_LOG_AND_EXIT(TAG, (0 < sp->supportedLen),
+            "List of supported security profiles can't be empty", ERROR);
+
+        cborEncoderResult = cbor_encode_text_string(
+            &spMap, OIC_JSON_SUPPORTED_SP_NAME, strlen(OIC_JSON_SUPPORTED_SP_NAME));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult,
+            "Failed Adding supported_profiles Name Tag.");
+        OIC_LOG_V(DEBUG, TAG, "%s encoded sp %s tag.", __func__, OIC_JSON_SUPPORTED_SP_NAME);
+
+        CborEncoder supportedProfiles;
+        cborEncoderResult = cbor_encoder_create_array(&spMap, &supportedProfiles, sp->supportedLen);
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed creating supported_types Array.");
+        OIC_LOG_V(DEBUG, TAG, "%s created sp supported_profiles array.", __func__);
+        for(size_t i = 0; i < sp->supportedLen; i++)
+        {
+            char* curProfile = sp->supportedProfiles[i];
+            cborEncoderResult = cbor_encode_text_string(&supportedProfiles, curProfile, strlen(curProfile));
+            VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding supported_profiles Value.");
+            OIC_LOG_V(DEBUG, TAG, "%s encoded sp supported_profile value %s.", __func__, curProfile);
+        }
+
+        cborEncoderResult = cbor_encoder_close_container(&spMap, &supportedProfiles);
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing supportedProfiles.");
+        OIC_LOG_V(DEBUG, TAG, "%s closed sp supported_profiles map.", __func__);
+    }
+
+    // active profile
+    if (propertiesToInclude[SP_ACTIVE_PROFILE])
+    {
+        cborEncoderResult = cbor_encode_text_string(
+            &spMap, OIC_JSON_ACTIVE_SP_NAME, strlen(OIC_JSON_ACTIVE_SP_NAME));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding active_profile Name Tag.");
+        OIC_LOG_V(DEBUG, TAG, "%s encoded sp %s tag.", __func__, OIC_JSON_ACTIVE_SP_NAME);
+
+        cborEncoderResult = cbor_encode_text_string(
+            &spMap, sp->activeProfile, strlen(sp->activeProfile));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding supported_profiles Value.");
+        OIC_LOG_V(DEBUG, TAG, "%s encoded sp active_profile value %s.", __func__, sp->activeProfile);
+    }
+
+    // cred id
+    if (propertiesToInclude[SP_CRED_ID])
+    {
+        cborEncoderResult = cbor_encode_text_string(
+            &spMap, OIC_JSON_SP_CREDID_NAME, strlen(OIC_JSON_SP_CREDID_NAME));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding credid Name Tag.");
+        OIC_LOG_V(DEBUG, TAG, "%s encoded sp %s tag.", __func__, OIC_JSON_SP_CREDID_NAME);
+
+        cborEncoderResult = cbor_encode_int(&spMap, sp->credid);
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding sp credid Value.");
+        OIC_LOG_V(DEBUG, TAG, "%s encoded sp %d tag.", __func__, sp->credid);
+    }
+
+    // rt (mandatory)
+
+    CborEncoder rtArray;
+    cborEncoderResult = cbor_encode_text_string(
+        &spMap, OIC_JSON_RT_NAME, strlen(OIC_JSON_RT_NAME));
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&spMap, &rtArray, 1);
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding RT Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_SP,
+                strlen(OIC_RSRC_TYPE_SEC_SP));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding RT Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&spMap, &rtArray);
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing RT.");
+
+    // if (mandatory)
+
+    CborEncoder ifArray;
+    cborEncoderResult = cbor_encode_text_string(&spMap, OIC_JSON_IF_NAME,
+       strlen(OIC_JSON_IF_NAME));
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&spMap, &ifArray, 1);
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding IF Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
+                strlen(OC_RSRVD_INTERFACE_DEFAULT));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding IF Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&spMap, &ifArray);
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing IF.");
+
+    cborEncoderResult = cbor_encoder_close_container(&encoder, &spMap);
+    VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing SP Map.");
+
+    if (CborNoError == cborEncoderResult)
+    {
+        *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
+        *payload = outPayload;
+        ret = OC_STACK_OK;
+    }
+
+exit:
+    if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
+    {
+        // reallocate and try again!
+        OICFree(outPayload);
+        outPayload = NULL;
+
+        // Since the allocated initial memory failed, double the memory.
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
+        cborEncoderResult = CborNoError;
+        ret = SpToCBORPayloadPartial(sp, payload, &cborLen, propertiesToInclude);
+        if (OC_STACK_OK == ret)
+        {
+            *size = cborLen;
+        }
+    }
+
+    if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
+    {
+        OICFree(outPayload);
+        outPayload = NULL;
+        *payload = NULL;
+        *size = 0;
+        ret = OC_STACK_ERROR;
+    }
+
+    return ret;
+}
+
+/**
+ * Static method to extract a supported_profiles array from spMap.
+ *
+ * @param [i] spMap             sp map positioned at supported_profiles array
+ * @param [o] supportedProfiles allocated and extracted list of supported profile names
+ * @param [o] supportedLen      length of the extracted supportedProfiles array
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+ *
+ * @note: this fxn allocates the supportedProfiles array, free with OICFree when done
+*/
+static OCStackResult SupportedProfilesFromCBOR(CborValue *spMap,
+                                               char*** supportedProfiles,
+                                               size_t* supportedLen)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    CborError cborResult = CborNoError;
+    *supportedProfiles = NULL;
+    *supportedLen = 0;
+
+    size_t readLen = 0;
+
+    cborResult = cbor_value_get_array_length(spMap, supportedLen);
+    VERIFY_OR_LOG_AND_EXIT(TAG, (CborNoError == cborResult) && (0 != supportedLen),
+        "Failed to find sp supported_profiles array length", ERROR);
+
+    *supportedProfiles = (char**)OICCalloc(*supportedLen, sizeof(char*));
+    VERIFY_NOT_NULL(TAG, *supportedProfiles, ERROR);
+
+    CborValue supportedProfilesCbor;
+    cborResult = cbor_value_enter_container(spMap, &supportedProfilesCbor);
+    VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to enter SP supported_profiles array");
+
+    size_t numProfilesExtracted = 0;
+    for(size_t i = 0;
+       cbor_value_is_valid(&supportedProfilesCbor) &&
+       cbor_value_is_text_string(&supportedProfilesCbor); i++)
+    {
+        // Extract the current profile name
+        cborResult = cbor_value_dup_text_string(
+            &supportedProfilesCbor, &((*supportedProfiles)[i]), &readLen, NULL);
+        VERIFY_CBOR_SUCCESS(TAG, cborResult,
+            "Failed to extract SP security profile name from supported_profiles.");
+        numProfilesExtracted++;
+
+        // advance to the next profile
+        cborResult = cbor_value_advance(&supportedProfilesCbor);
+        VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to advance to the SP next security profile name.");
+    }
+
+    // Make sure we extracted the entire contents of the cbor array
+    VERIFY_OR_LOG_AND_EXIT(TAG, (*supportedLen == numProfilesExtracted),
+        "Not all of the profiles from SP supported_profiles were extracted", ERROR);
+
+    ret = OC_STACK_OK;
+
+exit:
+
+    if ((CborNoError != cborResult) && (NULL != *supportedProfiles))
+    {
+        OICFree(supportedProfiles);
+        *supportedProfiles = NULL;
+        *supportedLen = 0;
+        ret = OC_STACK_ERROR;
+    }
+
+    return ret;
+}
+
+/**
+ * Static method to extract the active_profile from a spMap, and determine the
+ * corresponding index into the supportedProfiles array
+ *
+ * @param [i] spMap             sp map positioned at supported_profiles map
+ * @param [i] supportedProfiles array of supported profile names
+ * @param [i] supportedLen      length of supportedProfiles array
+ *
+ * @param [o] activeProfile     active profile
+ *                              NULL on error
+ *
+ * @return ::OC_STACK_OK for Success, otherwise error value.
+ */
+static OCStackResult ActiveProfileFromCBOR(CborValue *spMap, char **activeProfile)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    CborError cborResult = CborNoError;
+    *activeProfile = NULL;
+
+    size_t readLen = 0;
+
+    // extract the active profile name
+    cborResult = cbor_value_dup_text_string(spMap, activeProfile, &readLen, NULL);
+    VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to extract SP active profile name.");
+
+    ret = OC_STACK_OK;
+
+exit:
+    return ret;
+}
+
+/**
+ * Static method to determine if a credid is required, and to extract it from spMap if so
+ * corresponding index into the supportedProfiles array
+ *
+ * @param [i] spMap              sp map positioned at location where credit will be if present
+ * @param [o] credid             credid extracted from spMap, if credid required
+ *                               If credid not required, value of credid is undefined
+ *
+ * @return ::OC_STACK_OK for Success, otherwise error value.
+ */
+static OCStackResult CredIdFromCBOR(CborValue *spMap,
+                                    uint16_t *credid)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    CborError cborResult = CborNoError;
+    *credid = 0;
+
+    uint64_t extractedCredid = 0;
+    cborResult = cbor_value_get_uint64(spMap, &extractedCredid);
+    VERIFY_CBOR_SUCCESS(TAG, cborResult, "Could not extract SP credid.");
+    *credid = (uint16_t)extractedCredid;
+
+    ret = OC_STACK_OK;
+
+exit:
+    return ret;
+}
+
+OCStackResult CBORPayloadToSp(const uint8_t *cborPayload,
+                              const size_t size,
+                              OicSecSp_t **secSp,
+                              bool *decodedProperties)
+{
+
+
+    if (NULL == cborPayload || NULL == secSp || NULL != *secSp || 0 == size)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OCStackResult ret = OC_STACK_ERROR;
+    CborError cborResult = CborNoError;
+
+    CborParser parser = { .end = NULL };
+    CborValue spCbor = { .parser = NULL };
+    CborValue spMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
+
+    OicSecSp_t *sp = NULL;
+
+    if (NULL != decodedProperties)
+    {
+        SetAllSpProps(decodedProperties, false);
+    }
+
+    // init cbor parser
+    cbor_parser_init(cborPayload, size, 0, &parser, &spCbor);
+
+    // allocate sp struct
+    sp = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
+    VERIFY_NOT_NULL(TAG, sp, ERROR);
+
+    // Enter sp map
+    cborResult = cbor_value_enter_container(&spCbor, &spMap);
+    VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to enter the SP map");
+
+    // loop over all cbor entries looking for known keys
+    char* tagName = NULL;
+    size_t tagLen = 0;
+    while (cbor_value_is_valid(&spMap))
+    {
+        // Determine the next tag and advance to the corresponding value
+        CborType type = cbor_value_get_type(&spMap);
+        if (type == CborTextStringType && cbor_value_is_text_string(&spMap))
+        {
+            cborResult = cbor_value_dup_text_string(&spMap, &tagName, &tagLen, NULL);
+            VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to find next tag name in SP Map.");
+            cborResult = cbor_value_advance(&spMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed Advancing Value in SP Map.");
+        }
+
+        if(NULL != tagName)
+        {
+            // supported_profiles
+            if (strcmp(tagName, OIC_JSON_SUPPORTED_SP_NAME) == 0)
+            {
+                ret = SupportedProfilesFromCBOR(
+                    &spMap, &sp->supportedProfiles, &sp->supportedLen);
+                VERIFY_OR_LOG_AND_EXIT(TAG, OC_STACK_OK == ret,
+                    "Failed to extract list of supported profiles", ERROR);
+                if (NULL != decodedProperties)
+                {
+                    decodedProperties[SP_SUPPORTED_PROFILES] = true;
+                }
+            }
+
+            // active profile
+            else if (strcmp(tagName, OIC_JSON_ACTIVE_SP_NAME) == 0)
+            {
+                ret = ActiveProfileFromCBOR(&spMap, &sp->activeProfile);
+                VERIFY_OR_LOG_AND_EXIT(TAG, (OC_STACK_OK == ret) && (NULL != sp->activeProfile),
+                    "Failed to extract SP active profile", ERROR);
+                if (NULL != decodedProperties)
+                {
+                    decodedProperties[SP_ACTIVE_PROFILE] = true;
+                }
+            }
+
+            // credid
+            else if (strcmp(tagName, OIC_JSON_SP_CREDID_NAME) == 0)
+            {
+                ret = CredIdFromCBOR(&spMap, &sp->credid);
+                VERIFY_OR_LOG_AND_EXIT(TAG, (OC_STACK_OK == ret), "Failed to extract SP cred id", ERROR);
+                if (NULL != decodedProperties)
+                {
+                    decodedProperties[SP_CRED_ID] = true;
+                }
+            }
+
+            // advance to the next tag
+            if (cbor_value_is_valid(&spMap))
+            {
+                cborResult = cbor_value_advance(&spMap);
+                VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed Advancing SP Map.");
+            }
+
+            // cbor using malloc directly, so free() used instead of OICFree
+            free(tagName);
+            tagName = NULL;
+        }
+    }
+
+    *secSp = sp;
+    ret = OC_STACK_OK;
+
+exit:
+    if (CborNoError != cborResult)
+    {
+        OIC_LOG(ERROR, TAG, "CBORPayloadToSp failed");
+        DeleteSpBinData(sp);
+        sp = NULL;
+        *secSp = NULL;
+        ret = OC_STACK_ERROR;
+    }
+
+    return ret;
+}
+
+void DeleteSupportedProfiles(size_t supportedLen, char** supportedProfiles)
+{
+    if ((0 < supportedLen) && (NULL != supportedProfiles))
+    {
+        for(size_t i = 0; i < supportedLen; i++)
+        {
+            if(NULL != supportedProfiles[i])
+            {
+                OICFree(supportedProfiles[i]);
+            }
+        }
+    }
+    if (NULL != supportedProfiles)
+    {
+        OICFree(supportedProfiles);
+    }
+}
+
+void DeleteSpBinData(OicSecSp_t* sp)
+{
+    if ((NULL != sp) && (sp != &gDefaultSp))
+    {
+        DeleteSupportedProfiles(sp->supportedLen, sp->supportedProfiles);
+        sp->supportedLen = 0;
+        sp->supportedProfiles = NULL;
+
+        if (NULL != sp->activeProfile)
+        {
+            OICFree(sp->activeProfile);
+        }
+        sp->activeProfile = NULL;
+        sp->credid = 0;
+    }
+}
+
+bool SpRequiresCred(char* spName)
+{
+    if (NULL == spName)
+    {
+        OIC_LOG(WARNING, TAG, "NULL profile name supplied for cred check");
+        return false;
+    }
+
+    if ( (0 == strcmp(spName, "oic.sec.sp.black")) ||
+         (0 == strcmp(spName, "oic.sec.sp.blue")))
+    {
+        return true;
+    }
+    return false;
+}
+
+bool RequiredSpPropsPresentAndValid(OicSecSp_t* sp, bool *propertiesPresent)
+{
+    bool requiredPropsPresentAndValid = false;
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (true == propertiesPresent[SP_SUPPORTED_PROFILES]),
+        "Required SP property supported_profiles not present", WARNING);
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, ((NULL != sp->supportedProfiles) && (0 < sp->supportedLen)),
+        "Required SP property supported_profiles list is empty", WARNING);
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (true == propertiesPresent[SP_ACTIVE_PROFILE]),
+        "Required SP property active_profile not present", WARNING);
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != sp->activeProfile),
+        "Required SP property active_profile is invalid", WARNING);
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (0 <= ProfileIdx(sp->supportedLen, sp->supportedProfiles, sp->activeProfile)),
+        "Active_profile is not contained in supported_profiles list", WARNING);
+
+    VERIFY_OR_LOG_AND_EXIT(TAG,
+        !((true == SpRequiresCred(sp->activeProfile)) &&  (false == propertiesPresent[SP_CRED_ID])),
+        "Active profile requires credential, but none is present", WARNING);
+
+    requiredPropsPresentAndValid = true;
+
+exit:
+
+    return requiredPropsPresentAndValid;
+}
+
+/**
+ * Get the default value.
+ *
+ * @return the gDefaultSp pointer.
+ */
+static OicSecSp_t* GetSpDefault()
+{
+    return &gDefaultSp;
+}
+
+static bool ValidateQuery(const char * query)
+{
+    OIC_LOG (DEBUG, TAG, "In ValidateQuery");
+    if(NULL == gSp)
+    {
+        return false;
+    }
+
+    bool bInterfaceQry = false;      // does querystring contains 'if' query ?
+    bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
+
+    OicParseQueryIter_t parseIter = {.attrPos = NULL};
+
+    ParseQueryIterInit((unsigned char*)query, &parseIter);
+
+    while (GetNextQuery(&parseIter))
+    {
+        if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
+        {
+            bInterfaceQry = true;
+            if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
+            {
+                bInterfaceMatch = true;
+            }
+        }
+    }
+    return (bInterfaceQry ? bInterfaceMatch: true);
+}
+
+/**
+ * The entity handler determines how to process a GET request.
+ */
+static OCEntityHandlerResult HandleSpGetRequest (const OCEntityHandlerRequest * ehRequest)
+{
+    OCEntityHandlerResult ehRet = OC_EH_OK;
+
+    OIC_LOG(INFO, TAG, "HandleSpGetRequest  processing GET request");
+
+    //Checking if Get request is a query.
+    if (ehRequest->query)
+    {
+        OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
+        OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
+        if (!ValidateQuery(ehRequest->query))
+        {
+            ehRet = OC_EH_ERROR;
+        }
+    }
+
+    /*
+     * For GET or Valid Query request return pstat resource CBOR payload.
+     * For non-valid query return NULL payload.
+     * A device will 'always' have a default Pstat, so PstatToCBORPayload will
+     * return valid pstat resource json.
+     */
+    size_t size = 0;
+    uint8_t *payload = NULL;
+    if (ehRet == OC_EH_OK)
+    {
+        if(OC_STACK_OK != SpToCBORPayload(gSp, &payload, &size))
+        {
+            OIC_LOG_V(WARNING, TAG, "%s PstatToCBORPayload failed.", __func__);
+        }
+    }
+
+    // Send response payload to request originator
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
+                   OC_EH_OK : OC_EH_ERROR;
+    OICFree(payload);
+
+    LogSp(gSp, DEBUG, TAG, "SP resource being sent in response to GET:");
+
+    return ehRet;
+}
+
+static bool UpdatePersistentStorage(OicSecSp_t *sp)
+{
+    bool bRet = false;
+
+    size_t size = 0;
+    uint8_t *cborPayload = NULL;
+    OCStackResult ret = SpToCBORPayload(sp, &cborPayload, &size);
+    if (OC_STACK_OK == ret)
+    {
+        if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_SP_NAME, cborPayload, size))
+        {
+            bRet = true;
+        }
+        OICFree(cborPayload);
+    }
+
+    return bRet;
+}
+
+static char** SpSupportedProfilesDup(size_t supportedLen, char** supportedProfilesSrc)
+{
+    OCStackResult status = OC_STACK_ERROR;
+    char** supportedProfilesDup = NULL;
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (0 < supportedLen),
+        "sp supported profiles duplicate: invalid length for supported_profiles array", ERROR);
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != supportedProfilesSrc),
+        "sp  supported profiles duplicate: supported_profiles array not present", ERROR);
+
+    // allocate and populate list of supported profiles
+    supportedProfilesDup = (char**)OICCalloc(supportedLen, sizeof(char*));
+    VERIFY_NOT_NULL(TAG, supportedProfilesDup, ERROR);
+
+    for(size_t i = 0; i < supportedLen; i++)
+    {
+        if (NULL != supportedProfilesSrc[i])
+        {
+            supportedProfilesDup[i] = OICStrdup(supportedProfilesSrc[i]);
+            VERIFY_NOT_NULL(TAG, supportedProfilesDup[i], ERROR);
+        }
+        else
+        {
+            OIC_LOG_V(WARNING, TAG, "SP supported profiles entry %lu is null, skipping", (unsigned long)i);
+
+        }
+    }
+
+    status = OC_STACK_OK;
+
+exit:
+    if (OC_STACK_OK != status)
+    {
+        if (NULL != supportedProfilesDup)
+        {
+            DeleteSupportedProfiles(supportedLen, supportedProfilesDup);
+        }
+        return NULL;
+    }
+
+    return supportedProfilesDup;
+}
+
+
+// allocate new SP, setting props to spToDup.  Returns NULL on error
+static OicSecSp_t* SpDup(OicSecSp_t* spToDup)
+{
+    OicSecSp_t *spToRet = NULL;
+
+    OicSecSp_t *dupSp = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
+    VERIFY_NOT_NULL(TAG, dupSp, ERROR);
+
+    dupSp->supportedLen = spToDup->supportedLen;
+    dupSp->credid = spToDup->credid;
+    dupSp->activeProfile = OICStrdup(spToDup->activeProfile);
+    VERIFY_NOT_NULL(TAG, dupSp->activeProfile, ERROR);
+
+    dupSp->supportedProfiles = SpSupportedProfilesDup(spToDup->supportedLen, spToDup->supportedProfiles);
+    VERIFY_NOT_NULL(TAG, dupSp->supportedProfiles, ERROR);
+
+    spToRet = dupSp;
+
+exit:
+
+    if (NULL == spToRet)
+    {
+        DeleteSpBinData(dupSp);
+    }
+
+    return spToRet;
+}
+
+OCStackResult InstallTestSp(OicSecSp_t* testSp)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    OicSecSp_t* spCopy = SpDup(testSp);
+    VERIFY_NOT_NULL(TAG, spCopy, ERROR);
+
+    ret = OC_STACK_OK;
+
+exit:
+
+    if(OC_STACK_OK != ret )
+    {
+        DeleteSpBinData(spCopy);
+    }
+    else
+    {
+        DeleteSpBinData(gSp);
+        gSp = spCopy;
+    }
+
+    return ret;
+}
+
+/**
+ * The entity handler determines how to process a POST request.
+ * Per the REST paradigm, POST can also be used to update representation of existing
+ * resource or create a new resource.
+ */
+static OCEntityHandlerResult HandleSpPostRequest(OCEntityHandlerRequest *ehRequest)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
+
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    OCStackResult ret = OC_STACK_ERROR;
+
+    OicSecSp_t *spIncoming = NULL;
+    OicSecSp_t *spUpdate = NULL;
+
+    char** supportedProfilesSrc = NULL;
+    char* activeProfileSrc = NULL;
+
+    bool newSupportedProfiles = false;
+    bool newActiveProfile = false;
+    bool newCredid = false;
+
+    uint8_t *payload = NULL;
+    size_t size = 0;
+
+    VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != ehRequest->payload), "sp POST : no payload supplied ", ERROR);
+    VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != gSp), "sp POST : corrupt internal SP resource ", ERROR);
+
+    payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
+    size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
+    VERIFY_NOT_NULL(TAG, payload, ERROR);
+
+    bool decodedProperties[SP_PROPERTY_COUNT];
+    ret = CBORPayloadToSp(payload, size, &spIncoming, decodedProperties);
+    VERIFY_OR_LOG_AND_EXIT(TAG, ((OC_STACK_OK == ret) && (NULL != spIncoming)),
+        "sp POST : error decoding incoming payload", ERROR);
+
+    newSupportedProfiles = decodedProperties[SP_SUPPORTED_PROFILES];
+    newActiveProfile = decodedProperties[SP_ACTIVE_PROFILE];
+    newCredid = decodedProperties[SP_CRED_ID];
+
+    spUpdate = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
+    VERIFY_NOT_NULL(TAG, spUpdate, ERROR);
+
+    // supported profiles
+    spUpdate->supportedLen = newSupportedProfiles ? spIncoming->supportedLen : gSp->supportedLen;
+    supportedProfilesSrc = newSupportedProfiles ? spIncoming->supportedProfiles : gSp->supportedProfiles;
+    spUpdate->supportedProfiles = SpSupportedProfilesDup(spUpdate->supportedLen, supportedProfilesSrc);
+    VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != spUpdate),
+        "Problems duplicating active profiles list for sp POST", WARNING);
+
+    // active profile
+    activeProfileSrc = newActiveProfile ? spIncoming->activeProfile : gSp->activeProfile;
+    spUpdate->activeProfile = OICStrdup(activeProfileSrc);
+    VERIFY_NOT_NULL(TAG, spUpdate->activeProfile, ERROR);
+
+    // make sure active profile is in supported profiles list
+    VERIFY_OR_LOG_AND_EXIT(TAG,
+        (0 <= ProfileIdx(spUpdate->supportedLen, spUpdate->supportedProfiles, spUpdate->activeProfile)),
+        "sp POST : active_profile is not contained in supported_profiles list", ERROR);
+
+    // credid
+    if (true == SpRequiresCred(spUpdate->activeProfile))
+    {
+        spUpdate->credid = newCredid ? spIncoming->credid : gSp->credid;
+    }
+    else
+    {
+        spUpdate->credid = 0;
+    }
+
+    // Before we update the sp, lets make sure everthing is valid
+    VERIFY_OR_LOG_AND_EXIT(TAG,
+        (true == RequiredSpPropsPresentAndValid(spUpdate, gAllProps)),
+        "sp POST : update version of security profiles not valid, not updating", ERROR);
+
+    // whew ...
+    ret = OC_STACK_OK;
+
+exit:
+
+    if ((OC_STACK_OK == ret) && (NULL != spUpdate))
+    {
+        if( true != UpdatePersistentStorage(spUpdate))
+        {
+            OIC_LOG_V(DEBUG, TAG, "sp POST : Problems updating persistant storage");
+            ehRet = OC_EH_NOT_ACCEPTABLE;
+
+        }
+        else
+        {
+            // replace our internal copy
+            DeleteSpBinData(gSp);
+            gSp = spUpdate;
+
+            LogSp(gSp, DEBUG, TAG, "State of SP resource after being updated by POST:");
+
+            ehRet = OC_EH_OK;
+        }
+    }
+    else
+    {
+        ehRet = OC_EH_NOT_ACCEPTABLE;
+    }
+
+    if ((OC_STACK_OK != ret) && (NULL != spUpdate))
+    {
+        DeleteSpBinData(spUpdate);
+    }
+
+    DeleteSpBinData(spIncoming);
+
+    // Send response payload to request originator
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+        OC_EH_OK : OC_EH_ERROR;
+
+    OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
+
+    return ehRet;
+}
+
+int ProfileIdx( size_t supportedLen, char **supportedProfiles, char *profileName)
+{
+    if ((NULL != supportedProfiles) && (NULL != profileName))
+    {
+        for (size_t i = 0; i < supportedLen; i++)
+        {
+            if ((NULL != supportedProfiles[i]) && (0 == strcmp(profileName, supportedProfiles[i])))
+            {
+                return (int)i;
+            }
+        }
+    }
+    return -1;
+}
+
+OCEntityHandlerResult SpEntityHandler(OCEntityHandlerFlag flag,
+                                      OCEntityHandlerRequest * ehRequest,
+                                      void* callbackParameter)
+{
+    OC_UNUSED(callbackParameter);
+    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+
+    // This method will handle REST request (GET/POST) for /oic/sec/sp
+    if (flag & OC_REQUEST_FLAG)
+    {
+        OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
+        switch (ehRequest->method)
+        {
+            case OC_REST_GET:
+                ehRet = HandleSpGetRequest(ehRequest);
+                break;
+            case OC_REST_POST:
+                ehRet = HandleSpPostRequest(ehRequest);
+                break;
+            default:
+                ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+                    OC_EH_OK : OC_EH_ERROR;
+                break;
+        }
+    }
+    return ehRet;
+}
+
+OCStackResult CreateSpResource()
+{
+    OCStackResult ret = OCCreateResource(&gSpHandle,
+                                         OIC_RSRC_TYPE_SEC_SP,
+                                         OC_RSRVD_INTERFACE_DEFAULT,
+                                         OIC_RSRC_SP_URI,
+                                         SpEntityHandler,
+                                         NULL,
+                                         OC_SECURE |
+                                         OC_DISCOVERABLE);
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG(FATAL, TAG, "Unable to instantiate sp resource");
+        DeInitSpResource();
+    }
+    return ret;
+}
+
+OCStackResult DeInitSpResource()
+{
+    if (gSp != &gDefaultSp)
+    {
+        DeleteSpBinData(gSp);
+        gSp = NULL;
+    }
+    return OCDeleteResource(gSpHandle);
+}
+
+OCStackResult InitSpResource()
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    // Read sp resource from PS
+    uint8_t *data = NULL;
+    size_t size = 0;
+    ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_SP_NAME, &data, &size);
+
+    // If database read failed
+    if (OC_STACK_OK != ret)
+    {
+        OIC_LOG (DEBUG, TAG, "GetSecureVirtualDatabaseFromPS failed trying to read sp data");
+    }
+    if (data)
+    {
+        // Read sp resource from PS
+        bool decodedProperties[SP_PROPERTY_COUNT];
+        ret = CBORPayloadToSp(data, size, &gSp, decodedProperties);
+        OICFree(data);
+
+        if (false == RequiredSpPropsPresentAndValid(gSp, decodedProperties))
+        {
+            OIC_LOG (WARNING, TAG, "One or more required sp properties missing from  initialization database");
+        }
+    }
+
+    if ((OC_STACK_OK != ret) || !gSp)
+    {
+        gSp = GetSpDefault();
+    }
+    VERIFY_NOT_NULL(TAG, gSp, FATAL);
+
+    // Instantiate 'oic.sec.SP'
+    ret = CreateSpResource();
+
+exit:
+
+    if (OC_STACK_OK != ret)
+    {
+        DeInitSpResource();
+    }
+    else
+    {
+        LogSp(gSp, DEBUG, TAG, "SP resource after startup initialization");
+    }
+
+    return ret;
+}
+
+bool IsPropArraySame(bool* spProps1, bool* spProps2)
+{
+    for (int i = 0; i < SP_PROPERTY_COUNT; i++)
+    {
+        if ( spProps1[i] != spProps2[i])
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool IsSpSame(OicSecSp_t* sp1, OicSecSp_t* sp2, bool *propertiesToCheck)
+{
+    if ((NULL == sp1) || (NULL == sp2))
+    {
+        return false;
+    }
+
+    if (true == propertiesToCheck[SP_SUPPORTED_PROFILES] || (NULL == propertiesToCheck))
+    {
+        if ((NULL == sp1->supportedProfiles) || (NULL == sp2->supportedProfiles) ||
+            (sp1->supportedLen != sp2->supportedLen))
+        {
+            return false;
+        }
+
+        // check for 100% overlap in supported profiles lists
+        for (size_t i = 0; i < sp1->supportedLen; i++)
+        {
+            if (0 > ProfileIdx(sp1->supportedLen, sp1->supportedProfiles, sp2->supportedProfiles[i]))
+            {
+                return false;
+            }
+        }
+
+    }
+
+    if (true == propertiesToCheck[SP_ACTIVE_PROFILE] || (NULL == propertiesToCheck))
+    {
+        if ((NULL == sp1->activeProfile) || (NULL == sp2->activeProfile) ||
+            (0 != strcmp(sp1->activeProfile, sp2->activeProfile)))
+        {
+            return false;
+        }
+    }
+
+    if (true == propertiesToCheck[SP_CRED_ID] || (NULL == propertiesToCheck))
+    {
+        if (sp1->credid != sp2->credid)
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void SetAllSpProps(bool* spProps, bool setTo)
+{
+    for (int i = 0; i < SP_PROPERTY_COUNT; i++)
+    {
+        spProps[i] = setTo;
+    }
+}
+
+
+void LogSp(OicSecSp_t* sp, int level, const char* tag, const char* msg)
+{
+    // some compilers not flagging the use of level and tag in the logging
+    // macros as being used.  This is to get around these compiler warnings
+    (void) level;
+    (void) tag;
+    (void) msg;
+
+    if (NULL != msg)
+    {
+        OIC_LOG(level, tag, "-------------------------------------------------");
+        OIC_LOG_V(level, tag, "%s", msg);
+    }
+
+    OIC_LOG(level, tag, "-------------------------------------------------");
+    OIC_LOG_V(level, tag, "# security profiles supported: %lu", (unsigned long)sp->supportedLen);
+    for (size_t i = 0; i < sp->supportedLen; i++)
+    {
+        OIC_LOG_V(level, tag, "  %lu: %s", (unsigned long)i, sp->supportedProfiles[i]);
+    }
+    OIC_LOG_V(level, tag, "Active security profile: %s", sp->activeProfile);
+    OIC_LOG_V(level, tag, "Active requires cred: %s", (true == SpRequiresCred(sp->activeProfile) ? "yes" : "no"));
+    OIC_LOG_V(level, TAG, "credid: %hu", sp->credid);
+    OIC_LOG(level, tag, "-------------------------------------------------");
+}
index 17ea2a1..8ac49aa 100644 (file)
@@ -49,6 +49,11 @@ const char * OIC_RSRC_TYPE_SEC_PSTAT = "oic.r.pstat";
 const char * OIC_RSRC_PSTAT_URI =  "/oic/sec/pstat";
 const char * OIC_JSON_PSTAT_NAME = "pstat";
 
+//sp
+const char * OIC_RSRC_TYPE_SEC_SP = "oic.r.sp";
+const char * OIC_RSRC_SP_URI =  "/oic/sec/sp";
+const char * OIC_JSON_SP_NAME = "sp";
+
 //doxm
 const char * OIC_RSRC_TYPE_SEC_DOXM = "oic.r.doxm";
 const char * OIC_RSRC_DOXM_URI =  "/oic/sec/doxm";
@@ -122,6 +127,9 @@ const char * OIC_JSON_CM_NAME = "cm";
 const char * OIC_JSON_TM_NAME = "tm";
 const char * OIC_JSON_OM_NAME = "om";
 const char * OIC_JSON_SM_NAME = "sm";
+const char * OIC_JSON_SUPPORTED_SP_NAME = "supported_profiles";
+const char * OIC_JSON_ACTIVE_SP_NAME = "active_profile";
+const char * OIC_JSON_SP_CREDID_NAME = "credid";
 const char * OIC_JSON_CREDID_NAME = "credid";
 const char * OIC_JSON_SUBJECT_NAME = "subject";
 const char * OIC_JSON_SUBJECTID_NAME = "subjectuuid";
index 02e42c9..831ed06 100644 (file)
@@ -243,6 +243,7 @@ bool SRMIsSecurityResourceURI(const char* uri)
         OIC_RSRC_AMACL_URI,
         OIC_RSRC_CRL_URI,
         OIC_RSRC_CRED_URI,
+        OIC_RSRC_SP_URI,
         OIC_RSRC_CSR_URI,
         OIC_RSRC_ACL_URI,
         OIC_RSRC_ACL2_URI,
index 6e948b0..4099071 100644 (file)
@@ -35,6 +35,7 @@
 #include "srmutility.h"
 #include "aclresource.h"
 #include "pstatresource.h"
+#include "spresource.h"
 #include "experimental/doxmresource.h"
 #include "amaclresource.h"
 #include "credresource.h"
@@ -49,6 +50,7 @@
 #define DELTA_ERROR 0.0000001
 
 static OicSecPstat_t *JSONToPstatBin(const char *jsonStr);
+static OicSecSp_t *JSONToSpBin(const char *jsonStr);
 static OicSecDoxm_t *JSONToDoxmBin(const char *jsonStr);
 static OicSecAcl_t *JSONToAclBin(OicSecAclVersion_t *aclVersion,
                                  const char *jsonStr);
@@ -311,6 +313,7 @@ static OCStackResult ConvertOCJSONStringToCBORFile(const char *jsonStr, const ch
     OCStackResult ret = OC_STACK_ERROR;
     uint8_t *aclCbor = NULL;
     uint8_t *pstatCbor = NULL;
+    uint8_t *spCbor = NULL;
     uint8_t *doxmCbor = NULL;
     uint8_t *amaclCbor = NULL;
     uint8_t *credCbor = NULL;
@@ -368,6 +371,31 @@ static OCStackResult ConvertOCJSONStringToCBORFile(const char *jsonStr, const ch
         printf("JSON contains no /pstat\n");
     }
 
+    value = cJSON_GetObjectItem(jsonRoot, OIC_JSON_SP_NAME);
+    text = cJSON_PrintUnformatted(value);
+    printf("/sp json : \n%s\n", text);
+    size_t spCborSize = 0;
+    OICFree(text);
+    if (NULL != value)
+    {
+        OicSecSp_t *sp = JSONToSpBin(jsonStr);;
+        VERIFY_NOT_NULL(TAG, sp, FATAL);
+
+        ret = SpToCBORPayload(sp, &spCbor, &spCborSize);
+        if (OC_STACK_OK != ret)
+        {
+            OIC_LOG (ERROR, TAG, "Failed converting sp to Cbor Payload");
+            DeleteSpBinData(sp);
+            goto exit;
+        }
+        printf("SP Cbor Size: %" PRIuPTR "\n", spCborSize);
+        DeleteSpBinData(sp);
+    }
+    else
+    {
+        printf("JSON contains no /sp\n");
+    }
+
     value = cJSON_GetObjectItem(jsonRoot, OIC_JSON_DOXM_NAME);
     text = cJSON_PrintUnformatted(value);
     printf("/doxm json : \n%s\n", text);
@@ -464,8 +492,8 @@ static OCStackResult ConvertOCJSONStringToCBORFile(const char *jsonStr, const ch
     }
 
     CborEncoder encoder;
-    size_t cborSize = aclCborSize + pstatCborSize + doxmCborSize + credCborSize + amaclCborSize +
-                      dpCborSize;
+    size_t cborSize = aclCborSize + pstatCborSize + spCborSize + doxmCborSize +
+                      credCborSize + amaclCborSize + dpCborSize;
 
     printf("Total Cbor Size : %" PRIuPTR "\n", cborSize);
     cborSize += 255; // buffer margin for adding map and byte string
@@ -475,6 +503,13 @@ static OCStackResult ConvertOCJSONStringToCBORFile(const char *jsonStr, const ch
     CborEncoder map;
     CborError cborEncoderResult = cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Creating Main Map.");
+    if ((spCborSize > 0) && spCbor)
+    {
+        cborEncoderResult = cbor_encode_text_string(&map, OIC_JSON_SP_NAME, strlen(OIC_JSON_SP_NAME));
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding SP Name.");
+        cborEncoderResult = cbor_encode_byte_string(&map, spCbor, spCborSize);
+        VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding SP Value.");
+    }
     if ((aclCborSize > 0) && aclCbor)
     {
         cborEncoderResult = cbor_encode_text_string(&map, OIC_JSON_ACL_NAME, strlen(OIC_JSON_ACL_NAME));
@@ -482,7 +517,6 @@ static OCStackResult ConvertOCJSONStringToCBORFile(const char *jsonStr, const ch
         cborEncoderResult = cbor_encode_byte_string(&map, aclCbor, aclCborSize);
         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding ACL Value.");
     }
-
     if ((pstatCborSize > 0) && pstatCbor)
     {
         cborEncoderResult = cbor_encode_text_string(&map, OIC_JSON_PSTAT_NAME, strlen(OIC_JSON_PSTAT_NAME));
@@ -536,6 +570,7 @@ exit:
     OICFree(aclCbor);
     OICFree(doxmCbor);
     OICFree(pstatCbor);
+    OICFree(spCbor);
     OICFree(amaclCbor);
     OICFree(credCbor);
     OICFree(dpCbor);
@@ -1148,6 +1183,93 @@ exit:
     return pstat;
 }
 
+static OicSecSp_t *JSONToSpBin(const char *jsonStr)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    cJSON *jsonRoot = NULL;
+    cJSON *jsonSp = NULL;
+    cJSON *jsonActiveProfileName = NULL;
+    cJSON *jsonSupportedProfilesArray = NULL;
+    cJSON *jsonProfileName = NULL;
+    cJSON *jsonCredid = NULL;
+
+    OicSecSp_t *sp = NULL;
+
+    VERIFY_NOT_NULL(TAG, jsonStr, INFO);
+    jsonRoot = cJSON_Parse(jsonStr);
+    VERIFY_NOT_NULL(TAG, jsonRoot, INFO);
+    jsonSp = cJSON_GetObjectItem(jsonRoot, OIC_JSON_SP_NAME);
+    VERIFY_NOT_NULL(TAG, jsonSp, INFO);
+    sp = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
+    VERIFY_NOT_NULL(TAG, sp, INFO);
+
+    // Supported Profiles
+
+    jsonSupportedProfilesArray = cJSON_GetObjectItem(jsonSp, OIC_JSON_SUPPORTED_SP_NAME);
+    VERIFY_NOT_NULL(TAG, jsonSupportedProfilesArray, ERROR);
+    VERIFY_SUCCESS(TAG, (cJSON_Array == jsonSupportedProfilesArray->type), ERROR);
+    sp->supportedLen = cJSON_GetArraySize(jsonSupportedProfilesArray);
+    VERIFY_SUCCESS(TAG, (0 < sp->supportedLen), ERROR);
+    sp->supportedProfiles = (char **)OICCalloc(sp->supportedLen, sizeof(char *));
+    VERIFY_NOT_NULL(TAG, (sp->supportedProfiles), ERROR);
+
+    for (size_t i = 0; i < sp->supportedLen; i++)
+    {
+        jsonProfileName = cJSON_GetArrayItem(jsonSupportedProfilesArray, i);
+        VERIFY_NOT_NULL(TAG, jsonProfileName, ERROR);
+        sp->supportedProfiles[i] = OICStrdup(jsonProfileName->valuestring);
+        VERIFY_NOT_NULL(TAG, (sp->supportedProfiles[i]), ERROR);
+    }
+
+    // Active Profile
+
+    jsonActiveProfileName = cJSON_GetObjectItem(jsonSp, OIC_JSON_ACTIVE_SP_NAME);
+    VERIFY_NOT_NULL(TAG, jsonActiveProfileName, ERROR);
+    VERIFY_SUCCESS(TAG, (cJSON_String == jsonActiveProfileName->type), ERROR);
+    sp->activeProfile = OICStrdup(jsonActiveProfileName->valuestring);
+    VERIFY_NOT_NULL(TAG, (sp->activeProfile), ERROR);
+
+    if (0 > ProfileIdx(sp->supportedLen, sp->supportedProfiles, sp->activeProfile))
+    {
+        OIC_LOG_V(ERROR, TAG, "sp active profile %s not contained in supported profile list", sp->activeProfile);
+        goto exit;
+    }
+
+    // credid
+
+    jsonCredid = cJSON_GetObjectItem(jsonSp, OIC_JSON_SP_CREDID_NAME);
+    if (NULL == jsonCredid)
+    {
+        if (true == SpRequiresCred(sp->activeProfile))
+        {
+            OIC_LOG(ERROR, TAG, "sp active profile requires cred, but credid not present in json");
+            goto exit;
+        }
+        else
+        {
+            sp->credid = 0;
+        }
+    }
+    else
+    {
+        VERIFY_SUCCESS(TAG, (cJSON_Number == jsonCredid->type), ERROR);
+        sp->credid = (uint16_t)jsonCredid->valueint;
+    }
+
+    ret = OC_STACK_OK;
+
+exit:
+    cJSON_Delete(jsonRoot);
+    if (OC_STACK_OK != ret)
+    {
+        DeleteSpBinData(sp);
+        sp = NULL;
+    }
+    printf("OUT %s: %s\n", __func__, (sp != NULL) ? "success" : "failure");
+    return sp;
+}
+
 static OicEncodingType_t GetEncodingTypeFromStr(const char *encodingType)
 {
     if (strcmp(OIC_SEC_ENCODING_RAW, encodingType) == 0)
index f7278e2..5cfe8d5 100644 (file)
@@ -96,6 +96,7 @@ unittest = srmtest_env.Program('unittest', [
     'policyengine.cpp',
     'securityresourcemanager.cpp',
     'credentialresource.cpp',
+    'spresource.cpp',
     'srmutility.cpp',
     'iotvticalendartest.cpp',
     'base64tests.cpp',
diff --git a/resource/csdk/security/unittest/spresource.cpp b/resource/csdk/security/unittest/spresource.cpp
new file mode 100644 (file)
index 0000000..b115e42
--- /dev/null
@@ -0,0 +1,208 @@
+//******************************************************************
+// Copyright 2018 Cable Television Laboratories, Inc.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific lan guage governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <gtest/gtest.h>
+#include "ocpayload.h"
+#include "ocstack.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "resourcemanager.h"
+#include "spresource.h"
+#include "srmtestcommon.h"
+#include "srmutility.h"
+#include "psinterface.h"
+#include "security_internals.h"
+#include "experimental/logger.h"
+
+#define TAG "SRM-SP-UT"
+
+// helper fxns
+static void TestEncodeDecode(OicSecSp_t* spToTest, bool* propsToTest, bool checkForValidSp);
+static void TestInit(OicSecSp_t* testSp, bool* spProps);
+
+//*****************************************************************************
+// Test data
+//*****************************************************************************
+
+static char s_spBlackName[] = "oic.sec.sp.black";
+static char s_spBlueName[] = "oic.sec.sp.blue";
+static char s_spBaselineName[] = "oic.sec.sp.baseline";
+
+static char* s_profileArray[] = { NULL, NULL, NULL, NULL, NULL, };
+static OicSecSp_t s_testSp =
+{
+    0,                      // supportedLen
+    s_profileArray,         // supportedProfiles[0]
+    NULL,                   // activeProfile
+    0                       // credid
+};
+
+
+//*****************************************************************************
+// Tests
+//*****************************************************************************
+
+TEST(SPResourceTest, CBORFullEncodingPositive)
+{
+    bool propsToTest[SP_PROPERTY_COUNT];
+
+    // all supported profiles
+    TestInit(&s_testSp, propsToTest);
+    SetAllSpProps(propsToTest, true);
+    s_testSp.supportedLen = 3;
+    s_testSp.supportedProfiles[0] = s_spBlueName;
+    s_testSp.supportedProfiles[1] = s_spBaselineName;
+    s_testSp.supportedProfiles[2] = s_spBlackName;
+    s_testSp.activeProfile = s_spBlackName;
+    s_testSp.credid = 1;
+    TestEncodeDecode(&s_testSp, propsToTest, true);
+
+    // default configuration
+    TestInit(&s_testSp, propsToTest);
+    SetAllSpProps(propsToTest, true);
+    s_testSp.supportedLen = 1;
+    s_testSp.supportedProfiles[0] = s_spBaselineName;
+    s_testSp.activeProfile = s_spBaselineName;
+    TestEncodeDecode(&s_testSp, propsToTest, true);
+
+    // one non baseline
+    TestInit(&s_testSp, propsToTest);
+    SetAllSpProps(propsToTest, true);
+    s_testSp.supportedLen = 2;
+    s_testSp.supportedProfiles[0] = s_spBaselineName;
+    s_testSp.supportedProfiles[1] = s_spBlackName;
+    s_testSp.activeProfile = s_spBlackName;
+    s_testSp.credid = 22;
+    TestEncodeDecode(&s_testSp, propsToTest, true);
+}
+
+TEST(SPResourceTest, CBORPartialEncodingPositive)
+{
+    bool propsToTest[SP_PROPERTY_COUNT];
+
+    // supported profiles only
+    TestInit(&s_testSp, propsToTest);
+    propsToTest[SP_SUPPORTED_PROFILES] = true;
+    s_testSp.supportedLen = 1;
+    s_testSp.supportedProfiles[0] = s_spBaselineName;
+    TestEncodeDecode(&s_testSp, propsToTest, false);
+
+    // active profile only
+    TestInit(&s_testSp, propsToTest);
+    propsToTest[SP_ACTIVE_PROFILE] = true;
+    s_testSp.activeProfile = s_spBlueName;
+    TestEncodeDecode(&s_testSp, propsToTest, false);
+
+    // cred profile only
+    TestInit(&s_testSp, propsToTest);
+    propsToTest[SP_CRED_ID] = true;
+    s_testSp.credid = 11;
+    TestEncodeDecode(&s_testSp, propsToTest, false);
+
+    // supported profiles and active profile
+    TestInit(&s_testSp, propsToTest);
+    propsToTest[SP_SUPPORTED_PROFILES] = true;
+    propsToTest[SP_ACTIVE_PROFILE] = true;
+    s_testSp.supportedLen = 2;
+    s_testSp.supportedProfiles[0] = s_spBaselineName;
+    s_testSp.supportedProfiles[1] = s_spBlueName;
+    s_testSp.activeProfile = s_spBlueName;
+    TestEncodeDecode(&s_testSp, propsToTest, false);
+
+    // supported profiles and credid
+    TestInit(&s_testSp, propsToTest);
+    propsToTest[SP_SUPPORTED_PROFILES] = true;
+    propsToTest[SP_CRED_ID] = true;
+    s_testSp.supportedLen = 2;
+    s_testSp.supportedProfiles[0] = s_spBaselineName;
+    s_testSp.supportedProfiles[1] = s_spBlackName;
+    s_testSp.credid = 88;
+    TestEncodeDecode(&s_testSp, propsToTest, false);
+
+    // active profiles and credid
+    TestInit(&s_testSp, propsToTest);
+    propsToTest[SP_ACTIVE_PROFILE] = true;
+    propsToTest[SP_CRED_ID] = true;
+    s_testSp.activeProfile = s_spBaselineName;
+    s_testSp.credid = 22;
+    TestEncodeDecode(&s_testSp, propsToTest, false);
+}
+
+// TODO: in order of priority
+// * GetRequestPositive
+// * PostRequestPositive
+// * GetRequestGetNegative
+// * GetRequestPostNegative
+// * CBORFullEncodingNegative
+// * CBORPartialEncodingNegative
+
+//*****************************************************************************
+// Helper fxns
+//*****************************************************************************
+
+static void TestEncodeDecode(OicSecSp_t* spToTest, bool* propsToTest, bool checkForValidSp)
+{
+    OCStackResult ret = OC_STACK_OK;
+
+    uint8_t *cborPayload = NULL;
+    size_t cborSize = 0;
+    OicSecSp_t *spDecoded = NULL;
+    bool decodedProperties[SP_PROPERTY_COUNT];
+
+    // encode
+    ret = SpToCBORPayloadPartial(spToTest, &cborPayload, &cborSize, propsToTest);
+    EXPECT_TRUE(OC_STACK_OK == ret);
+    VERIFY_OR_LOG_AND_EXIT(TAG, (OC_STACK_OK == ret), "Failed to encode sp", ERROR);
+
+    // decode
+    ret = CBORPayloadToSp(cborPayload, cborSize, &spDecoded, decodedProperties);
+    EXPECT_TRUE(OC_STACK_OK == ret);
+    VERIFY_OR_LOG_AND_EXIT(TAG, (OC_STACK_OK == ret), "Failed to decode sp", ERROR);
+
+    if ( checkForValidSp )
+    {
+        EXPECT_TRUE(true==RequiredSpPropsPresentAndValid(spDecoded, decodedProperties));
+    }
+
+    // compare
+    EXPECT_TRUE(true == IsPropArraySame(propsToTest, decodedProperties));
+    EXPECT_TRUE(true == IsSpSame(&s_testSp, spDecoded, propsToTest));
+
+exit:
+    OICFree(cborPayload);
+    DeleteSpBinData(spDecoded);
+}
+
+// can pass in spProps = NULL;
+static void TestInit(OicSecSp_t* testSp, bool* spProps)
+{
+    testSp->supportedLen = 0;
+    testSp->activeProfile = NULL;
+    testSp->credid = 0;
+
+    for (size_t i = 0; i < sizeof(s_profileArray)/sizeof(s_profileArray[0]); i++)
+    {
+        testSp->supportedProfiles[i] = NULL;
+    }
+    if (spProps != NULL)
+    {
+        SetAllSpProps(spProps, false);
+    }
+}
+
index b78cbec..6e40b39 100644 (file)
@@ -48,7 +48,7 @@ extern "C"
 #endif
 
 /**
- * Macro to verify the validity of cbor operation.
+ * Macro to verify the validity of cbor operation or out of memory condition
  */
 #define VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(log_tag, err, log_message) \
     if ((CborNoError != (err)) && !(CborErrorOutOfMemory & (err))) \
@@ -61,6 +61,20 @@ extern "C"
         goto exit; \
     } \
 
+/**
+ * Macro to verify the validity of cbor operation
+ */
+#define VERIFY_CBOR_SUCCESS(log_tag, err, log_message) \
+    if (CborNoError != (err)) \
+    { \
+        if ((log_tag) && (log_message)) \
+        { \
+            OIC_LOG_V(ERROR, (log_tag), "%s with cbor error: \'%s\'.", \
+                    (log_message), (cbor_error_string(err))); \
+        } \
+        goto exit; \
+    } \
+
 #define VERIFY_PARAM_NON_NULL(log_tag, err, log_message) \
     if (NULL == (err)) \
     { \
index 5914590..2f53282 100644 (file)
@@ -27,6 +27,7 @@ OCGetDevInfoFromNetwork
 OCGetLinkedStatus
 OCGetPublicKeyFromCSR
 OCGetRolesResource
+OCGetSpResource
 OCGetUuidFromCSR
 OCInitPM
 OCClosePM
@@ -36,6 +37,7 @@ OCSaveACL
 OCProvisionCertificate
 OCProvisionCredentials
 OCProvisionPairwiseDevices
+OCProvisionSecurityProfileInfo
 OCProvisionSymmetricRoleCredentials
 OCProvisionTrustCertChain
 OCReadTrustCertChain
@@ -77,3 +79,4 @@ UnsetUserConfirmCB
 SetVerifyOption
 VerifyOwnershipTransfer
 LogCurrrentCredResource
+LogSp