[IOT-1785] Implement roles from symmetric pair-wise keys 63/18463/7
authorKevin Kane <kkane@microsoft.com>
Wed, 29 Mar 2017 20:26:01 +0000 (13:26 -0700)
committerGreg Zaverucha <gregz@microsoft.com>
Fri, 7 Apr 2017 17:44:37 +0000 (17:44 +0000)
Implement roleId property of an oic.sec.cred object.

Fix error path bugs in CRED<->CBOR code to fail properly if
certain serialization subroutines fail; error codes were
being ignored. Fix error path memory leaks.

Also fix the ACL/ACL2<->CBOR code to use the correct JSON
field names per the schema. Fix error path memory leaks.

Change-Id: Ie9aa8baba5903c482acb3adc6ef617a1ced7db31
Signed-off-by: Kevin Kane <kkane@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/18463
Reviewed-by: Alex Kelley <alexke@microsoft.com>
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Dave Thaler <dthaler@microsoft.com>
Reviewed-by: Greg Zaverucha <gregz@microsoft.com>
20 files changed:
resource/csdk/security/include/internal/rolesresource.h
resource/csdk/security/include/internal/secureresourcemanager.h
resource/csdk/security/include/internal/srmresourcestrings.h
resource/csdk/security/include/securevirtualresourcetypes.h
resource/csdk/security/provisioning/include/internal/credentialgenerator.h
resource/csdk/security/provisioning/include/internal/secureresourceprovider.h
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/sample/autoprovisioningclient.c
resource/csdk/security/provisioning/sample/provisioningTest.py
resource/csdk/security/provisioning/src/credentialgenerator.c
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c
resource/csdk/security/provisioning/unittest/credentialgeneratortest.cpp
resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/credresource.c
resource/csdk/security/src/rolesresource.c
resource/csdk/security/src/secureresourcemanager.c
resource/csdk/security/src/srmresourcestrings.c
resource/csdk/stack/octbstack_product_secured.def

index 252bd2c..40c75cd 100644 (file)
@@ -53,6 +53,16 @@ OCStackResult InitRolesResource();
  */
 OCStackResult DeInitRolesResource();
 
+/**
+ * Register the PSK credential being used for authentication. This is used by the cred resource
+ * to inform the roles resource a symmetric PSK has a particular role associated with it.
+ *
+ * @param[in]  cred         PSK credential to register
+ *
+ * @return OC_STACK_OK if role credential is successfully registered; error otherwise.
+ */
+OCStackResult RegisterSymmetricCredentialRole(const OicSecCred_t *cred);
+
 /**
  * Retrieve the roles asserted by a given endpoint with certificates.
  *
index b6d74e2..baaff54 100644 (file)
@@ -135,6 +135,17 @@ bool SRMIsSecurityResourceURI(const char* uri);
  */
 OicSecSvrType_t GetSvrTypeFromUri(const char* uri);
 
+extern const OicSecRole_t EMPTY_ROLE;
+
+/**
+ * Determine if a role is non-empty.
+ *
+ * @param[in]  role     Role to check
+ *
+ * @return true if role is non-empty, false if role is empty
+ */
+bool IsNonEmptyRole(const OicSecRole_t *role);
+
 #ifdef __cplusplus
 }
 #endif
index b1b59b2..2e25f47 100644 (file)
@@ -126,7 +126,8 @@ extern const char * OIC_JSON_OXM_TYPE_NAME;
 extern const char * OIC_JSON_OXM_SEL_NAME;
 extern const char * OIC_JSON_DEVICE_ID_FORMAT_NAME;
 extern const char * OIC_JSON_CREDID_NAME;
-extern const char * OIC_JSON_ROLEIDS_NAME;
+extern const char * OIC_JSON_ROLEID_NAME;
+extern const char * OIC_JSON_ROLE_NAME;
 extern const char * OIC_JSON_AUTHORITY_NAME;
 extern const char * OIC_JSON_CREDTYPE_NAME;
 extern const char * OIC_JSON_PUBLICDATA_NAME;
index 55a02f1..472c741 100644 (file)
@@ -528,10 +528,8 @@ struct OicSecCred
     // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
     uint16_t            credId;         // 0:R:S:Y:UINT16
     OicUuid_t           subject;        // 1:R:S:Y:oic.uuid
-    //Note: Need further clarification on roleID data type
-    //NOTE: Need further clarification on roleId datatype.
-    //size_t              roleIdsLen;     // the number of elts in RoleIds
-    //OicSecRole_t        *roleIds;       // 2:R:M:N:oic.sec.role
+    // If roleId.id is all zeroes, this property is not set.
+    OicSecRole_t        roleId;         // 2:R:M:N:oic.sec.roletype
     OicSecCredType_t    credType;       // 3:R:S:Y:oic.sec.credtype
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
     OicSecKey_t         publicData;     // own cerificate chain
index 4e69acb..c8a6bf9 100644 (file)
@@ -36,6 +36,8 @@ extern "C" {
  * @param[in]  ptDeviceId     Device ID of provisioning tool.
  * @param[in]  firstDeviceId  DeviceID of the first device.
  * @param[in]  secondDeviceId DeviceID of the second device.
+ * @param[in]  firstRole      Role to grant firstDeviceId when communicating with secondDeviceId; NULL for none
+ * @param[in]  secondRole     Role to grant secondDeviceId when communicating with firstDeviceId; NULL for none
  * @param[out] firstCred      Generated credential for first device.
  * @param[out] secondCred     Generated credential for second device.
  * @return  OC_STACK_OK on success
@@ -44,6 +46,8 @@ OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySiz
                                        const OicUuid_t *ptDeviceId,
                                        const OicUuid_t *firstDeviceId,
                                        const OicUuid_t *secondDeviceId,
+                                       const OicSecRole_t *firstRole,
+                                       const OicSecRole_t *secondRole,
                                        OicSecCred_t **firstCred,
                                        OicSecCred_t **secondCred);
 
index 9e7c011..2fd0f0b 100644 (file)
@@ -227,10 +227,17 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
  * @param[in] ctx Application context to be returned in result callback.
  * @param[in] type Type of credentials to be provisioned to the device.
  * @param[in] keySize size of key
- * @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance, respresenting resource to be provsioned.
- * @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance, respresenting resource to be provsioned.
+ * @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance, representing the resource to be provisioned.
+ * @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance, representing the resource to be provisioned.
+ *                  Use NULL to indicate the local device.
  * @param[in] pemCert When provisioning a certificate (type is SIGNED_ASYMMETRIC_KEY), this is the
  *                    certificate, encoded as PEM.
+ * @param[in] role1 When provisioning a PSK (type is SYMMETRIC_PAIR_WISE_KEY), this is the role which
+ *                  the device indicated by pDev1 will also have when communicating with pDev2. Use NULL
+ *                  to associate no role with this credential.
+ * @param[in] role2 When provisioning a PSK (type is SYMMETRIC_PAIR_WISE_KEY), this is the role which
+ *                  the device indicated by pDev1 will also have when communicating with pDev2. Use NULL
+ *                  to associate no role with this credential.
  * @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.
@@ -239,6 +246,8 @@ OCStackResult SRPProvisionCredentials(void *ctx,OicSecCredType_t type, size_t ke
                                       const OCProvisionDev_t *pDev1,
                                       const OCProvisionDev_t *pDev2,
                                       const char* pemCert,
+                                      const OicSecRole_t *role1,
+                                      const OicSecRole_t *role2,
                                       OCProvisionResultCB resultCallback);
 
 /**
index 1441bb6..e1f8c3a 100644 (file)
@@ -344,8 +344,8 @@ OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *select
  * @param[in] ctx Application context returned in the result callback.
  * @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,respresenting resource to be provsioned.
  @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
+ * @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] 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.
@@ -355,6 +355,30 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
                                       const OCProvisionDev_t *pDev2,
                                       OCProvisionResultCB resultCallback);
 
+/**
+ * API to provision symmetric pair-wise key credentials to devices that grant a role.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @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. 
+ *                  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.
+ * @param[in] role2 The role which the device indicated by pDev2 will have when communicating with pDev1.
+ *                  Use NULL to associate no role with this credential.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request receives a response from first resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCProvisionSymmetricRoleCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
+                                                  const OCProvisionDev_t *pDev1,
+                                                  const OCProvisionDev_t *pDev2,
+                                                  const OicSecRole_t *role1,
+                                                  const OicSecRole_t *role2,
+                                                  OCProvisionResultCB resultCallback);
+
 /**
  * API to provision a certificate to a device.
  *
index c05411e..0c46821 100644 (file)
@@ -1571,6 +1571,136 @@ exit:
     return ret;
 }
 
+static int provisionSymmetricRoleCred(int dev_num)
+{
+    OicSecRole_t role;
+    memset(&role, 0, sizeof(role));
+    OICStrcpy(role.id, sizeof(role.id), TEST_CERT_ROLE1);
+
+    // call |OCProvisionCredentials| API
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    OCStackResult rst =
+        OCProvisionSymmetricRoleCredentials((void*) g_ctx,
+                    SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
+                    getDevInst((const OCProvisionDev_t*) g_own_list, dev_num),
+                    NULL, NULL, &role,
+                    provisionCredCB);
+    if (OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionCredentials API error: %d", rst);
+        return -1;
+    }
+    if (waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int testSymmetricRoleUse(int dev_num)
+{
+    const char* uri = "/a/led";
+    OicSecAcl_t* acl = NULL;
+
+    // Make sure we own at least one device to provision
+    if (!g_own_list || (g_own_cnt == 0))
+    {
+        OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
+        return -1;  // Error, we should have registered unowned devices already
+    }
+
+    /* Create and provision a role-based ACL allowing ROLE1 to access '/a/led'. */
+    int ret = createLedAcl(&acl, TEST_CERT_ROLE1, NULL);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to create led ACL", __func__);
+        return ret;
+    }
+
+    ret = provisionAcl(dev_num, acl);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to provision led ACL", __func__);
+        goto exit;
+    }
+
+    /* Create and provision an ACL to allow anyone access to the roles resource. Since all actions
+     * on the roles resource first requires authentication by public key, this is effectively "any
+     * authenticated" access.
+     * @todo: This should be done by default and not be necessary here (IOT-1950).
+     */
+    OCDeleteACLList(acl);
+    acl = NULL;
+    ret = createRolesAcl(&acl);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to create roles ACL", __func__);
+        goto exit;
+    }
+
+    ret = provisionAcl(dev_num, acl);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to provision roles ACL", __func__);
+        goto exit;
+    }
+
+    /* Remove the owner credential so that we don't use it when asserting role certs. */
+    OCStackResult res = OCRemoveCredential(&g_uuidDev1);
+    if (res != OC_STACK_RESOURCE_DELETED)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to remove owner credential for subject UUID: ", __func__);
+        OIC_LOG_BUFFER(DEBUG, TAG, g_uuidDev1.id, UUID_LENGTH);
+        ret = -1;
+        goto exit;
+    }
+
+    /* The server has an owner PSK associated with our GUID. Change our GUID to something else,
+     * which will both be used to generate the role credential and for the later connection.
+     */
+    const OCUUIdentity newIdentity = { .id = { 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 } };
+    if (OC_STACK_OK != OCSetDeviceId(&newIdentity))
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to set device ID", __func__);
+        ret = -1;
+        goto exit;
+    }
+
+    /* Create a new symmetric credential with the role. */
+    ret = provisionSymmetricRoleCred(dev_num);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to provision symmetric role pair-wise keys", __func__);
+        goto exit;
+    }
+
+    /* Close all secure sessions */
+    if (closeAllSessions() != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
+        ret = -1;
+        goto exit;
+    }
+
+    /* Try a get request, expect success */
+    ret = doGetRequest(uri, dev_num);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Get request to %s failed, but should have succeeded", __func__, uri);
+        goto exit;
+    }
+
+exit:
+
+    OCDeleteACLList(acl);
+
+    return ret;
+}
+
 /* Get a specific device from the provided device list. The devices in the list
  * are numbered starting from 1.
  */
@@ -1905,6 +2035,32 @@ exit:
     return ret;
 }
 
+int TestSymmetricRoleUse()
+{
+    int ret = -1;
+
+    OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
+
+    if (initDiscoverRegisterAllDevices())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
+        goto exit;
+    }
+
+    /* There should be one owned device with number 1. */
+    if (testSymmetricRoleUse(1))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to use symmetric key role");
+        goto exit;
+    }
+
+exit:
+
+    shutdownProvisionClient();
+
+    return ret;
+}
+
 // main function for provisioning client using C-level provisioning API
 int main(int argc, char** argv)
 {
@@ -1927,6 +2083,8 @@ int main(int argc, char** argv)
             return TestRoleProvisioning();
         case 5:
             return TestRoleAssertionAndUse();
+        case 6:
+            return TestSymmetricRoleUse();
         default:
             printf("%s: Invalid test number\n", argv[0]);
             return 1;
index 93d4282..53514be 100644 (file)
@@ -42,7 +42,7 @@ def print_environment():
 ### main ###
 
 # Number of unit tests in autoprovisioningclient
-NUM_TESTS = 5
+NUM_TESTS = 6
 
 usage = '''
  Run end-to-end certificate tests between autoprovisioningclient and sampleserver_justworks
index 8442ec4..2e375d0 100644 (file)
@@ -34,7 +34,9 @@
 
 OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySize,
         const OicUuid_t *ptDeviceId, const OicUuid_t *firstDeviceId,
-        const OicUuid_t *secondDeviceId, OicSecCred_t **firstCred, OicSecCred_t **secondCred)
+        const OicUuid_t *secondDeviceId, 
+        const OicSecRole_t *firstRole, const OicSecRole_t *secondRole,
+        OicSecCred_t **firstCred, OicSecCred_t **secondCred)
 {
     if (NULL == ptDeviceId || NULL == firstDeviceId || NULL == firstCred || NULL != *firstCred || \
         NULL == secondDeviceId || NULL == secondCred || NULL != *secondCred)
@@ -77,6 +79,18 @@ OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySiz
     tempSecondCred =  GenerateCredential(firstDeviceId, type, NULL, &privKey, ptDeviceId, NULL);
     VERIFY_NOT_NULL(TAG, tempSecondCred, ERROR);
 
+    // firstRole and secondRole are the roles granted to the client when authenticating with this credential;
+    // therefore, the role to be granted has to be stored on the corresponding server. This is why secondRole
+    // is assigned to tempFirstCred and vice versa.
+    if (NULL != secondRole)
+    {
+        tempFirstCred->roleId = *secondRole;
+    }
+    if (NULL != firstRole)
+    {
+        tempSecondCred->roleId = *firstRole;
+    }
+
     *firstCred = tempFirstCred;
     *secondCred = tempSecondCred;
     res = OC_STACK_OK;
index 3269355..83f6da3 100644 (file)
@@ -478,8 +478,34 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
                                       OCProvisionResultCB resultCallback)
 {
     return SRPProvisionCredentials(ctx, type, keySize,
-                                      pDev1, pDev2, NULL, resultCallback);
+                                      pDev1, pDev2, NULL, NULL, NULL, resultCallback);
+}
 
+/**
+ * API to provision symmetric pair-wise key credentials to devices that grant a role.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @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. 
+ *                  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.
+ * @param[in] role2 The role which the device indicated by pDev2 will have when communicating with pDev1.
+ *                  Use NULL to associate no role with this credential.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            provisioning request receives a response from first resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCProvisionSymmetricRoleCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
+                                                  const OCProvisionDev_t *pDev1,
+                                                  const OCProvisionDev_t *pDev2,
+                                                  const OicSecRole_t *role1,
+                                                  const OicSecRole_t *role2,
+                                                  OCProvisionResultCB resultCallback)
+{
+    return SRPProvisionCredentials(ctx, type, keySize, pDev1, pDev2, NULL, role1, role2, resultCallback);
 }
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
@@ -499,7 +525,7 @@ OCStackResult OCProvisionCertificate(void *ctx,
     OCProvisionResultCB resultCallback)
 {
     return SRPProvisionCredentials(ctx, SIGNED_ASYMMETRIC_KEY, 0,
-        pDev, NULL, pemCert, resultCallback);
+        pDev, NULL, pemCert, NULL, NULL, resultCallback);
 }
 #endif
 
@@ -1245,7 +1271,7 @@ OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_
     link->currentCountResults = 0;
     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
     res = SRPProvisionCredentials(link, type, keySize,
-                                     pDev1, pDev2, NULL, &ProvisionCredsCB);
+                                     pDev1, pDev2, NULL, NULL, NULL, &ProvisionCredsCB);
     if (res != OC_STACK_OK)
     {
         OICFree(link->resArr);
index 8df1668..d2db735 100644 (file)
@@ -175,27 +175,47 @@ struct RemoveData {
 /**
  * Function prototype
  */
-static OCStackResult provisionCredentials(const OicSecCred_t *cred,
+static OCStackResult provisionCredentials(OicSecCred_t *cred,
         const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
         OCClientResponseHandler responseHandler);
 
+typedef enum {
+    DEVICE_1_FINISHED,
+    DEVICE_2_FINISHED,
+    DEVICE_LOCAL_FINISHED
+} CredProvisioningResultCause_t;
+
 /**
  * Internal function to update result in result array.
  */
 static void registerResultForCredProvisioning(CredentialData_t *credData,
-                                              OCStackResult stackresult, int cause)
+                                              OCStackResult stackresult, CredProvisioningResultCause_t cause)
 {
-
+   OCStackResult res = OC_STACK_ERROR;
    OIC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
-   if(1 == cause)
+   switch (cause)
    {
+   case DEVICE_1_FINISHED:
        memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
               credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
-   }
-   else
-   {
+       break;
+   case DEVICE_2_FINISHED:
        memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
               credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
+       break;
+   case DEVICE_LOCAL_FINISHED:
+       res = GetDoxmDeviceID(&credData->resArr[(credData->numOfResults)].deviceId);
+       if (OC_STACK_OK != res)
+       {
+           OIC_LOG_V(WARNING, TAG, "%s: Could not retrieve own device ID to populate result for cred provisioning: %d", __func__, res);
+           memset(credData->resArr[(credData->numOfResults)].deviceId.id, 0, UUID_LENGTH);
+       }
+       break;
+   default:
+       assert(!"Unknown value for cause");
+       OIC_LOG_V(ERROR, TAG, "%s: unknown value of cause: %d", __func__, cause);
+       memset(credData->resArr[(credData->numOfResults)].deviceId.id, 0, UUID_LENGTH);
+       break;
    }
    credData->resArr[(credData->numOfResults)].res = stackresult;
    ++(credData->numOfResults);
@@ -223,7 +243,7 @@ static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNU
     {
         if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
         {
-            registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, 2);
+            registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, DEVICE_2_FINISHED);
             OCStackResult res =  PDMLinkDevices(&credData->deviceInfo1->doxm->deviceID,
                     &credData->deviceInfo2->doxm->deviceID);
             if (OC_STACK_OK != res)
@@ -243,7 +263,7 @@ static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNU
 
     }
     OIC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
-    registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
+    registerResultForCredProvisioning(credData, OC_STACK_ERROR, DEVICE_2_FINISHED);
     ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                             credData->resArr,
                                             true);
@@ -276,10 +296,16 @@ static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNU
         if (OC_STACK_RESOURCE_CHANGED == clientResponse->result)
         {
             // send credentials to second device
-            registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED,1);
+            registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, DEVICE_1_FINISHED);
             OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
                     provisionCredentialCB2);
-            DeleteCredList(credInfo);
+            // If deviceInfo is NULL, this device is the second device. Don't delete the cred
+            // because provisionCredentials added it to the local cred store and it now owns
+            // the memory.
+            if ((NULL != deviceInfo) || (OC_STACK_OK != res))
+            {
+                DeleteCredList(credInfo);
+            }
             if (OC_STACK_OK != res)
             {
                 registerResultForCredProvisioning(credData, res,2);
@@ -293,7 +319,7 @@ static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNU
         }
         else
         {
-            registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
+            registerResultForCredProvisioning(credData, OC_STACK_ERROR, DEVICE_1_FINISHED);
             ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                     credData->resArr,
                                                     true);
@@ -305,7 +331,7 @@ static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNU
     else
     {
         OIC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
-        registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
+        registerResultForCredProvisioning(credData, OC_STACK_ERROR, DEVICE_1_FINISHED);
        ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
                                                      credData->resArr,
                                                      true);
@@ -325,58 +351,73 @@ static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNU
  * @param[in] responseHandler callbak called by OC stack when request API receives response.
  * @return  OC_STACK_OK in case of success and other value otherwise.
  */
-static OCStackResult provisionCredentials(const OicSecCred_t *cred,
+static OCStackResult provisionCredentials(OicSecCred_t *cred,
         const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
         OCClientResponseHandler responseHandler)
 {
-    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;
-    int secureFlag = 0;
-    OCStackResult res = CredToCBORPayload(cred, &secPayload->securityData,
-                                          &secPayload->payloadSize, secureFlag);
-    if((OC_STACK_OK != res) && (NULL == secPayload->securityData))
-    {
-        OCPayloadDestroy((OCPayload *)secPayload);
-        OIC_LOG(ERROR, TAG, "Failed to CredToCBORPayload");
-        return OC_STACK_NO_MEMORY;
-    }
+    OCStackResult res = OC_STACK_OK;
 
-    OIC_LOG(DEBUG, TAG, "Created payload for Cred:");
-    OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
-    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
-    if(!PMGenerateQuery(true,
-                        deviceInfo->endpoint.addr,
-                        deviceInfo->securePort,
-                        deviceInfo->connType,
-                        query, sizeof(query), OIC_RSRC_CRED_URI))
+    if (NULL != deviceInfo)
     {
-        OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
-        OCPayloadDestroy((OCPayload *)secPayload);
-        return OC_STACK_ERROR;
-    }
-    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+        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;
+        int secureFlag = 0;
+        res = CredToCBORPayload(cred, &secPayload->securityData, &secPayload->payloadSize, secureFlag);
+        if ((OC_STACK_OK != res) && (NULL == secPayload->securityData))
+        {
+            OCPayloadDestroy((OCPayload *)secPayload);
+            OIC_LOG(ERROR, TAG, "Failed to CredToCBORPayload");
+            return OC_STACK_NO_MEMORY;
+        }
 
-    OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
-    cbData.cb = responseHandler;
-    cbData.context = (void *) credData;
-    cbData.cd = NULL;
+        OIC_LOG(DEBUG, TAG, "Created payload for Cred:");
+        OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+        char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = { 0 };
+        if (!PMGenerateQuery(true,
+            deviceInfo->endpoint.addr,
+            deviceInfo->securePort,
+            deviceInfo->connType,
+            query, sizeof(query), OIC_RSRC_CRED_URI))
+        {
+            OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
+            OCPayloadDestroy((OCPayload *)secPayload);
+            return OC_STACK_ERROR;
+        }
+        OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
 
-    OCDoHandle handle = NULL;
-    OCMethod method = OC_REST_POST;
-    OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
+        OCCallbackData cbData = { .context = NULL, .cb = NULL, .cd = NULL };
+        cbData.cb = responseHandler;
+        cbData.context = (void *)credData;
+        cbData.cd = NULL;
+
+        OCDoHandle handle = NULL;
+        OCMethod method = OC_REST_POST;
+        res = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
             deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
-    OIC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
-    if (ret != OC_STACK_OK)
+        OIC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d", res);
+        if (res != OC_STACK_OK)
+        {
+            OIC_LOG(ERROR, TAG, "OCStack resource error");
+            return res;
+        }
+        return OC_STACK_OK;
+    }
+    else
     {
-        OIC_LOG(ERROR, TAG, "OCStack resource error");
-        return ret;
+        /* Provision this credential to the local cred store. On success, the cred resource takes
+         * ownership of the memory. On failure, provisionCredentialCB1 will delete the cred object.
+         */
+        res = AddCredential(cred);
+        /* Call the result callback directly. */
+        registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CHANGED, DEVICE_LOCAL_FINISHED);
+        (credData->resultCallback)(credData->ctx, credData->numOfResults, credData->resArr, false);
+        return res;
     }
-    return OC_STACK_OK;
 }
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
@@ -893,20 +934,19 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
                                       const OCProvisionDev_t *pDev1,
                                       const OCProvisionDev_t *pDev2,
                                       const char* pemCert,
+                                      const OicSecRole_t *role1,
+                                      const OicSecRole_t *role2,
                                       OCProvisionResultCB resultCallback)
 {
     VERIFY_NOT_NULL_RETURN(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
-    if (SYMMETRIC_PAIR_WISE_KEY == type)
-    {
-        VERIFY_NOT_NULL_RETURN(TAG, pDev2, ERROR,  OC_STACK_INVALID_PARAM);
-    }
     if (!resultCallback)
     {
         OIC_LOG(INFO, TAG, "SRPProvisionCredentials: NULL Callback");
         return OC_STACK_INVALID_CALLBACK;
     }
-    if (SYMMETRIC_PAIR_WISE_KEY == type &&
-        0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t)))
+    if ((SYMMETRIC_PAIR_WISE_KEY == type) && 
+        (NULL != pDev2) &&
+        (0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t))))
     {
         OIC_LOG(INFO, TAG, "SRPProvisionCredentials : Same device ID");
         return OC_STACK_INVALID_PARAM;
@@ -921,7 +961,7 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
 
     OIC_LOG(INFO, TAG, "In SRPProvisionCredentials");
 
-    if (SYMMETRIC_PAIR_WISE_KEY == type)
+    if ((SYMMETRIC_PAIR_WISE_KEY == type) && (NULL != pDev2))
     {
         bool linkExisits = true;
         OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExisits);
@@ -955,7 +995,8 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
             OicSecCred_t *firstCred = NULL;
             OicSecCred_t *secondCred = NULL;
             OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
-                    &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
+                    &firstDevice->doxm->deviceID, (NULL != secondDevice) ? &secondDevice->doxm->deviceID : &provTooldeviceID,
+                    role1, role2,
                     &firstCred, &secondCred);
             VERIFY_SUCCESS_RETURN(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
             OIC_LOG(INFO, TAG, "Credentials generated successfully");
index 4f3f086..f948ddf 100644 (file)
@@ -38,7 +38,7 @@ TEST(PMGeneratePairWiseCredentialsTest, InvalidProvisioningtoolDevID)
     OicSecCred_t *cred2 = NULL;
     size_t keySize = OWNER_PSK_LENGTH_128;
     EXPECT_EQ(OC_STACK_INVALID_PARAM, PMGeneratePairWiseCredentials(NO_SECURITY_MODE,
-             keySize, NULL, firstDevID, SecondDevID, &cred1, &cred2));
+             keySize, NULL, firstDevID, SecondDevID, NULL, NULL, &cred1, &cred2));
     OICFree(firstDevID);
     OICFree(SecondDevID);
 }
@@ -59,7 +59,7 @@ TEST(PMGeneratePairWiseCredentialsTest, InvalidFirstDevID)
     OicSecCred_t *cred2 = NULL;
     size_t keySize = OWNER_PSK_LENGTH_128;
     EXPECT_EQ(OC_STACK_INVALID_PARAM, PMGeneratePairWiseCredentials(NO_SECURITY_MODE,
-              keySize, provisioningDevID, NULL, SecondDevID, &cred1, &cred2));
+              keySize, provisioningDevID, NULL, SecondDevID, NULL, NULL, &cred1, &cred2));
     OICFree(SecondDevID);
     OICFree(provisioningDevID);
 }
@@ -80,7 +80,7 @@ TEST(PMGeneratePairWiseCredentialsTest, InvalidSecondDevID)
     OicSecCred_t *cred2 = NULL;
     size_t keySize = OWNER_PSK_LENGTH_128;
     EXPECT_EQ(OC_STACK_INVALID_PARAM, PMGeneratePairWiseCredentials(NO_SECURITY_MODE, keySize,
-              provisioningDevID, firstDevID, NULL, &cred1, &cred2));
+              provisioningDevID, firstDevID, NULL, NULL, NULL, &cred1, &cred2));
     OICFree(firstDevID);
     OICFree(provisioningDevID);
 }
@@ -104,9 +104,8 @@ TEST(PMGeneratePairWiseCredentialsTest, InvalidCred)
     }
     size_t keySize = OWNER_PSK_LENGTH_128;
     EXPECT_EQ(OC_STACK_INVALID_PARAM, PMGeneratePairWiseCredentials(NO_SECURITY_MODE, keySize,
-              provisioningDevID, firstDevID, SecondDevID, NULL, NULL));
+              provisioningDevID, firstDevID, SecondDevID, NULL, NULL, NULL, NULL));
     OICFree(firstDevID);
     OICFree(SecondDevID);
     OICFree(provisioningDevID);
 }
-
index 26ca0e8..8dd6b27 100644 (file)
@@ -98,27 +98,27 @@ TEST(SRPProvisionCredentialsTest, NullDevice1)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
                                                               OWNER_PSK_LENGTH_128, NULL,
-                                                              &pDev2, NULL, &provisioningCB));
+                                                              &pDev2, NULL, NULL, NULL, &provisioningCB));
 }
 
 TEST(SRPProvisionCredentialsTest, SamelDeviceId)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
                                                               OWNER_PSK_LENGTH_128, &pDev1,
-                                                              &pDev1, NULL, &provisioningCB));
+                                                              &pDev1, NULL, NULL, NULL, &provisioningCB));
 }
 
 TEST(SRPProvisionCredentialsTest, NullCallback)
 {
     EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionCredentials(NULL, credType,
                                                                  OWNER_PSK_LENGTH_128,
-                                                                 &pDev1, &pDev2, NULL, NULL));
+                                                                 &pDev1, &pDev2, NULL, NULL, NULL, NULL));
 }
 
 TEST(SRPProvisionCredentialsTest, InvalidKeySize)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
-                                                                0, &pDev1, &pDev2, NULL,
+                                                                0, &pDev1, &pDev2, NULL, NULL, NULL, 
                                                                 &provisioningCB));
 }
 
@@ -127,11 +127,6 @@ TEST(SRPUnlinkDevicesTest, NullDevice1)
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPUnlinkDevices(NULL, NULL, &pDev2, provisioningCB));
 }
 
-TEST(SRPUnlinkDevicesTest, NullDevice2)
-{
-    EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPUnlinkDevices(NULL, &pDev1, NULL, provisioningCB));
-}
-
 TEST(SRPUnlinkDevicesTest, SamelDeviceId)
 {
     EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPUnlinkDevices(NULL, &pDev1, &pDev1, provisioningCB));
index 1dc4197..225586d 100644 (file)
 #include "srmresourcestrings.h"
 #include "aclresource.h"
 #include "doxmresource.h"
+#include "rolesresource.h"
 #include "resourcemanager.h"
 #include "srmutility.h"
 #include "psinterface.h"
 #include "ocpayloadcbor.h"
+#include "secureresourcemanager.h"
 
 #include "security_internals.h"
 
@@ -56,7 +58,7 @@ static const uint8_t ACL_MAP_SIZE = 4;
 static const uint8_t ACL_ACLIST_MAP_SIZE = 1;
 static const uint8_t ACL_ACES_MAP_SIZE = 3;
 static const uint8_t ACL_RESOURCE_MAP_SIZE = 3;
-static const uint8_t ACE_ROLE_MAP_SIZE = 2;
+static const uint8_t ACE_ROLE_MAP_SIZE = 1;
 
 
 // CborSize is the default cbor payload size being used.
@@ -428,20 +430,26 @@ OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, OicSecAclVersion_t acl
         {
             assert(OIC_SEC_ACL_V2 <= aclVersion);
             CborEncoder roleMap;
-            cborEncoderResult = cbor_encoder_create_map(&oicSecAclMap, &roleMap, ACE_ROLE_MAP_SIZE);
+
+            bool includeAuthority = (0 != memcmp(&ace->subjectRole.authority, &EMPTY_ROLE.authority, sizeof(EMPTY_ROLE.authority)));
+
+            cborEncoderResult = cbor_encoder_create_map(&oicSecAclMap, &roleMap, ACE_ROLE_MAP_SIZE + includeAuthority?1:0);
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed creating role map");
 
-            cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_ROLEIDS_NAME, strlen(OIC_JSON_ROLEIDS_NAME));
+            cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_ROLE_NAME, strlen(OIC_JSON_ROLE_NAME));
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roleid tag");
 
             cborEncoderResult = cbor_encode_text_string(&roleMap, ace->subjectRole.id, strlen(ace->subjectRole.id));
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roleid value");
 
-            cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_AUTHORITY_NAME, strlen(OIC_JSON_AUTHORITY_NAME));
-            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority tag");
+            if (includeAuthority)
+            {
+                cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_AUTHORITY_NAME, strlen(OIC_JSON_AUTHORITY_NAME));
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority tag");
 
-            cborEncoderResult = cbor_encode_text_string(&roleMap, ace->subjectRole.authority, strlen(ace->subjectRole.authority));
-            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority value");
+                cborEncoderResult = cbor_encode_text_string(&roleMap, ace->subjectRole.authority, strlen(ace->subjectRole.authority));
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority value");
+            }
 
             cborEncoderResult = cbor_encoder_close_container(&oicSecAclMap, &roleMap);
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing role map");
@@ -1178,7 +1186,7 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
 
                                                     if (NULL != roleTagName)
                                                     {
-                                                        if (strcmp(roleTagName, OIC_JSON_ROLEIDS_NAME) == 0)
+                                                        if (strcmp(roleTagName, OIC_JSON_ROLE_NAME) == 0)
                                                         {
                                                             char *roleId = NULL;
                                                             cborFindResult = cbor_value_dup_text_string(&roleMap, &roleId, &unusedLen, NULL);
@@ -1186,6 +1194,7 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                                                             if (strlen(roleId) >= sizeof(ace->subjectRole.id))
                                                             {
                                                                 cborFindResult = CborUnknownError;
+                                                                free(roleId);
                                                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Role ID is too long");
                                                             }
                                                             OICStrcpy(ace->subjectRole.id, sizeof(ace->subjectRole.id), roleId);
@@ -1199,6 +1208,7 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                                                             if (strlen(authorityName) >= sizeof(ace->subjectRole.authority))
                                                             {
                                                                 cborFindResult = CborUnknownError;
+                                                                free(authorityName);
                                                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Authority name is too long");
                                                             }
                                                             OICStrcpy(ace->subjectRole.authority, sizeof(ace->subjectRole.authority), authorityName);
index 854a9e2..8022140 100644 (file)
@@ -55,6 +55,7 @@
 #include "pinoxmcommon.h"
 #include "certhelpers.h"
 #include "cacommon.h"
+#include "secureresourcemanager.h"
 
 #ifdef __unix__
 #include <sys/types.h>
@@ -86,6 +87,7 @@ static const uint16_t CBOR_SIZE = 2048;
 /** CRED size - Number of mandatory items. */
 static const uint8_t CRED_ROOT_MAP_SIZE = 4;
 static const uint8_t CRED_MAP_SIZE = 3;
+static const uint8_t ROLEID_MAP_SIZE = 1;
 
 
 static OicSecCred_t        *gCred = NULL;
@@ -233,6 +235,7 @@ static bool IsEmptyCred(const OicSecCred_t* cred)
     OicUuid_t emptyUuid = {.id={0}};
 
     VERIFY_SUCCESS(TAG, (0 == memcmp(cred->subject.id, emptyUuid.id, sizeof(emptyUuid))), ERROR);
+    VERIFY_SUCCESS(TAG, !IsNonEmptyRole(&cred->roleId), ERROR);
     VERIFY_SUCCESS(TAG, (0 == cred->credId), ERROR);
     VERIFY_SUCCESS(TAG, (0 == cred->credType), ERROR);
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
@@ -400,8 +403,8 @@ CborError SerializeEncodingToCbor(CborEncoder *rootMap, const char* tag, const O
     cborEncoderResult = cbor_encoder_create_map(rootMap, &map, mapSize);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Map");
 
-    VERIFY_CBOR_SUCCESS(TAG, SerializeEncodingToCborInternal(&map, value),
-                        "Failed adding OicSecKey_t structure");
+    cborEncoderResult = SerializeEncodingToCborInternal(&map, value);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding OicSecKey_t structure");
 
     cborEncoderResult = cbor_encoder_close_container(rootMap, &map);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Map.");
@@ -427,8 +430,8 @@ CborError SerializeSecOptToCbor(CborEncoder *rootMap, const char* tag, const Oic
     in.encoding = value->encoding;
     in.len = value->len;
 
-    VERIFY_CBOR_SUCCESS(TAG, SerializeEncodingToCborInternal(&map, &in),
-                        "Failed adding OicSecKey_t structure");
+    cborEncoderResult = SerializeEncodingToCborInternal(&map, &in);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding OicSecKey_t structure");
 
     cborEncoderResult = cbor_encode_text_string(&map, OIC_JSON_REVOCATION_STATUS_NAME,
         strlen(OIC_JSON_REVOCATION_STATUS_NAME));
@@ -524,8 +527,8 @@ CborError DeserializeEncodingFromCbor(CborValue *rootMap, OicSecKey_t *value)
         }
         if (name)
         {
-            VERIFY_CBOR_SUCCESS(TAG, DeserializeEncodingFromCborInternal(&map, name, value),
-                                "Failed to read OicSecKey_t value");
+            cborFindResult = DeserializeEncodingFromCborInternal(&map, name, value);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read OicSecKey_t value");
         }
         if (cbor_value_is_valid(&map))
         {
@@ -566,8 +569,8 @@ CborError DeserializeSecOptFromCbor(CborValue *rootMap, OicSecOpt_t *value)
                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding revstat Value.")
             }
             OicSecKey_t out;
-            VERIFY_CBOR_SUCCESS(TAG, DeserializeEncodingFromCborInternal(&map, name, &out),
-                                "Failed to read OicSecKey_t value");
+            cborFindResult = DeserializeEncodingFromCborInternal(&map, name, &out);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read OicSecKey_t value");
 
             value->data = out.data;
             value->encoding = out.encoding;
@@ -610,6 +613,11 @@ static void logCredMetadata()
         {
             OIC_LOG_V(DEBUG, TAG, "Subject UUID: %s", uuidString);
         }
+        if (IsNonEmptyRole(&temp->roleId))
+        {
+            OIC_LOG_V(DEBUG, TAG, "Role ID: %s", temp->roleId.id);
+            OIC_LOG_V(DEBUG, TAG, "Role authority: %s", temp->roleId.authority);
+        }
         OIC_LOG_V(DEBUG, TAG, "Cred Type: %d", temp->credType);
         OIC_LOG_V(DEBUG, TAG, "privateData length: %d, encoding: %d", temp->privateData.len, temp->privateData.encoding);
 
@@ -631,7 +639,6 @@ static void logCredMetadata()
 #endif
 }
 
-
 OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload,
                                 size_t *cborSize, int secureFlag)
 {
@@ -652,6 +659,7 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
     CborEncoder encoder;
     CborEncoder credArray;
     CborEncoder credRootMap;
+    CborEncoder roleIdMap;
 
     if (0 == cborLen)
     {
@@ -707,6 +715,10 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
         {
             mapSize++;
         }
+        if (IsNonEmptyRole(&cred->roleId))
+        {
+            mapSize++;
+        }
 #endif /* __WITH_DTLS__ ||  __WITH_TLS__*/
         if (!secureFlag && cred->privateData.data)
         {
@@ -744,6 +756,37 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
             OICFree(subject);
         }
 
+        //Role ID -- optional
+        if (IsNonEmptyRole(&cred->roleId))
+        {
+            cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_ROLEID_NAME,
+                strlen(OIC_JSON_ROLEID_NAME));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role ID map tag");
+
+            bool includeAuthority = (0 != memcmp(&cred->roleId.authority, &EMPTY_ROLE.authority, sizeof(EMPTY_ROLE.authority)));
+
+            cborEncoderResult = cbor_encoder_create_map(&credMap, &roleIdMap, ROLEID_MAP_SIZE + includeAuthority ? 1 : 0);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role ID map");
+
+            cborEncoderResult = cbor_encode_text_string(&roleIdMap, OIC_JSON_ROLE_NAME, strlen(OIC_JSON_ROLE_NAME));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role tag");
+            
+            cborEncoderResult = cbor_encode_text_string(&roleIdMap, cred->roleId.id, strlen(cred->roleId.id));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role value");
+
+            if (includeAuthority)
+            {
+                cborEncoderResult = cbor_encode_text_string(&roleIdMap, OIC_JSON_AUTHORITY_NAME, strlen(OIC_JSON_AUTHORITY_NAME));
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority tag");
+
+                cborEncoderResult = cbor_encode_text_string(&roleIdMap, cred->roleId.authority, strlen(cred->roleId.authority));
+                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding authority value");
+            }
+
+            cborEncoderResult = cbor_encoder_close_container(&credMap, &roleIdMap);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing role ID map");
+        }
+
         //CredType -- Mandatory
         cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_CREDTYPE_NAME,
             strlen(OIC_JSON_CREDTYPE_NAME));
@@ -917,6 +960,9 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
         return OC_STACK_INVALID_PARAM;
     }
 
+    char* tagName = NULL;
+    char* roleIdTagName = NULL;
+    char* name = NULL;
     OCStackResult ret = OC_STACK_ERROR;
     CborValue credCbor = { .parser = NULL };
     CborParser parser = { .end = NULL };
@@ -940,7 +986,6 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
 
     while (cbor_value_is_valid(&CredRootMap))
     {
-        char* tagName = NULL;
         size_t len = 0;
         CborType type = cbor_value_get_type(&CredRootMap);
         if (type == CborTextStringType && cbor_value_is_text_string(&CredRootMap))
@@ -988,7 +1033,6 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
 
                     while(cbor_value_is_valid(&credMap) && cbor_value_is_text_string(&credMap))
                     {
-                        char* name = NULL;
                         CborType cmType = cbor_value_get_type(&credMap);
                         if (cmType == CborTextStringType)
                         {
@@ -1026,6 +1070,77 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                                 //It is required to use free() instead of OICFree
                                 free(subjectid);
                             }
+                            // roleid
+                            if (strcmp(name, OIC_JSON_ROLEID_NAME) == 0)
+                            {
+                                /* Role subject */
+                                size_t unusedLen = 0;
+                                CborValue roleIdMap;
+                                memset(&roleIdMap, 0, sizeof(roleIdMap));
+
+                                cborFindResult = cbor_value_enter_container(&credMap, &roleIdMap);
+                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering role ID map");
+
+                                while (cbor_value_is_valid(&roleIdMap) && cbor_value_is_text_string(&roleIdMap))
+                                {
+                                    cborFindResult = cbor_value_dup_text_string(&roleIdMap, &roleIdTagName, &unusedLen, NULL);
+                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting role ID map tag name");
+                                    cborFindResult = cbor_value_advance(&roleIdMap);
+                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role ID map");
+
+                                    if (NULL != roleIdTagName)
+                                    {
+                                        if (strcmp(roleIdTagName, OIC_JSON_ROLE_NAME) == 0)
+                                        {
+                                            char *roleId = NULL;
+                                            cborFindResult = cbor_value_dup_text_string(&roleIdMap, &roleId, &unusedLen, NULL);
+                                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting role id value");
+                                            if (strlen(roleId) >= sizeof(cred->roleId.id))
+                                            {
+                                                cborFindResult = CborUnknownError;
+                                                free(roleId);
+                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Role ID is too long");
+                                            }
+                                            OICStrcpy(cred->roleId.id, sizeof(cred->roleId.id), roleId);
+                                            free(roleId);
+                                        }
+                                        else if (strcmp(roleIdTagName, OIC_JSON_AUTHORITY_NAME) == 0)
+                                        {
+                                            char *authorityName = NULL;
+                                            cborFindResult = cbor_value_dup_text_string(&roleIdMap, &authorityName, &unusedLen, NULL);
+                                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed getting role authority value");
+                                            if (strlen(authorityName) >= sizeof(cred->roleId.authority))
+                                            {
+                                                cborFindResult = CborUnknownError;
+                                                free(authorityName);
+                                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Authority name is too long");
+                                            }
+                                            OICStrcpy(cred->roleId.authority, sizeof(cred->roleId.authority), authorityName);
+                                            free(authorityName);
+                                        }
+                                        else
+                                        {
+                                            OIC_LOG_V(WARNING, TAG, "Unknown tag name in role ID map: %s", roleIdTagName);
+                                        }
+
+                                        free(roleIdTagName);
+                                        roleIdTagName = NULL;
+                                    }
+
+                                    if (cbor_value_is_valid(&roleIdMap))
+                                    {
+                                        cborFindResult = cbor_value_advance(&roleIdMap);
+                                        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role map");
+                                    }
+                                }
+
+                                /* Make sure at least the id is present. */
+                                if ('\0' == cred->roleId.id[0])
+                                {
+                                    cborFindResult = CborUnknownError;
+                                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "ID for role was not present in role map");
+                                }
+                            }
                             // credtype
                             if (strcmp(name, OIC_JSON_CREDTYPE_NAME)  == 0)
                             {
@@ -1095,6 +1210,7 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                             //Because cbor using malloc directly
                             //It is required to use free() instead of OICFree
                             free(name);
+                            name = NULL;
                         }
                     }
                     cred->next = NULL;
@@ -1114,10 +1230,10 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Rownerid Value.");
 
                 ret = ConvertStrToUuid(stRowner, &headCred->rownerID);
-                VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
                 //Because cbor using malloc directly
                 //It is required to use free() instead of OICFree
                 free(stRowner);
+                VERIFY_SUCCESS(TAG, (ret == OC_STACK_OK), ERROR);
             }
             else if (NULL != gCred)
             {
@@ -1126,6 +1242,7 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
             //Because cbor using malloc directly
             //It is required to use free() instead of OICFree
             free(tagName);
+            tagName = NULL;
         }
         if (cbor_value_is_valid(&CredRootMap))
         {
@@ -1146,6 +1263,10 @@ exit:
         ret = OC_STACK_ERROR;
     }
 
+    free(tagName);
+    free(roleIdTagName);
+    free(name);
+
     return ret;
 }
 
@@ -1524,6 +1645,7 @@ static CredCompareResult_t CompareCredential(const OicSecCred_t * l, const OicSe
 
     VERIFY_SUCCESS(TAG, (l->credType == r->credType), INFO);
     VERIFY_SUCCESS(TAG, (0 == memcmp(l->subject.id, r->subject.id, sizeof(l->subject.id))), INFO);
+    VERIFY_SUCCESS(TAG, (0 == memcmp(&l->roleId, &r->roleId, sizeof(l->roleId))), INFO);
 
     switch(l->credType)
     {
@@ -2636,6 +2758,11 @@ int32_t GetDtlsPskCredentials(CADtlsPskCredType_t type,
                             OICFree(outKey);
                         }
 
+                        if (OC_STACK_OK != RegisterSymmetricCredentialRole(cred))
+                        {
+                            OIC_LOG(WARNING, TAG, "Couldn't RegisterRoleForSubject");
+                        }
+
                         return ret;
                     }
                 }
index 32c461e..aa14e82 100644 (file)
@@ -48,6 +48,7 @@
 #include "ca_adapter_net_ssl.h"
 #include "ocstackinternal.h"
 #include "rolesresource.h"
+#include "secureresourcemanager.h"
 
 #define TAG  "OIC_SRM_ROLES"
 
@@ -63,11 +64,19 @@ typedef struct RolesEntry {
     struct RolesEntry       *next;
 } RolesEntry_t;
 
-static OCResourceHandle gRolesHandle        = NULL;
-static RolesEntry_t     *gRoles             = NULL;
-static uint32_t         gIdCounter          = 1;
+typedef struct SymmetricRoleEntry {
+    OicUuid_t                 subject;          /**< Subject of the symmetric credential */
+    OicSecRole_t              role;             /**< Role of the symmetric credential */
 
-/**
+    struct SymmetricRoleEntry *next;
+} SymmetricRoleEntry_t;
+
+static OCResourceHandle     gRolesHandle        = NULL;
+static RolesEntry_t         *gRoles             = NULL;
+static SymmetricRoleEntry_t *gSymmetricRoles    = NULL;
+static uint32_t             gIdCounter          = 1;
+
+/** 
  * Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
  * The value of payload size is increased until reaching max cbor size.
  */
@@ -107,7 +116,7 @@ static OCStackResult GetPeerPublicKeyFromEndpoint(const CAEndpoint_t *endpoint,
     if ((NULL == sep.publicKey) || (0 == sep.publicKeyLength))
     {
         OIC_LOG_V(ERROR, TAG, "%s: Peer did not have a public key", __func__);
-        return OC_STACK_ERROR;
+        return OC_STACK_INVALID_PARAM;
     }
 
     *publicKey = OICCalloc(1, sep.publicKeyLength);
@@ -187,6 +196,67 @@ static void FreeRolesList(RolesEntry_t *roles)
     }
 }
 
+static void FreeSymmetricRoleEntry(SymmetricRoleEntry_t *symRoleEntry)
+{
+    OICFree(symRoleEntry);
+}
+
+static void FreeSymmetricRolesList(SymmetricRoleEntry_t *head)
+{
+    if (NULL != head)
+    {
+        SymmetricRoleEntry_t *entryTmp1 = NULL;
+        SymmetricRoleEntry_t *entryTmp2 = NULL;
+
+        LL_FOREACH_SAFE(head, entryTmp1, entryTmp2)
+        {
+            LL_DELETE(head, entryTmp1);
+            FreeSymmetricRoleEntry(entryTmp1);
+        }
+    }
+}
+
+OCStackResult RegisterSymmetricCredentialRole(const OicSecCred_t *cred)
+{
+    VERIFY_NON_NULL_RET(cred, TAG, "Parameter cred is NULL", OC_STACK_INVALID_PARAM);
+    VERIFY_SUCCESS_RETURN(TAG, (SYMMETRIC_PAIR_WISE_KEY == cred->credType), ERROR, OC_STACK_INVALID_PARAM);
+
+    SymmetricRoleEntry_t *curr = NULL;
+
+    LL_FOREACH(gSymmetricRoles, curr)
+    {
+        if (0 == memcmp(&cred->subject, &curr->subject, sizeof(curr->subject)))
+        {
+            if (!IsNonEmptyRole(&cred->roleId))
+            {
+                LL_DELETE(gSymmetricRoles, curr);
+            }
+            else
+            {
+                curr->role = cred->roleId;
+            }
+
+            return OC_STACK_OK;
+        }
+    }
+
+    /* No entry found; add a new one if we're setting a role. */
+    if (IsNonEmptyRole(&cred->roleId))
+    {
+        curr = (SymmetricRoleEntry_t *)OICCalloc(1, sizeof(SymmetricRoleEntry_t));
+        if (NULL == curr)
+        {
+            OIC_LOG(ERROR, TAG, "No memory allocating new symmetric role entry");
+            return OC_STACK_NO_MEMORY;
+        }
+        LL_APPEND(gSymmetricRoles, curr);
+        curr->subject = cred->subject;
+        curr->role = cred->roleId;
+    }
+
+    return OC_STACK_OK;
+}
+
 static OCStackResult DuplicateRoleCertChain(const RoleCertChain_t *roleCert, RoleCertChain_t **duplicate)
 {
     OIC_LOG(DEBUG, TAG, "DuplicateRoleCertChain IN");
@@ -970,6 +1040,7 @@ OCStackResult DeInitRolesResource()
     gRolesHandle = NULL;
 
     FreeRolesList(gRoles);
+    FreeSymmetricRolesList(gSymmetricRoles);
 
     gRoles = NULL;
 
@@ -1045,8 +1116,37 @@ OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **role
     {
         /*
          * OC_STACK_INVALID_PARAM means the endpoint didn't authenticate with a certificate.
-         * Succeed and return no roles.
+         * Look for a symmetric key-based role and return that if present.
          */
+        CASecureEndpoint_t sep;
+        CAResult_t caRes = GetCASecureEndpointData(endpoint, &sep);
+        if (CA_STATUS_OK != caRes)
+        {
+            *roles = NULL;
+            *roleCount = 0;
+            return OC_STACK_OK;
+        }
+
+        SymmetricRoleEntry_t *curr = NULL;
+        LL_FOREACH(gSymmetricRoles, curr)
+        {
+            if ((UUID_LENGTH == sep.identity.id_length) && 
+                (0 == memcmp(curr->subject.id, sep.identity.id, sizeof(curr->subject.id))))
+            {
+                *roles = (OicSecRole_t *)OICCalloc(1, sizeof(OicSecRole_t));
+                if (NULL == *roles)
+                {
+                    OIC_LOG(ERROR, TAG, "No memory allocating roles for symmetric credential");
+                    return OC_STACK_NO_MEMORY;
+                }
+
+                (*roles)[0] = curr->role;
+                *roleCount = 1;
+                return OC_STACK_OK;
+            }
+        }
+
+        /* No symmetric role found. Return empty list. */
         *roles = NULL;
         *roleCount = 0;
         return OC_STACK_OK;
index d50d716..5d07c27 100644 (file)
@@ -662,3 +662,13 @@ OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
 
     return NOT_A_SVR_RESOURCE;
 }
+
+/**
+ * An unset role, used in comparisons.
+ */
+const OicSecRole_t EMPTY_ROLE = { .id = { 0 }, .authority = { 0 } };
+
+bool IsNonEmptyRole(const OicSecRole_t *role)
+{
+    return (0 != memcmp(&role->id, &EMPTY_ROLE.id, sizeof(role->id)));
+}
index 4b89eab..a484fdb 100644 (file)
@@ -128,7 +128,8 @@ const char * OIC_JSON_OM_NAME = "om";
 const char * OIC_JSON_SM_NAME = "sm";
 const char * OIC_JSON_CREDID_NAME = "credid";
 const char * OIC_JSON_SUBJECTID_NAME = "subjectuuid";
-const char * OIC_JSON_ROLEIDS_NAME = "roleid";
+const char * OIC_JSON_ROLEID_NAME = "roleid";
+const char * OIC_JSON_ROLE_NAME = "role";
 const char * OIC_JSON_AUTHORITY_NAME = "authority";
 const char * OIC_JSON_CREDTYPE_NAME = "credtype";
 const char * OIC_JSON_PUBLICDATA_NAME = "publicdata";
index 6402145..792c2ec 100644 (file)
@@ -36,6 +36,7 @@ OCProvisionCertificate
 OCProvisionCredentials
 OCProvisionDirectPairing
 OCProvisionPairwiseDevices
+OCProvisionSymmetricRoleCredentials
 OCProvisionTrustCertChain
 OCReadTrustCertChain
 OCRegisterTrustCertChainNotifier