[IOT-1785] Finish role certs feature
authorGreg Zaverucha <gregz@microsoft.com>
Tue, 28 Mar 2017 23:23:39 +0000 (16:23 -0700)
committerNathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
Fri, 31 Mar 2017 18:09:40 +0000 (18:09 +0000)
Add end-to-end testing of role certificate scenario:
- provision role certs
- test role-based ACLs provisioning and enforcement
- test assertion of role certificates

Fix bugs and add new functions as necessary. Added the ROLE_CERT
usage to distinguish role certs (which can't be used for TLS)
from identity certs. Previously they were both saved as PRIMARY_CERT.
Some small changes to save and retrieve role certificates locally. Add
functionality to assert roles (POST the certs to /oic/sec/roles).

Change-Id: I9080e0ca6b0809608621eb8b23dd4bbbfbbb176c
Signed-off-by: Greg Zaverucha <gregz@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/18219
Reviewed-by: Alex Kelley <alexke@microsoft.com>
Reviewed-by: Dave Thaler <dthaler@microsoft.com>
Reviewed-by: Kevin Kane <kkane@microsoft.com>
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Nathan Heldt-Sheller <nathan.heldt-sheller@intel.com>
19 files changed:
resource/csdk/security/include/internal/credresource.h
resource/csdk/security/include/internal/rolesresource.h
resource/csdk/security/include/internal/srmresourcestrings.h
resource/csdk/security/include/occertutility.h
resource/csdk/security/include/securevirtualresourcetypes.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/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/certhelpers.c
resource/csdk/security/src/credresource.c
resource/csdk/security/src/policyengine.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 876af2f..486ec8a 100644 (file)
@@ -24,6 +24,7 @@
 #include "cainterface.h"
 #include "securevirtualresourcetypes.h"
 #include "octypes.h"
+#include "rolesresource.h"
 #include <cbor.h>
 
 #ifdef __cplusplus
@@ -125,13 +126,13 @@ OCStackResult AddCredential(OicSecCred_t * cred);
 
 /**
  * Function to remove credentials from the SVR DB for the given subject UUID.
- * If multiple credentials exist for the UUID, they will all be removed. 
+ * If multiple credentials exist for the UUID, they will all be removed.
  *
  * @param subject is the Credential Subject to be deleted.
  *
- * @return ::OC_STACK_RESOURCE_DELETED if credentials were removed, or 
+ * @return ::OC_STACK_RESOURCE_DELETED if credentials were removed, or
  * if there are no credentials with the given UUID.  An error is returned if
- * removing credentials failed. 
+ * removing credentials failed.
  */
 OCStackResult RemoveCredential(const OicUuid_t *subject);
 
@@ -221,6 +222,18 @@ OCStackResult GetCredRownerId(OicUuid_t *rowneruuid);
  * @param[in] usage credential usage string.
  */
 OCStackResult GetPemCaCert(ByteArray_t * crt, const char * usage);
+
+/**
+ * Get a list of all role certificates. Used when asserting roles.
+ *
+ * @param[out] roleCerts list of role certificates
+ * @return When ::OC_STACK_OK is returned, a list of certificates (roleCerts)
+ *         that must be freed with FreeRoleCertChainList. roleCerts can still
+ *         be NULL in this case, if no role certs are installed. On error, an
+ *         error value is returned and roleCerts is NULL.
+ */
+OCStackResult GetAllRoleCerts(RoleCertChain_t** roleCerts);
+
 /**
  * Used by mbedTLS to retrieve own certificate chain
  *
index 9a7149a..252bd2c 100644 (file)
@@ -61,7 +61,7 @@ OCStackResult DeInitRolesResource();
  *                          On success, caller must free the received array with OICFree when finished
  * @param[out] roleCount    Variable to receive length of roles array.
  *
- * @note If the endpoint is found but has not asserted any roles with certificates, 
+ * @note If the endpoint is found but has not asserted any roles with certificates,
  *       OC_STACK_OK will be returned, but NULL will be returned in roles and 0 in roleCount.
  *
  * @return OC_STACK_OK if list of roles is successfully populated; error otherwise.
@@ -76,11 +76,25 @@ OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **role
  * @param[in] size Size of cborPayload
  * @param[out] roleCertList Pointer to receive linked list of RoleCertChain_t objects
  *             On success, caller must call FreeRoleCertChainList on *roleCertList when finished
+ *
  * @return OC_STACK_OK if payload is successfully converted; error code otherwise
  */
 OCStackResult CBORPayloadToRoles(const uint8_t *cborPayload, size_t size, RoleCertChain_t **roleCertList);
 
 /**
+ * This function converts a list of role certificates into a CBOR payload.
+ * Caller needs to call 'OICFree' on *cborPayload after use.
+ *
+ * @param[in] roles Linked list of RoleCertChain_t objects
+ * @param[out] cborPayload Pointer to receive the CBOR payload
+ *             On success, caller must call OICFree on *cborPayload when finished
+ * @param[out] size Pointer to receive size of cborPayload
+ *
+ * @return OC_STACK_OK if payload is successfully converted; error code otherwise
+ */
+OCStackResult RolesToCBORPayload(const RoleCertChain_t *roles, uint8_t **cborPayload, size_t *cborSize);
+
+/**
  * Free the memory used by a list of RoleCertChain_t objects created by CBORPayloadToRoles.
  *
  * @param[in] roleCertList List received from CBORPayloadToRoles
index 78a5167..b1b59b2 100644 (file)
@@ -181,6 +181,7 @@ extern const char * OIC_JSON_EMPTY_STRING;
 extern const char * TRUST_CA;
 extern const char * PRIMARY_CERT;
 extern const char * PRIMARY_KEY;
+extern const char * ROLE_CERT;
 
 // Certificates provided by manufacturer
 extern const char * MF_TRUST_CA;
index 7962cd0..12f936d 100644 (file)
@@ -132,7 +132,7 @@ OCStackResult OCGenerateIdentityCertificate(
     size_t *certificateLen);
 
 /**
- * Generate a certificate for a device's role.
+ * Generate a role certificate for a device.
  *
  * @param subjectUuid           UUID for the device to use the certificate.
  * @param subjectPublicKey      Subject's public key in PEM format
@@ -176,7 +176,7 @@ OCStackResult OCGenerateRoleCertificate(
  * @param[in]  csr  The CSR containing the UUID as null-terminated PEM.
  * @param[out] uuid The UUID in the CSR
  *
- * @return 0 on success, nonzero otherwise
+ * @return OC_STACK_OK if successful, error code otherwise
  */
 OCStackResult OCGetUuidFromCSR(const char* csr, OicUuid_t* uuid);
 
@@ -187,7 +187,7 @@ OCStackResult OCGetUuidFromCSR(const char* csr, OicUuid_t* uuid);
  * @param[out] publicKey The public key is output here as null-terminated PEM.
  *                       Callers must call OICFree when finished.
  *
- * @return 0 on success, nonzero otherwise
+ * @return OC_STACK_OK if successful, error code otherwise
  */
 OCStackResult OCGetPublicKeyFromCSR(const char* csr, char** publicKey);
 
@@ -196,7 +196,7 @@ OCStackResult OCGetPublicKeyFromCSR(const char* csr, char** publicKey);
  *
  * @param[in] csr The CSR to check, as null-terminated PEM.
  *
- * @returns 0 on success, nonzero otherwise
+ * @return OC_STACK_OK if successful, error code otherwise
  *
  * @remark Requires that ECDSA with SHA-256 be used for the signature.
  */
@@ -207,11 +207,11 @@ OCStackResult OCVerifyCSRSignature(const char* csr);
  *
  * @param[in] derCSR The CSR to convert, encoded as DER
  * @param[in] derCSRLen Then number of bytes in derCSR
- * @param[out] pemCSR The output, PEM encoded, null-terminated CSR. Callers 
- *                    call OICFree when finished. 
+ * @param[out] pemCSR The output, PEM encoded, null-terminated CSR. Callers
+ *                    call OICFree when finished.
  *
- * @returns 0 on success, nonzero otherwise
-*/
+ * @return OC_STACK_OK if successful, error code otherwise
+ */
 OCStackResult OCConvertDerCSRToPem(const char* derCSR, size_t derCSRLen, char** pemCSR);
 
 #ifdef __cplusplus
index 8ebe4f4..55a02f1 100644 (file)
@@ -293,14 +293,15 @@ enum
     OIC_R_AMACL_TYPE,
     OIC_R_CRED_TYPE,
     OIC_R_CRL_TYPE,
-    OIC_R_CSR_TYPE,
     OIC_R_DOXM_TYPE,
     OIC_R_DPAIRING_TYPE,
     OIC_R_PCONF_TYPE,
     OIC_R_PSTAT_TYPE,
-    OIC_R_ROLES_TYPE,
     OIC_R_SACL_TYPE,
     OIC_R_SVC_TYPE,
+    OIC_R_CSR_TYPE,
+    OIC_R_ACL2_TYPE,
+    OIC_R_ROLES_TYPE,
     OIC_SEC_SVR_TYPE_COUNT, //define the value to number of SVR
     NOT_A_SVR_RESOURCE = 99
 };
index 3a140c8..9e7c011 100644 (file)
@@ -157,6 +157,31 @@ OCStackResult SRPSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainS
 OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId);
 
 /**
+ * function to save own role certificate into Cred of SVR.
+ *
+ * @param[in] cert Certificate chain to be saved in Cred of SVR
+ * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ *
+ * @note The certificate public key must be the same as public key in the identity
+ *       certificate (installed by SRPSaveOwnCertChain).
+ */
+OCStackResult SRPSaveOwnRoleCert(OicSecKey_t * cert, uint16_t *credId);
+
+/**
+ * Assert all roles to a device. This POSTs all role certificates from the
+ * local cred resource to /oic/sec/roles.
+ *
+ * @param[in] ctx User context to be passed.
+ * @param[in] device The device to assert the roles to
+ * @param[in] resultCallback Callback that is called with the response from the device
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ *
+ * @note If no role certificates are installed, this will fail. See GetAllRoleCerts in credresource.h
+ */
+OCStackResult SRPAssertRoles(void *ctx, const OCProvisionDev_t *device, OCProvisionResultCB resultCallback);
+
+/**
  * function to register callback, for getting notification for TrustCertChain change.
  *
  * @param[in] ctx user context to be passed.
@@ -204,8 +229,8 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
  * @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] pemCert When provisioning a certificate (type is SIGNED_ASYMMETRIC_KEY), this is the 
- *                    certificate, encoded as PEM. 
+ * @param[in] pemCert When provisioning a certificate (type is SIGNED_ASYMMETRIC_KEY), this is the
+ *                    certificate, encoded as PEM.
  * @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.
index 790a55b..1441bb6 100644 (file)
-/* *****************************************************************\r
- *\r
- * Copyright 2015 Samsung Electronics All Rights Reserved.\r
- *\r
- *\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- *\r
- * *****************************************************************/\r
-\r
-#ifndef OCPROVISIONINGMANAGER_H_\r
-#define OCPROVISIONINGMANAGER_H_\r
-\r
-#include "octypes.h"\r
-#include "pmtypes.h"\r
-#include "ownershiptransfermanager.h"\r
-#ifdef MULTIPLE_OWNER\r
-#include "securevirtualresourcetypes.h"\r
-#endif //MULTIPLE_OWNER\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif // __cplusplus\r
-\r
-/**\r
- * The function is responsible for initializaton of the provisioning manager. It will load\r
- * provisioning database which have owned device's list and their linked status.\r
- * TODO: In addition, if there is a device(s) which has not up-to-date credentials, this function will\r
- * automatically try to update the deivce(s).\r
- *\r
- * @param[in] dbPath file path of the sqlite3 db\r
- *\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCInitPM(const char* dbPath);\r
-\r
-/**\r
- * API to cleanup PDM in case of timeout.\r
- * It will remove the PDM_DEVICE_INIT state devices from PDM.\r
- *\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCPDMCleanupForTimeout();\r
-\r
-/**\r
- * The function is responsible for discovery of owned/unowned device is specified endpoint/deviceID.\r
- * It will return the found device even though timeout is not exceeded.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    server before returning the device.\r
- * @param[in] deviceID         deviceID of target device.\r
- * @param[out] ppFoundDevice     OCProvisionDev_t of found device\r
- * @return OTM_SUCCESS in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverSingleDevice(unsigned short timeout, const OicUuid_t* deviceID,\r
-                             OCProvisionDev_t **ppFoundDevice);\r
-\r
-/**\r
- * The function is responsible for discovery of owned/unowned device is specified endpoint/MAC\r
- * address.\r
- * It will return the found device even though timeout is not exceeded.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    server before returning the device.\r
- * @param[in] deviceID         deviceID of target device.\r
- * @param[in] hostAddress       MAC address of target device.\r
- * @param[in] connType       ConnectivityType for discovery.\r
- * @param[out] ppFoundDevice     OCProvisionDev_t of found device.\r
- * @return OTM_SUCCESS in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverSingleDeviceInUnicast(unsigned short timeout, const OicUuid_t* deviceID,\r
-                             const char* hostAddress, OCConnectivityType connType,\r
-                             OCProvisionDev_t **ppFoundDevice);\r
-\r
-/**\r
- * The function is responsible for discovery of device is current subnet. It will list\r
- * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as\r
- * OCMode.\r
- *\r
- * @param[in] waittime Timeout in seconds, value till which function will listen to responses from\r
- *                    server before returning the list of devices.\r
- * @param[out] ppList List of candidate devices to be provisioned\r
- * @return OTM_SUCCESS in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverUnownedDevices(unsigned short waittime, OCProvisionDev_t **ppList);\r
-\r
-/**\r
- * Do ownership transfer for un-owned device.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] targetDevices List of devices to perform ownership transfer.\r
- * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDoOwnershipTransfer(void* ctx,\r
-                                    OCProvisionDev_t *targetDevices,\r
-                                    OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to set a allow status of OxM\r
- *\r
- * @param[in] oxm Owership transfer method (ref. OicSecOxm_t)\r
- * @param[in] allowStatus allow status (true = allow, false = not allow)\r
- *\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSetOxmAllowStatus(const OicSecOxm_t oxm, const bool allowStatus);\r
-\r
-#ifdef MULTIPLE_OWNER\r
-/**\r
- * API to perfrom multiple ownership transfer for MOT enabled device.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] targetDevices List of devices to perform ownership transfer.\r
- * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDoMultipleOwnershipTransfer(void* ctx,\r
-                                      OCProvisionDev_t *targetDevices,\r
-                                      OCProvisionResultCB resultCallback);\r
-#endif //MULTIPLE_OWNER\r
-\r
-/**\r
- * API to register for particular OxM.\r
- *\r
- * @param[in] oxm transfer method.\r
- * @param[in] callbackData of callback functions for owership transfer.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData);\r
-\r
-/**\r
- * The function is responsible for discovery of owned device is current subnet. It will list\r
- * all the device in subnet which are owned by calling provisioning client.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    server before returning the list of devices.\r
- * @param[out] ppList List of device owned by provisioning tool.\r
- * @return OTM_SUCCESS in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
-\r
-#ifdef MULTIPLE_OWNER\r
-/**\r
- * The function is responsible for the discovery of an MOT-enabled device with the specified deviceID.\r
- * The function will return when security information for device with deviceID has been obtained or the \r
- * timeout has been exceeded.\r
- *\r
- * @param[in]  timeoutSeconds  Maximum time, in seconds, this function will listen for responses from \r
- *                             servers before returning.\r
- * @param[in]  deviceID        deviceID of target device.\r
- * @param[out] ppFoundDevice   OCProvisionDev_t of discovered device. Caller should use\r
- *                             OCDeleteDiscoveredDevices to delete the device.\r
- * @return OC_STACK_OK in case of success and other values otherwise.\r
- */\r
-OCStackResult OCDiscoverMultipleOwnerEnabledSingleDevice(unsigned short timeoutSeconds,\r
-                                                         const OicUuid_t *deviceID, \r
-                                                         OCProvisionDev_t **ppFoundDevice);\r
-\r
-/**\r
- * The function is responsible for discovery of MOT enabled device is current subnet.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    server before returning the list of devices.\r
- * @param[out] ppList List of MOT enabled devices.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverMultipleOwnerEnabledDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
-\r
-/**\r
- * The function is responsible for discovery of Multiple Owned device is current subnet.\r
- *\r
- * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
- *                    server before returning the list of devices.\r
- * @param[out] ppList List of Multiple Owned devices.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCDiscoverMultipleOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
-\r
-/**\r
- * The function is responsible for determining if the caller is a subowner of the specified device.\r
- *\r
- * @param[in]  device      MOT enabled device that contains a list of subowners.\r
- * @param[out] isSubowner  Bool indicating whether the caller is a subowner of device.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCIsSubownerOfDevice(OCProvisionDev_t *device, bool *isSubowner);\r
-#endif //MULTIPLE_OWNER\r
-\r
-/**\r
- * API to provision credentials between two devices and ACLs for the devices who act as a server.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] type Type of credentials to be provisioned to the device.\r
+/* *****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics All Rights Reserved.
+ *
+ *
+ *
+ * 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 language governing permissions and
+ * limitations under the License.
+ *
+ * *****************************************************************/
+
+#ifndef OCPROVISIONINGMANAGER_H_
+#define OCPROVISIONINGMANAGER_H_
+
+#include "octypes.h"
+#include "pmtypes.h"
+#include "ownershiptransfermanager.h"
+#ifdef MULTIPLE_OWNER
+#include "securevirtualresourcetypes.h"
+#endif //MULTIPLE_OWNER
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * The function is responsible for initializaton of the provisioning manager. It will load
+ * provisioning database which have owned device's list and their linked status.
+ * TODO: In addition, if there is a device(s) which has not up-to-date credentials, this function will
+ * automatically try to update the deivce(s).
+ *
+ * @param[in] dbPath file path of the sqlite3 db
+ *
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCInitPM(const char* dbPath);
+
+/**
+ * API to cleanup PDM in case of timeout.
+ * It will remove the PDM_DEVICE_INIT state devices from PDM.
+ *
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCPDMCleanupForTimeout();
+
+/**
+ * The function is responsible for discovery of owned/unowned device is specified endpoint/deviceID.
+ * It will return the found device even though timeout is not exceeded.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the device.
+ * @param[in] deviceID         deviceID of target device.
+ * @param[out] ppFoundDevice     OCProvisionDev_t of found device
+ * @return OTM_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverSingleDevice(unsigned short timeout, const OicUuid_t* deviceID,
+                             OCProvisionDev_t **ppFoundDevice);
+
+/**
+ * The function is responsible for discovery of owned/unowned device is specified endpoint/MAC
+ * address.
+ * It will return the found device even though timeout is not exceeded.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the device.
+ * @param[in] deviceID         deviceID of target device.
+ * @param[in] hostAddress       MAC address of target device.
+ * @param[in] connType       ConnectivityType for discovery.
+ * @param[out] ppFoundDevice     OCProvisionDev_t of found device.
+ * @return OTM_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverSingleDeviceInUnicast(unsigned short timeout, const OicUuid_t* deviceID,
+                             const char* hostAddress, OCConnectivityType connType,
+                             OCProvisionDev_t **ppFoundDevice);
+
+/**
+ * The function is responsible for discovery of device is current subnet. It will list
+ * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as
+ * OCMode.
+ *
+ * @param[in] waittime Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the list of devices.
+ * @param[out] ppList List of candidate devices to be provisioned
+ * @return OTM_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverUnownedDevices(unsigned short waittime, OCProvisionDev_t **ppList);
+
+/**
+ * Do ownership transfer for un-owned device.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] targetDevices List of devices to perform ownership transfer.
+ * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDoOwnershipTransfer(void* ctx,
+                                    OCProvisionDev_t *targetDevices,
+                                    OCProvisionResultCB resultCallback);
+
+/**
+ * API to set a allow status of OxM
+ *
+ * @param[in] oxm Owership transfer method (ref. OicSecOxm_t)
+ * @param[in] allowStatus allow status (true = allow, false = not allow)
+ *
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSetOxmAllowStatus(const OicSecOxm_t oxm, const bool allowStatus);
+
+#ifdef MULTIPLE_OWNER
+/**
+ * API to perfrom multiple ownership transfer for MOT enabled device.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] targetDevices List of devices to perform ownership transfer.
+ * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDoMultipleOwnershipTransfer(void* ctx,
+                                      OCProvisionDev_t *targetDevices,
+                                      OCProvisionResultCB resultCallback);
+#endif //MULTIPLE_OWNER
+
+/**
+ * API to register for particular OxM.
+ *
+ * @param[in] oxm transfer method.
+ * @param[in] callbackData of callback functions for owership transfer.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData);
+
+/**
+ * The function is responsible for discovery of owned device is current subnet. It will list
+ * all the device in subnet which are owned by calling provisioning client.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the list of devices.
+ * @param[out] ppList List of device owned by provisioning tool.
+ * @return OTM_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);
+
+#ifdef MULTIPLE_OWNER
+/**
+ * The function is responsible for the discovery of an MOT-enabled device with the specified deviceID.
+ * The function will return when security information for device with deviceID has been obtained or the
+ * timeout has been exceeded.
+ *
+ * @param[in]  timeoutSeconds  Maximum time, in seconds, this function will listen for responses from
+ *                             servers before returning.
+ * @param[in]  deviceID        deviceID of target device.
+ * @param[out] ppFoundDevice   OCProvisionDev_t of discovered device. Caller should use
+ *                             OCDeleteDiscoveredDevices to delete the device.
+ * @return OC_STACK_OK in case of success and other values otherwise.
+ */
+OCStackResult OCDiscoverMultipleOwnerEnabledSingleDevice(unsigned short timeoutSeconds,
+                                                         const OicUuid_t *deviceID,
+                                                         OCProvisionDev_t **ppFoundDevice);
+
+/**
+ * The function is responsible for discovery of MOT enabled device is current subnet.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the list of devices.
+ * @param[out] ppList List of MOT enabled devices.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverMultipleOwnerEnabledDevices(unsigned short timeout, OCProvisionDev_t **ppList);
+
+/**
+ * The function is responsible for discovery of Multiple Owned device is current subnet.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the list of devices.
+ * @param[out] ppList List of Multiple Owned devices.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverMultipleOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);
+
+/**
+ * The function is responsible for determining if the caller is a subowner of the specified device.
+ *
+ * @param[in]  device      MOT enabled device that contains a list of subowners.
+ * @param[out] isSubowner  Bool indicating whether the caller is a subowner of device.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCIsSubownerOfDevice(OCProvisionDev_t *device, bool *isSubowner);
+#endif //MULTIPLE_OWNER
+
+/**
+ * API to provision credentials between two devices and ACLs for the devices who act as a server.
+ *
+ * @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 device to be provisioned.\r
- * @param[in] pDev1Acl ACL for device 1. If this is not required set NULL.\r
- * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.\r
- * @param[in] pDev2Acl ACL for device 2. If this is not required set NULL.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request recieves a response from first resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,\r
-                                         const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,\r
-                                         const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,\r
-                                         OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to send version 1 ACL information to device.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] acl ACL to provision.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to send version 2 ACL information to device.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] acl ACL to provision.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
+ * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.
+ * @param[in] pDev1Acl ACL for device 1. If this is not required set NULL.
+ * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned.
+ * @param[in] pDev2Acl ACL for device 2. If this is not required set NULL.
+ * @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 OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
+                                         const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
+                                         const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
+                                         OCProvisionResultCB resultCallback);
+
+/**
+ * API to send version 1 ACL information to device.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] acl ACL to provision.
+ * @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 OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * API to send version 2 ACL information to device.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] acl ACL to provision.
+ * @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 OCProvisionACL2(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
-                              OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * function to save ACL which has several ACE into Acl of SVR.\r
- *\r
- * @param acl ACL to be saved in Acl of SVR.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSaveACL(const OicSecAcl_t* acl);\r
-\r
-/**\r
- * this function requests CRED information to resource.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCGetCredResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * this function requests version 1 ACL information to resource.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * this function requests version 2 ACL information to resource.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
-                               OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * This function requests the device provide its Certificate Signing Request (CSR).\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCGetCSRResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
-                               OCGetCSRResultCB resultCallback);\r
-\r
-/**\r
- * This function requests the device provide its roles resource, listing the role certificates\r
- * it has for the local requestor.\r
- *\r
- * @param[in] ctx Application context that is returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] resultCallback callback provided by the API user. Callback will be called when provisioning\r
- *                           request receives a response from the resource server.\r
- * @return OC_STACK_OK in case of success, and error value otherwise.\r
- */\r
-OCStackResult OCGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
-                                 OCGetRolesResultCB resultCallback);\r
-\r
-/**\r
- * This function requests the device delete a particular role certificate by credId.\r
- *\r
- * @param[in] ctx Application context that is returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] resultCallback callback provided by the API user. Callback will be called when request receives\r
- *            a response from the resource server.\r
- * @param[in] credId credId to request be deleted. If 0, delete all role certificates for this peer.\r
- *\r
- * @return OC_STACK_OK in case of success, and error value otherwise.\r
- */\r
-OCStackResult OCDeleteRoleCertificateByCredId(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
-                                              OCProvisionResultCB resultCallback, uint32_t credId);\r
-\r
-/**\r
- * this function sends Direct-Pairing Configuration to a device.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] pconf PCONF pointer.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecPconf_t *pconf,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to provision credential to devices.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] type Type of credentials to be provisioned to the device.\r
+                              OCProvisionResultCB resultCallback);
+
+/**
+ * function to save ACL which has several ACE into Acl of SVR.
+ *
+ * @param acl ACL to be saved in Acl of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSaveACL(const OicSecAcl_t* acl);
+
+/**
+ * this function requests CRED information to resource.
+ *
+ * @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 OCGetCredResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * this function requests version 1 ACL information to resource.
+ *
+ * @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 OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * this function requests version 2 ACL information to resource.
+ *
+ * @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 OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                               OCProvisionResultCB resultCallback);
+
+/**
+ * This function requests the device provide its Certificate Signing Request (CSR).
+ *
+ * @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 OCGetCSRResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                               OCGetCSRResultCB resultCallback);
+
+/**
+ * This function requests the device provide its roles resource, listing the role certificates
+ * it has for the local requestor.
+ *
+ * @param[in] ctx Application context that is returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback callback provided by the API user. Callback will be called when provisioning
+ *                           request receives a response from the resource server.
+ * @return OC_STACK_OK in case of success, and error value otherwise.
+ */
+OCStackResult OCGetRolesResource(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                 OCGetRolesResultCB resultCallback);
+
+/**
+ * This function requests the device delete a particular role certificate by credId.
+ *
+ * @param[in] ctx Application context that is returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] resultCallback callback provided by the API user. Callback will be called when request receives
+ *            a response from the resource server.
+ * @param[in] credId credId to request be deleted. If 0, delete all role certificates for this peer.
+ *
+ * @return OC_STACK_OK in case of success, and error value otherwise.
+ */
+OCStackResult OCDeleteRoleCertificateByCredId(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
+                                              OCProvisionResultCB resultCallback, uint32_t credId);
+
+/**
+ * this function sends Direct-Pairing Configuration to a device.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] pconf PCONF pointer.
+ * @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 OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecPconf_t *pconf,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * API to provision credential to devices.
+ *
+ * @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.\r
-   @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request recieves a response from first resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,\r
-                                      const OCProvisionDev_t *pDev1,\r
-                                      const OCProvisionDev_t *pDev2,\r
-                                      OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to provision a certificate to a device.\r
- *\r
- * @param[in] ctx Application context returned in result callback.\r
- * @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.\r
- * @param[in] pemCert Certificate to provision, encoded as PEM\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request receives a response from first resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionCertificate(void *ctx,\r
-                                     const OCProvisionDev_t *pDev,\r
-                                     const char* pemCert,\r
-                                     OCProvisionResultCB resultCallback);\r
-\r
-#ifdef MULTIPLE_OWNER\r
-/**\r
- * API to provision preconfigured PIN to device(NOT LIST).\r
- * If device does not support the Preconfigured PIN OxM,\r
- * OCProvisionPreconfigPin API will update the device's Doxm\r
- * and then try preconfigured PIN provisioning once again.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] targetDeviceInfo Selected target device.\r
- * @param[in] preconfigPin string of preconfigured PIN.\r
- * @param[in] preconfigPinLen string length of 'preconfigPin'.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request recieves a response from first resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionPreconfigPin(void *ctx,\r
-                                      OCProvisionDev_t *targetDeviceInfo,\r
-                                      const char *preconfigPin,\r
-                                      size_t preconfigPinLen,\r
-                                      OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to add preconfigured PIN to local SVR DB.\r
- *\r
- * @param[in] targetDeviceInfo Selected target device.\r
- * @param[in] preconfigPin Preconfig PIN which is used while multiple owner authentication\r
- * @param[in] preconfigPinLen Byte length of preconfigPin\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCAddPreconfigPin(const OCProvisionDev_t *targetDeviceInfo,\r
-                                const char *preconfigPin, \r
-                                size_t preconfigPinLen);\r
-\r
-/**\r
- * API to update 'doxm.mom' to resource server.\r
- *\r
- * @param[in] targetDeviceInfo Selected target device.\r
- * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            POST 'mom' request recieves a response from resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCChangeMOTMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,\r
-                            const OicSecMomType_t momType, OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * API to update 'doxm.oxmsel' to resource server.\r
- *\r
- * @param[in] targetDeviceInfo Selected target device.\r
- * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.doxmtype)\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            POST 'oxmsel' request recieves a response from resource server.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,\r
-                                 const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback);\r
-#endif //MULTIPLE_OWNER\r
-\r
-/**\r
- * Function to unlink devices.\r
- * This function will remove the credential & relasionship between the two devices.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] pTargetDev1 fitst device information to be unlinked.\r
- * @param[in] pTargetDev2 second device information to be unlinked.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            device unlink is finished.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCUnlinkDevices(void* ctx,\r
-                              const OCProvisionDev_t* pTargetDev1,\r
-                              const OCProvisionDev_t* pTargetDev2,\r
-                              OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * Function for device revocation\r
- * This function will remove credential of target device from all devices in subnet.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
- * @param[in] pTargetDev Device information to be revoked.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            credential revocation is finished.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- *         if OC_STACK_OK is returned, the caller of this API should wait for callback.\r
- *         OC_STACK_CONTINUE means operation is success but no need to wait for callback.\r
- */\r
-OCStackResult OCRemoveDevice(void* ctx,\r
-                             unsigned short waitTimeForOwnedDeviceDiscovery,\r
-                             const OCProvisionDev_t* pTargetDev,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * Function to device revocation\r
- * This function will remove credential of target device from all devices in subnet.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
- * @param[in] pTargetUuid Device information to be revoked.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            credential revocation is finished.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCRemoveDeviceWithUuid(void* ctx,\r
-                                     unsigned short waitTimeForOwnedDeviceDiscovery,\r
-                                     const OicUuid_t* pTargetUuid,\r
-                                     OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * Function to reset the target device.\r
- * This function will remove credential and ACL of target device from all devices in subnet.\r
- *\r
- * @param[in] ctx Application context would be returned in result callback\r
- * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
- * @param[in] pTargetDev Device information to be revoked.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            credential revocation is finished.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCResetDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,\r
-                            const OCProvisionDev_t* pTargetDev,\r
-                            OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * This function resets SVR DB to its factory setting.\r
- *\r
- *@return OC_STACK_OK in case of successful reset and other value otherwise.\r
- */\r
-OCStackResult OCResetSVRDB(void);\r
-\r
-/**\r
- * This function configures SVR DB as self-ownership.\r
- *\r
- *@return OC_STACK_OK in case of successful configue and other value otherwise.\r
- */\r
-OCStackResult OCConfigSelfOwnership(void);\r
-\r
-/**\r
- * API to get status of all the devices in current subnet. The status include endpoint information\r
- * and doxm information which can be extracted duing owned and unowned discovery. Along with this\r
- * information. The API will provide information about devices' status\r
- * Device can have following states\r
- *  - ON/OFF: Device is switched on or off.\r
- *\r
- * NOTE: Caller need to call OCDeleteDiscoveredDevices to delete memory allocated by this API for out\r
- * variables pOwnedDevList and pUnownedDevList.\r
- *\r
- * @param[in] waittime Wait time for the API. The wait time will be divided by 2, and half of wait time\r
- * will be used for unowned discovery and remaining half for owned discovery. So the wait time should be\r
- * equal to or more than 2.\r
- * @param[out] pOwnedDevList  list of owned devices.\r
- * @param[out] pUnownedDevList  list of unowned devices.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCGetDevInfoFromNetwork(unsigned short waittime,\r
-                                       OCProvisionDev_t** pOwnedDevList,\r
-                                       OCProvisionDev_t** pUnownedDevList);\r
-/**\r
- * This method is used to get linked devices' IDs.\r
- *\r
- * @param[in] uuidOfDevice a target device's uuid.\r
- * @param[out] uuidList information about the list of linked devices' uuids.\r
- * @param[out] numOfDevices total number of linked devices.\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice,\r
-                                  OCUuidList_t** uuidList,\r
-                                  size_t* numOfDevices);\r
-\r
-/**\r
- * Remove locally stored credentials with the specified subject UUID.\r
- *\r
- * @param[in] subjectUuid The subject UUID of the credentials to remove\r
- *\r
+ * @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] 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 OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
+                                      const OCProvisionDev_t *pDev1,
+                                      const OCProvisionDev_t *pDev2,
+                                      OCProvisionResultCB resultCallback);
+
+/**
+ * API to provision a certificate to a device.
+ *
+ * @param[in] ctx Application context returned in result callback.
+ * @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.
+ * @param[in] pemCert Certificate to provision, encoded as PEM
+ * @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 OCProvisionCertificate(void *ctx,
+                                     const OCProvisionDev_t *pDev,
+                                     const char* pemCert,
+                                     OCProvisionResultCB resultCallback);
+
+#ifdef MULTIPLE_OWNER
+/**
+ * API to provision preconfigured PIN to device(NOT LIST).
+ * If device does not support the Preconfigured PIN OxM,
+ * OCProvisionPreconfigPin API will update the device's Doxm
+ * and then try preconfigured PIN provisioning once again.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfigPin string of preconfigured PIN.
+ * @param[in] preconfigPinLen string length of 'preconfigPin'.
+ * @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 OCProvisionPreconfigPin(void *ctx,
+                                      OCProvisionDev_t *targetDeviceInfo,
+                                      const char *preconfigPin,
+                                      size_t preconfigPinLen,
+                                      OCProvisionResultCB resultCallback);
+
+/**
+ * API to add preconfigured PIN to local SVR DB.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfigPin Preconfig PIN which is used while multiple owner authentication
+ * @param[in] preconfigPinLen Byte length of preconfigPin
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCAddPreconfigPin(const OCProvisionDev_t *targetDeviceInfo,
+                                const char *preconfigPin,
+                                size_t preconfigPinLen);
+
+/**
+ * API to update 'doxm.mom' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'mom' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCChangeMOTMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                            const OicSecMomType_t momType, OCProvisionResultCB resultCallback);
+
+/**
+ * API to update 'doxm.oxmsel' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.doxmtype)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'oxmsel' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                                 const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback);
+#endif //MULTIPLE_OWNER
+
+/**
+ * Function to unlink devices.
+ * This function will remove the credential & relasionship between the two devices.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] pTargetDev1 fitst device information to be unlinked.
+ * @param[in] pTargetDev2 second device information to be unlinked.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            device unlink is finished.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCUnlinkDevices(void* ctx,
+                              const OCProvisionDev_t* pTargetDev1,
+                              const OCProvisionDev_t* pTargetDev2,
+                              OCProvisionResultCB resultCallback);
+
+/**
+ * Function for device revocation
+ * This function will remove credential of target device from all devices in subnet.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
+ * @param[in] pTargetDev Device information to be revoked.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            credential revocation is finished.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ *         if OC_STACK_OK is returned, the caller of this API should wait for callback.
+ *         OC_STACK_CONTINUE means operation is success but no need to wait for callback.
+ */
+OCStackResult OCRemoveDevice(void* ctx,
+                             unsigned short waitTimeForOwnedDeviceDiscovery,
+                             const OCProvisionDev_t* pTargetDev,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * Function to device revocation
+ * This function will remove credential of target device from all devices in subnet.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
+ * @param[in] pTargetUuid Device information to be revoked.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            credential revocation is finished.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCRemoveDeviceWithUuid(void* ctx,
+                                     unsigned short waitTimeForOwnedDeviceDiscovery,
+                                     const OicUuid_t* pTargetUuid,
+                                     OCProvisionResultCB resultCallback);
+
+/**
+ * Function to reset the target device.
+ * This function will remove credential and ACL of target device from all devices in subnet.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
+ * @param[in] pTargetDev Device information to be revoked.
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            credential revocation is finished.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCResetDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
+                            const OCProvisionDev_t* pTargetDev,
+                            OCProvisionResultCB resultCallback);
+
+/**
+ * This function resets SVR DB to its factory setting.
+ *
+ *@return OC_STACK_OK in case of successful reset and other value otherwise.
+ */
+OCStackResult OCResetSVRDB(void);
+
+/**
+ * This function configures SVR DB as self-ownership.
+ *
+ *@return OC_STACK_OK in case of successful configue and other value otherwise.
+ */
+OCStackResult OCConfigSelfOwnership(void);
+
+/**
+ * API to get status of all the devices in current subnet. The status include endpoint information
+ * and doxm information which can be extracted duing owned and unowned discovery. Along with this
+ * information. The API will provide information about devices' status
+ * Device can have following states
+ *  - ON/OFF: Device is switched on or off.
+ *
+ * NOTE: Caller need to call OCDeleteDiscoveredDevices to delete memory allocated by this API for out
+ * variables pOwnedDevList and pUnownedDevList.
+ *
+ * @param[in] waittime Wait time for the API. The wait time will be divided by 2, and half of wait time
+ * will be used for unowned discovery and remaining half for owned discovery. So the wait time should be
+ * equal to or more than 2.
+ * @param[out] pOwnedDevList  list of owned devices.
+ * @param[out] pUnownedDevList  list of unowned devices.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCGetDevInfoFromNetwork(unsigned short waittime,
+                                       OCProvisionDev_t** pOwnedDevList,
+                                       OCProvisionDev_t** pUnownedDevList);
+/**
+ * This method is used to get linked devices' IDs.
+ *
+ * @param[in] uuidOfDevice a target device's uuid.
+ * @param[out] uuidList information about the list of linked devices' uuids.
+ * @param[out] numOfDevices total number of linked devices.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice,
+                                  OCUuidList_t** uuidList,
+                                  size_t* numOfDevices);
+
+/**
+ * Remove locally stored credentials with the specified subject UUID.
+ *
+ * @param[in] subjectUuid The subject UUID of the credentials to remove
+ *
  * @return OC_STACK_RESOURCE_DELETED if credentials were removed, or
- * OC_STACK_ERROR if no credentials were removed.\r
- */\r
-OCStackResult OCRemoveCredential(const OicUuid_t* subjectUuid);\r
-\r
-/**\r
- * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API.\r
- *\r
- * @param[in] pList Pointer to OCProvisionDev_t which should be deleted.\r
- */\r
-void OCDeleteDiscoveredDevices(OCProvisionDev_t *pList);\r
-\r
-/**\r
- * API to delete memory allocated to OicUuid_t list.\r
- *\r
- * @param[in] pList Pointer to OicUuid_t list which should be deleted.\r
- */\r
-void OCDeleteUuidList(OCUuidList_t* pList);\r
-\r
-/**\r
- * This function deletes ACL data.\r
- *\r
- * @param pAcl Pointer to OicSecAcl_t structure.\r
- */\r
-void OCDeleteACLList(OicSecAcl_t* pAcl);\r
-\r
-/**\r
- * This function deletes PDACL data.\r
- *\r
- * @param pPdAcl Pointer to OicSecPdAcl_t structure.\r
- */\r
-void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl);\r
-\r
-#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)\r
-/**\r
- * this function sends CRL information to resource.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] selectedDeviceInfo Selected target device.\r
- * @param[in] crl CRL to provision.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when provisioning\r
-              request recieves a response from resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecCrl_t *crl,\r
-                             OCProvisionResultCB resultCallback);\r
-\r
-/**\r
- * function to provision Trust certificate chain to devices.\r
- *\r
- * @param[in] ctx Application context returned in the result callback.\r
- * @param[in] type Type of credentials to be provisioned to the device.\r
- * @param[in] credId CredId of trust certificate chain to be provisioned to the device.\r
- * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.\r
- * @param[in] resultCallback callback provided by API user, callback will be called when\r
- *            provisioning request recieves a response from first resource server.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,\r
-                                      const OCProvisionDev_t *selectedDeviceInfo,\r
-                                      OCProvisionResultCB resultCallback);\r
-/**\r
- * function to save Trust certificate chain into Cred of SVR.\r
- *\r
- * @param[in] trustCertChain Trust certificate chain to be saved in Cred of SVR.\r
- * @param[in] chainSize Size of trust certificate chain to be saved in Cred of SVR\r
- * @param[in] encodingType Encoding type of trust certificate chain to be saved in Cred of SVR\r
- * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,\r
-                                   OicEncodingType_t encodingType, uint16_t *credId);\r
-\r
-/**\r
- * Function to save an identity certificate chain into Cred of SVR.\r
- *\r
- * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated\r
- * @param[in] key private key corresponding to the certificate, PEM encoded, null terminated\r
- * @param[out] credId CredId of saved certificate chain in Cred of SVR.\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCSaveOwnCertChain(const char* cert, const char* key, uint16_t *credId);\r
-\r
-/**\r
- * function to register callback, for getting notification for TrustCertChain change.\r
- *\r
- * @param[in] TrustCertChainChangeCB notifier callback function\r
- * @return OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCRegisterTrustCertChainNotifier(void *cb, TrustCertChainChangeCB CB);\r
-\r
-/**\r
- * function to de-register TrustCertChain notification callback.\r
- */\r
-void OCRemoveTrustCertChainNotifier(void);\r
-\r
-/**\r
- * Function to read Trust certificate chain from SVR.\r
- * Caller must free when done using the returned trust certificate\r
- * @param[in] credId CredId of trust certificate chain in SVR.\r
- * @param[out] trustCertChain Trust certificate chain.\r
- * @param[out] chainSize Size of trust certificate chain\r
- * @return  OC_STACK_OK in case of success and other value otherwise.\r
- */\r
-OCStackResult OCReadTrustCertChain(uint16_t credId, uint8_t **trustCertChain,\r
-                                     size_t *chainSize);\r
-\r
-/**\r
- * Function to select appropriate security provisioning method.\r
- *\r
- * @param[in] supportedMethods   Array of supported methods\r
- * @param[in] numberOfMethods   number of supported methods\r
- * @param[out]  selectedMethod         Selected methods\r
- * @param[in] ownerType type of owner device (SUPER_OWNER or SUB_OWNER)\r
- * @return  OC_STACK_OK on success\r
- */\r
-OCStackResult OCSelectOwnershipTransferMethod(const OicSecOxm_t *supportedMethods,\r
-        size_t numberOfMethods, OicSecOxm_t *selectedMethod, OwnerType_t ownerType);\r
-\r
-#endif // __WITH_DTLS__ || __WITH_TLS__\r
-\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif // __cplusplus\r
-\r
-#endif /* OCPROVISIONINGMANAGER_H_ */\r
+ * OC_STACK_ERROR if no credentials were removed.
+ */
+OCStackResult OCRemoveCredential(const OicUuid_t* subjectUuid);
+
+/**
+ * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API.
+ *
+ * @param[in] pList Pointer to OCProvisionDev_t which should be deleted.
+ */
+void OCDeleteDiscoveredDevices(OCProvisionDev_t *pList);
+
+/**
+ * API to delete memory allocated to OicUuid_t list.
+ *
+ * @param[in] pList Pointer to OicUuid_t list which should be deleted.
+ */
+void OCDeleteUuidList(OCUuidList_t* pList);
+
+/**
+ * This function deletes ACL data.
+ *
+ * @param pAcl Pointer to OicSecAcl_t structure.
+ */
+void OCDeleteACLList(OicSecAcl_t* pAcl);
+
+/**
+ * This function deletes PDACL data.
+ *
+ * @param pPdAcl Pointer to OicSecPdAcl_t structure.
+ */
+void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl);
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+/**
+ * this function sends CRL information to resource.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] selectedDeviceInfo Selected target device.
+ * @param[in] crl CRL to provision.
+ * @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 OCProvisionCRL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecCrl_t *crl,
+                             OCProvisionResultCB resultCallback);
+
+/**
+ * function to provision Trust certificate chain to devices.
+ *
+ * @param[in] ctx Application context returned in the result callback.
+ * @param[in] type Type of credentials to be provisioned to the device.
+ * @param[in] credId CredId of trust certificate chain to be provisioned to the device.
+ * @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 OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
+                                      const OCProvisionDev_t *selectedDeviceInfo,
+                                      OCProvisionResultCB resultCallback);
+/**
+ * function to save Trust certificate chain into Cred of SVR.
+ *
+ * @param[in] trustCertChain Trust certificate chain to be saved in Cred of SVR.
+ * @param[in] chainSize Size of trust certificate chain to be saved in Cred of SVR
+ * @param[in] encodingType Encoding type of trust certificate chain to be saved in Cred of SVR
+ * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSaveTrustCertChain(const uint8_t *trustCertChain, size_t chainSize,
+                                   OicEncodingType_t encodingType, uint16_t *credId);
+
+/**
+ * Function to save an identity certificate chain into Cred of SVR.
+ *
+ * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated
+ * @param[in] key private key corresponding to the certificate, PEM encoded, null terminated
+ * @param[out] credId CredId of saved certificate chain in Cred of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSaveOwnCertChain(const char* cert, const char* key, uint16_t *credId);
+
+/**
+ * Function to save own role certificate into Cred of SVR.
+ *
+ * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated
+ * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ *
+ * @note The certificate public key must be the same as public key in the identity
+ *       certificate (installed by OCSaveOwnCertChain).
+ */
+OCStackResult OCSaveOwnRoleCert(const char* cert, uint16_t *credId);
+
+/**
+ * function to register callback, for getting notification for TrustCertChain change.
+ *
+ * @param[in] TrustCertChainChangeCB notifier callback function
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCRegisterTrustCertChainNotifier(void *cb, TrustCertChainChangeCB CB);
+
+/**
+ * function to de-register TrustCertChain notification callback.
+ */
+void OCRemoveTrustCertChainNotifier(void);
+
+/**
+ * Function to read Trust certificate chain from SVR.
+ * Caller must free when done using the returned trust certificate
+ * @param[in] credId CredId of trust certificate chain in SVR.
+ * @param[out] trustCertChain Trust certificate chain.
+ * @param[out] chainSize Size of trust certificate chain
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCReadTrustCertChain(uint16_t credId, uint8_t **trustCertChain,
+                                     size_t *chainSize);
+
+/**
+ * Function to select appropriate security provisioning method.
+ *
+ * @param[in] supportedMethods   Array of supported methods
+ * @param[in] numberOfMethods   number of supported methods
+ * @param[out]  selectedMethod         Selected methods
+ * @param[in] ownerType type of owner device (SUPER_OWNER or SUB_OWNER)
+ * @return  OC_STACK_OK on success
+ */
+OCStackResult OCSelectOwnershipTransferMethod(const OicSecOxm_t *supportedMethods,
+        size_t numberOfMethods, OicSecOxm_t *selectedMethod, OwnerType_t ownerType);
+
+#endif // __WITH_DTLS__ || __WITH_TLS__
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* OCPROVISIONINGMANAGER_H_ */
index 783d542..c05411e 100644 (file)
@@ -50,6 +50,9 @@
 #include "occertutility.h"
 #include "pmutility.h"
 
+#include "secureresourceprovider.h" /* @todo: For SRPAssertRoles. Remove once IOT-1952 is resolved. */
+
+
 #ifdef _MSC_VER
 #include <io.h>
 
@@ -64,7 +67,7 @@ extern "C"
 
 #define DISCOVERY_TIMEOUT   3  // 3 sec
 #define CALLBACK_TIMEOUT    60  // 1 min
-#define TAG "provisioningclient"
+#define TAG "autoprovisioningclient"
 
 static const char* SVR_DB_FILE_NAME = "oic_svr_db_client.dat";
         // '_' for separaing from the same constant variable in |srmresourcestrings.c|
@@ -72,6 +75,12 @@ static const char* PRVN_DB_FILE_NAME = "oic_autoprvn_mng.db";
 
 static const char* TEST_CERT_NOT_BEFORE = "20170101000000"; // Not before field for certificates, in format YYYYMMDDhhmmss
 static const char* TEST_CERT_NOT_AFTER = "20270101000000";  // + ten years
+static const char* TEST_CERT_ROLE1 = "IoTivity-test-role1";
+static const char* TEST_CERT_ROLE2 = "IoTivity-test-role2";
+static const char* TEST_CERT_AUTHORITY = "IoTivity-test-OBT-authority-name";
+
+static OicUuid_t WILDCARD_SUBJECT_ID = { "*" };
+static size_t WILDCARD_SUBJECT_ID_LEN = 1;
 
 // |g_ctx| means provision manager application context and
 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
@@ -85,6 +94,7 @@ static int g_own_cnt;
 static int g_unown_cnt;
 static char* g_csr;    /* Certificate signing request from device */
 static OicUuid_t g_uuidDev1;
+static char* g_idPublicKey = NULL;
 
 static volatile bool g_doneCB;    /* Set to true by the callback to indicate it completed. */
 static bool g_successCB; /* Set to true by the callback to indicate success. */
@@ -103,28 +113,28 @@ static int waitCallbackRet(void);
  * Test CA key and certificate created with
  * iotivity/resource/csdk/security/scripts/test_cert_generation.sh
  */
-static const char* g_caCertPem = "-----BEGIN CERTIFICATE-----\n"\r
-"MIIBfjCCASSgAwIBAgIJAPQXoGTceaW5MAoGCCqGSM49BAMCMBkxFzAVBgNVBAoM\n"\r
-"DklvVGl2aXR5VGVzdENBMB4XDTE3MDMxNTAwNTExOVoXDTMwMTEyMjAwNTExOVow\n"\r
-"GTEXMBUGA1UECgwOSW9UaXZpdHlUZXN0Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"\r
-"BwNCAARvYPdt+LjqASlHoc2zrjo3hHGjZsI31c+bg9AwINW5TuRZsE03w/Ejotza\n"\r
-"y4VDLImMlDhGP+K/f6OmKD3FNHhKo1UwUzAhBgNVHSUEGjAYBgorBgEEAYLefAEG\n"\r
-"BgorBgEEAYLefAEHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNw+hm69Rxb5\n"\r
-"UpclERf5r85g1nwmMAoGCCqGSM49BAMCA0gAMEUCIQDbvNLA3ZkwEzuoH6XUR6JS\n"\r
-"UzZTVgsDgnJcOqtqOg0qEAIgUJR2g8XlMxqiuXP7JdwALdtnvCQTlJQbuD1gu+Jy\n"\r
-"AdQ=\n"\r
+static const char* g_caCertPem = "-----BEGIN CERTIFICATE-----\n"
+"MIIBfjCCASSgAwIBAgIJAPQXoGTceaW5MAoGCCqGSM49BAMCMBkxFzAVBgNVBAoM\n"
+"DklvVGl2aXR5VGVzdENBMB4XDTE3MDMxNTAwNTExOVoXDTMwMTEyMjAwNTExOVow\n"
+"GTEXMBUGA1UECgwOSW9UaXZpdHlUZXN0Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"
+"BwNCAARvYPdt+LjqASlHoc2zrjo3hHGjZsI31c+bg9AwINW5TuRZsE03w/Ejotza\n"
+"y4VDLImMlDhGP+K/f6OmKD3FNHhKo1UwUzAhBgNVHSUEGjAYBgorBgEEAYLefAEG\n"
+"BgorBgEEAYLefAEHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNw+hm69Rxb5\n"
+"UpclERf5r85g1nwmMAoGCCqGSM49BAMCA0gAMEUCIQDbvNLA3ZkwEzuoH6XUR6JS\n"
+"UzZTVgsDgnJcOqtqOg0qEAIgUJR2g8XlMxqiuXP7JdwALdtnvCQTlJQbuD1gu+Jy\n"
+"AdQ=\n"
 "-----END CERTIFICATE-----\n";
 
-static const char* g_caKeyPem = "-----BEGIN EC PRIVATE KEY-----\n"\r
-"MHcCAQEEILx9VOHDrMYuan6SXN4CQIHHXNq6SjzanaDFDgIaOaXloAoGCCqGSM49\n"\r
-"AwEHoUQDQgAEb2D3bfi46gEpR6HNs646N4Rxo2bCN9XPm4PQMCDVuU7kWbBNN8Px\n"\r
-"I6Lc2suFQyyJjJQ4Rj/iv3+jpig9xTR4Sg==\n"\r
+static const char* g_caKeyPem = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEILx9VOHDrMYuan6SXN4CQIHHXNq6SjzanaDFDgIaOaXloAoGCCqGSM49\n"
+"AwEHoUQDQgAEb2D3bfi46gEpR6HNs646N4Rxo2bCN9XPm4PQMCDVuU7kWbBNN8Px\n"
+"I6Lc2suFQyyJjJQ4Rj/iv3+jpig9xTR4Sg==\n"
 "-----END EC PRIVATE KEY-----\n";
 
 
-/* At a few places in this file, warning 4028 is incorrectly produced, disable it for the whole file. */\r
-#ifdef _MSC_VER\r
-#pragma warning( disable : 4028)\r
+/* 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)
 #endif
 
 // callback function(s) for provisioning client using C-level provisioning API
@@ -274,6 +284,22 @@ static void provisionAclCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, b
     g_doneCB = true;
 }
 
+static void assertRolesCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if (!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Asserting roles SUCCEEDED - ctx: %s", (char*)ctx);
+        g_successCB = true;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Asserting roles FAILED - ctx: %s", (char*)ctx);
+        printResultList((const OCProvisionResult_t*)arr, nOfRes);
+        g_successCB = false;
+    }
+    g_doneCB = true;
+}
+
 // function(s) for provisioning client using C-level provisioning API
 static int initProvisionClient(void)
 {
@@ -647,11 +673,13 @@ static int provisionCert(int dev_num, char* cert)
 }
 
 /*
- * Create an identity certificate for a device, based on the information in its CSR.
- * Assumes the csr has already been validated wtih OCVerifyCSRSignature.
+ * Create a role or identity certificate for a device, based on the information in its CSR.
+ * Assumes the CSR has already been validated wtih OCVerifyCSRSignature.
+ * If role is not NULL, a role certificate is created, otherwise an identity certificate
+ * is created.
  */
-static int createIdentityCertFromCSR(const char* caKeyPem, const char* caCertPem, char* csr,
-    char** deviceCert)
+static int createCertFromCSR(const char* caKeyPem, const char* caCertPem, char* csr,
+    const char* role, const char* authority, char** deviceCert)
 {
     char* publicKey = NULL;
     char* serial = NULL;
@@ -682,20 +710,37 @@ static int createIdentityCertFromCSR(const char* caKeyPem, const char* caCertPem
     }
 
     size_t deviceCertLen;
-    res = OCGenerateIdentityCertificate(
-        &uuid,
-        publicKey,
-        caCertPem,
-        caKeyPem,
-        serial,
-        TEST_CERT_NOT_BEFORE,
-        TEST_CERT_NOT_AFTER,
-        deviceCert,
-        &deviceCertLen);
-
+    if (role != NULL)
+    {
+        res = OCGenerateRoleCertificate(
+            &uuid,
+            publicKey,
+            caCertPem,
+            caKeyPem,
+            serial,
+            TEST_CERT_NOT_BEFORE,
+            TEST_CERT_NOT_AFTER,
+            role,
+            authority,
+            deviceCert,
+            &deviceCertLen);
+    }
+    else
+    {
+        res = OCGenerateIdentityCertificate(
+            &uuid,
+            publicKey,
+            caCertPem,
+            caKeyPem,
+            serial,
+            TEST_CERT_NOT_BEFORE,
+            TEST_CERT_NOT_AFTER,
+            deviceCert,
+            &deviceCertLen);
+    }
     if (res != OC_STACK_OK)
     {
-        OIC_LOG_V(ERROR, TAG, "OCGenerateIdentityCertificate failed, error: %d", res);
+        OIC_LOG_V(ERROR, TAG, "Failed generating certificate, error: %d", res);
         goto exit;
     }
 
@@ -712,7 +757,6 @@ static int setupOwnCert(OicUuid_t* inputUuid)
     uint16_t caCredId;
     char* serial = NULL;
     size_t serialLen = 0;
-    char* idPublicKey = NULL;
     size_t idPublicKeyLen = 0;
     char* idKey = NULL;
     size_t idKeyLen = 0;
@@ -721,7 +765,7 @@ static int setupOwnCert(OicUuid_t* inputUuid)
 
     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
 
-    /* Set our own trust anchor so that we trust certs we've issued. */\r
+    /* Set our own trust anchor so that we trust certs we've issued. */
     OCStackResult res = OCSaveTrustCertChain((const uint8_t*)g_caCertPem, strlen(g_caCertPem)+1, OIC_ENCODING_PEM, &caCredId);
     if (OC_STACK_OK != res)
     {
@@ -730,7 +774,7 @@ static int setupOwnCert(OicUuid_t* inputUuid)
     }
 
     /* Create identity certificate for use by the CA. */
-    res = OCGenerateKeyPair(&idPublicKey, &idPublicKeyLen, &idKey, &idKeyLen);
+    res = OCGenerateKeyPair(&g_idPublicKey, &idPublicKeyLen, &idKey, &idKeyLen);
     if (res != OC_STACK_OK)
     {
         OIC_LOG_V(ERROR, TAG, "OCGenerateKeyPair failed, error: %d", res);
@@ -763,7 +807,7 @@ static int setupOwnCert(OicUuid_t* inputUuid)
 
     res = OCGenerateIdentityCertificate(
         uuidForCert,
-        idPublicKey,
+        g_idPublicKey,
         g_caCertPem,
         g_caKeyPem,
         serial,
@@ -787,7 +831,6 @@ static int setupOwnCert(OicUuid_t* inputUuid)
 
 exit:
     OICFree(serial);
-    OICFree(idPublicKey);
     if (idKey != NULL)
     {
         OICClearMemory(idKey, idKeyLen);
@@ -800,8 +843,89 @@ exit:
     return (res == OC_STACK_OK) ? 0 : -1;
 }
 
-// Caller must call OCDeleteACLList(newAcl)
-static int createLedAcl(OicSecAcl_t** newAcl)
+static int setupOwnRoleCert(OicUuid_t* inputUuid, const char* role, const char* authority)
+{
+    OCUUIdentity deviceId = { 0 };
+    char* serial = NULL;
+    size_t serialLen = 0;
+    char* roleCert = NULL;
+    size_t roleCertLen = 0;
+
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    if (g_idPublicKey == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed because own public key is NULL, has setupOwnCert been called?", __func__);
+        return -1;
+    }
+
+    /* Create role certificate. */
+    OCStackResult res = OCGenerateRandomSerialNumber(&serial, &serialLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
+        goto exit;
+    }
+
+    OicUuid_t* uuidForCert = inputUuid;
+    OicUuid_t uuid = { 0 };
+    if (inputUuid == NULL)
+    {
+        res = OCGetDeviceId(&deviceId);
+        if (res != OC_STACK_OK)
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+            goto exit;
+        }
+        memcpy(uuid.id, deviceId.id, sizeof(uuid.id));
+        uuidForCert = &uuid;
+    }
+
+    OIC_LOG(DEBUG, TAG, "Creating own role cert with UUID:");
+    printUuid(uuidForCert);
+
+    res = OCGenerateRoleCertificate(
+        uuidForCert,
+        g_idPublicKey,
+        g_caCertPem,
+        g_caKeyPem,
+        serial,
+        TEST_CERT_NOT_BEFORE,
+        TEST_CERT_NOT_AFTER,
+        role,
+        authority,
+        &roleCert,
+        &roleCertLen);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create role cert, error: %d", res);
+        goto exit;
+    }
+
+    uint16_t roleCertCredId = 0;
+    res = OCSaveOwnRoleCert(roleCert, &roleCertCredId);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to save role cert, error: %d", res);
+        goto exit;
+    }
+
+exit:
+    OICFree(serial);
+    OICFree(roleCert);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+
+    return (res == OC_STACK_OK) ? 0 : -1;
+}
+
+/*
+ * Create an ACL for the /a/led resource.
+ * Caller must call OCDeleteACLList(newAcl).
+ * The role and authority parameters are optional.  If role is not NULL, a
+ * role-based ACL will be created. Otherwise a subject-based ACL is created.
+ */
+static int createLedAcl(OicSecAcl_t** newAcl, const char* role, const char* authority)
 {
     int ret = -1;
     OCUUIdentity ownUuid = { 0 };
@@ -828,20 +952,122 @@ static int createLedAcl(OicSecAcl_t** newAcl)
     }
     LL_APPEND(acl->aces, ace);
 
-    /* Set uuid to our own */
-    OCStackResult res = OCGetDeviceId(&ownUuid);
-    if (res != OC_STACK_OK)
+    if (role != NULL)    /* Create a role-based ACL */
+    {
+        ace->subjectType = OicSecAceRoleSubject;
+        assert(strlen(role) + 1 < ROLEID_LENGTH);
+        memcpy(ace->subjectRole.id, role, strlen(role) + 1);
+
+        if (authority != NULL)
+        {
+            assert(strlen(authority) + 1 < ROLEAUTHORITY_LENGTH);
+            memcpy(ace->subjectRole.authority, role, strlen(authority) + 1);
+        }
+        OIC_LOG_V(DEBUG, TAG, "Creating ACE with role id = %s, authority = %s:", ace->subjectRole.id, ace->subjectRole.authority);
+    }
+    else /* Create a subject based ACL */
+    {
+        /* Set uuid to our own */
+        OCStackResult res = OCGetDeviceId(&ownUuid);
+        if (res != OC_STACK_OK)
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+            goto exit;
+        }
+        ace->subjectType = OicSecAceUuidSubject;
+        memcpy(ace->subjectuuid.id, ownUuid.id, sizeof(ace->subjectuuid.id));
+
+        OicUuid_t uuid = { 0 };
+        memcpy(uuid.id, ownUuid.id, sizeof(uuid.id));
+        OIC_LOG(DEBUG, TAG, "Creating ACE with UUID:");
+        printUuid(&uuid);
+    }
+
+    /* Add a resource (e.g. '/a/led') to the ACE */
+    rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
+    if (!rsrc)
     {
-        OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc)", __func__);
         goto exit;
     }
+    LL_APPEND(ace->resources, rsrc);
+    rsrc->href = OICStrdup(resource);
+
+    /* Set resource type, e.g., 'core.led' */
+    rsrc->typeLen = 1;
+    rsrc->types = (char**)OICCalloc(rsrc->typeLen, sizeof(char*));
+    if (!rsrc->types)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc->types)", __func__);
+        goto exit;
+    }
+    rsrc->types[0] = OICStrdup(resource_type);
+
+    /* Set interface, e.g., 'oic.if.baseline' */
+    rsrc->interfaceLen = 1;
+    rsrc->interfaces = (char**)OICCalloc(rsrc->interfaceLen, sizeof(char*));
+    if (!rsrc->interfaces)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc->interfaces)", __func__);
+        goto exit;
+    }
+    rsrc->interfaces[0] = OICStrdup(resource_interface);
+
+    if (!rsrc->href || !rsrc->types[0] || !rsrc->interfaces[0])
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICStrdup failed", __func__);
+        goto exit;
+    }
+
+    /* Set permission for the ACE */
+    ace->permission = perms;
+
+    ret = 0; /* success */
+    *newAcl = acl;
+
+exit:
+
+    if (ret != 0)
+    {
+        *newAcl = NULL;
+        OCDeleteACLList(acl);
+    }
+
+    return ret;
+}
+
+/* Once IOT-1950 is resolved, this can be removed. */
+static int createRolesAcl(OicSecAcl_t** newAcl)
+{
+    int ret = -1;
+    OicSecAcl_t* acl = NULL;
+    OicSecAce_t* ace = NULL;
+    OicSecRsrc_t* rsrc = NULL;
+    const char* resource = "/oic/sec/roles";
+    const char* resource_type = "oic.sec.role";
+    const char* resource_interface = "oic.if.baseline";
+    uint16_t perms = PERMISSION_FULL_CONTROL;
+
+    /* Create an ACL with one ACE */
+    acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
+    if (!acl)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (acl)", __func__);
+        goto exit;
+    }
+    ace = (OicSecAce_t*)OICCalloc(1, sizeof(OicSecAce_t));
+    if (!ace)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (ace)", __func__);
+        goto exit;
+    }
+    LL_APPEND(acl->aces, ace);
+
+    /* Set uuid to "*", everyone */
     ace->subjectType = OicSecAceUuidSubject;
-    memcpy(ace->subjectuuid.id, ownUuid.id, sizeof(ace->subjectuuid.id));
+    memcpy(&ace->subjectuuid, &WILDCARD_SUBJECT_ID, WILDCARD_SUBJECT_ID_LEN);
 
-    OicUuid_t uuid = { 0 };
-    memcpy(uuid.id, ownUuid.id, sizeof(uuid.id));
-    OIC_LOG(DEBUG, TAG, "Creating ACE with UUID:");
-    printUuid(&uuid);
+    OIC_LOG(DEBUG, TAG, "Creating ACE with wildcard UUID");
 
     /* Add a resource (e.g. '/a/led') to the ACE */
     rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
@@ -931,7 +1157,9 @@ exit:
 }
 
 
-/* Fucntion to work around IOT-1927.  The ocrandom.h include is only required for the workaround. */
+/* Function to work around IOT-1927.  The ocrandom.h include is only required for the workaround.
+ * @todo: when IOT-1927 is resolved remove this function
+ */
 #include "ocrandom.h"
 int workAroundBug()
 {
@@ -980,7 +1208,7 @@ static int testCertUse(int dev_num)
         return -1;
     }
 
-    int ret = createIdentityCertFromCSR(g_caKeyPem, g_caCertPem, csr, &deviceCert);
+    int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &deviceCert);
     if (ret != 0)
     {
         OIC_LOG_V(ERROR, TAG, "Failed to create identity certificate", __func__);
@@ -1002,7 +1230,7 @@ static int testCertUse(int dev_num)
         goto exit;
     }
 
-    ret = createLedAcl(&acl);
+    ret = createLedAcl(&acl, NULL, NULL);
     if (ret != 0)
     {
         OIC_LOG_V(ERROR, TAG, "%s failed to create ACL", __func__);
@@ -1029,7 +1257,7 @@ static int testCertUse(int dev_num)
 
     /*
      * Work around bug IOT-1927
-     * When that bug is resolved, remove this call and the function workAroundBug
+     * @todo: When that bug is resolved, remove this call and the function workAroundBug
      */
     if (workAroundBug() != 0)
     {
@@ -1050,7 +1278,7 @@ static int testCertUse(int dev_num)
     ret = doGetRequest(uri, dev_num);
     if (ret == 0)
     {
-        OIC_LOG_V(ERROR, TAG, "%s Get request to %s suceeded, but should have failed", __func__, uri);
+        OIC_LOG_V(ERROR, TAG, "%s Get request to %s succeeded, but should have failed", __func__, uri);
         goto exit;
     }
 
@@ -1070,7 +1298,6 @@ static int testCertUse(int dev_num)
         goto exit;
     }
 
-
     /* Try a get request, expect success */
     ret = doGetRequest(uri, dev_num);
     if (ret != 0)
@@ -1088,8 +1315,265 @@ exit:
     return ret;
 }
 
+static int testRoleProvisioning(int dev_num)
+{
+    char* csr = NULL;
+    char* idCert = NULL;
+    char* roleCert = 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
+    }
+
+    /* Provision the device with the CA root, and issue it a role and identity cert. */
+    if (provisionTrustAnchor(dev_num) != 0)
+    {
+        return -1;
+    }
+
+    if (getCsr(dev_num, &csr) != 0)
+    {
+        return -1;
+    }
+
+    int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &idCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create identity certificate", __func__);
+        goto exit;
+    }
+
+    ret = provisionCert(dev_num, idCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to provision id certificate", __func__);
+        goto exit;
+    }
+
+    /* The first role cert will have no authority field (it's optional) */
+    ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, TEST_CERT_ROLE1, NULL, &roleCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create role certificate", __func__);
+        goto exit;
+    }
+
+    ret = provisionCert(dev_num, roleCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to provision role certificate", __func__);
+        goto exit;
+    }
+    OICFreeAndSetToNull(&roleCert);
+
+    /* The second will have the authority field set */
+    ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, TEST_CERT_ROLE2, TEST_CERT_AUTHORITY, &roleCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create role certificate", __func__);
+        goto exit;
+    }
+
+    ret = provisionCert(dev_num, roleCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to provision role certificate", __func__);
+        goto exit;
+    }
+
+exit:
+
+    OICFree(csr);
+    OICFree(idCert);
+    OICFree(roleCert);
+
+    return ret;
+}
+
+static int testRoleAssertionAndUse(int dev_num)
+{
+    char* csr = NULL;
+    char* idCert = NULL;
+    char* roleCert = NULL;
+    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
+    }
+
+    /* Provision the device with the CA root, and issue it an identity cert. */
+    if (provisionTrustAnchor(dev_num) != 0)
+    {
+        return -1;
+    }
+
+    if (getCsr(dev_num, &csr) != 0)
+    {
+        return -1;
+    }
+
+    int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &idCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to create identity certificate", __func__);
+        goto exit;
+    }
+
+    ret = provisionCert(dev_num, idCert);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to provision id certificate", __func__);
+        goto exit;
+    }
+
+    /* Create and provision a role-based ACL allowing ROLE1 to access '/a/led'. */
+    ret = createLedAcl(&acl, TEST_CERT_ROLE1, NULL);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s failed to create led ACL", __func__);
+        goto exit;
+    }
+
+    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;
+    }
+
+    /* Provision ourselves an identity and role cert.
+     * For the identity cert we use a random UUID, since the server has an ACE granting our UUID
+     * access to everything (as owner). We don't want to remove this ACE because it would lock
+     * us out. Using another UUID makes us appear as another device on the network.
+     */
+    OicUuid_t notOurUuid;
+    (void) OCGenerateUuid(notOurUuid.id);
+    ret = setupOwnCert(&notOurUuid);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
+        goto exit;
+    }
+
+    ret = setupOwnRoleCert(NULL, TEST_CERT_ROLE1, NULL);
+    if (ret != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __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;
+    }
+
+    /*
+    * Work around bug IOT-1927
+    * @todo: When that bug is resolved, remove this call and the function workAroundBug
+    */
+    if (workAroundBug() != 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s bug workaround failed: ", __func__);
+        ret = -1;
+        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 failure, we haven't asserted our role cert yet. */
+    ret = doGetRequest(uri, dev_num);
+    if (ret == 0)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Get request to %s succeeded, but should have failed", __func__, uri);
+        goto exit;
+    }
+
+    /* Assert our role cert.  (@todo: This should be done automatically, IOT-1952) */
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+    if (!dev)
+    {
+        OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+        return -1;
+    }
+
+    g_doneCB = false;
+    res = SRPAssertRoles(g_ctx, dev, &assertRolesCB);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s Failed assert roles", __func__);
+        ret = -1;
+        goto exit;
+    }
+    if (waitCallbackRet())
+    {
+        OIC_LOG(ERROR, TAG, "SRPAssertRoles callback error");
+        goto exit;
+    }
+    if (!g_successCB)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s callback completed, but failed", __func__);
+        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:
+    OICFree(csr);
+    OICFree(idCert);
+    OICFree(roleCert);
+    OCDeleteACLList(acl);
+
+    return ret;
+}
+
 /* Get a specific device from the provided device list. The devices in the list
- * are numbered starting from 1. */
+ * are numbered starting from 1.
+ */
 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
 {
     if (!dev_lst || 0 >= dev_num)
@@ -1289,7 +1773,7 @@ int TestTrustAnchorProvisioning()
 
     if(initDiscoverRegisterAllDevices())
     {
-        OIC_LOG_V(ERROR, TAG, "%s: Failed discover and provision devices", __func__);
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
         goto exit;
     }
 
@@ -1317,7 +1801,7 @@ int TestCSRResource()
 
     if(initDiscoverRegisterAllDevices())
     {
-        OIC_LOG_V(ERROR, TAG, "%s: Failed discover and provision devices", __func__);
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
         goto exit;
     }
 
@@ -1345,7 +1829,7 @@ int TestCertUse()
 
     if (initDiscoverRegisterAllDevices())
     {
-        OIC_LOG_V(ERROR, TAG, "%s: Failed discover and provision devices", __func__);
+        OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
         goto exit;
     }
 
@@ -1365,6 +1849,62 @@ exit:
     return ret;
 }
 
+int TestRoleProvisioning()
+{
+    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 (testRoleProvisioning(1))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to provision roles to device");
+        goto exit;
+    }
+
+    ret = 0;
+
+exit:
+
+    shutdownProvisionClient();
+
+    return ret;
+}
+
+int TestRoleAssertionAndUse()
+{
+    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 (testRoleAssertionAndUse(1))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to assert and use roles");
+        goto exit;
+    }
+
+    ret = 0;
+
+exit:
+
+    shutdownProvisionClient();
+
+    return ret;
+}
+
 // main function for provisioning client using C-level provisioning API
 int main(int argc, char** argv)
 {
@@ -1383,6 +1923,10 @@ int main(int argc, char** argv)
             return TestCSRResource();
         case 3:
             return TestCertUse();
+        case 4:
+            return TestRoleProvisioning();
+        case 5:
+            return TestRoleAssertionAndUse();
         default:
             printf("%s: Invalid test number\n", argv[0]);
             return 1;
index b935496..93d4282 100644 (file)
@@ -21,26 +21,29 @@ def cleanup(iotivity_base_path, exe_path):
     dat_file_src = os.path.join(iotivity_base_path, 'resource', 'csdk', 'security', 'provisioning', 'sample', 'oic_svr_db_server_justworks.dat' )
     dat_file_dest = exe_path
     shutil.copy(dat_file_src, dat_file_dest)
-\r
-    # Copy fresh oic_svr_db_client.dat \r
-    dat_file_src = os.path.join(iotivity_base_path, 'resource', 'examples', 'oic_svr_db_client.dat' )\r
-    dat_file_dest = exe_path\r
-    shutil.copy(dat_file_src, dat_file_dest)\r
-\r
-    #Delete provisioning DB file\r
-    db_file = os.path.join(exe_path, 'oic_autoprvn_mng.db')\r
-    if os.path.isfile(db_file):\r
-        os.unlink(db_file)\r
-\r
+
+    # Copy fresh oic_svr_db_client.dat
+    dat_file_src = os.path.join(iotivity_base_path, 'resource', 'examples', 'oic_svr_db_client.dat' )
+    dat_file_dest = exe_path
+    shutil.copy(dat_file_src, dat_file_dest)
+
+    #Delete provisioning DB file
+    db_file = os.path.join(exe_path, 'oic_autoprvn_mng.db')
+    if os.path.isfile(db_file):
+        os.unlink(db_file)
+
 # Print the environment variables (useful for debugging)
 def print_environment():
-    for key in os.environ.keys():\r
-        print "%30s %s \n" % (key,os.environ[key])\r
+    for key in os.environ.keys():
+        print "%30s %s \n" % (key,os.environ[key])
     print 'current PATH is %s' % sys.path
 
 
 ### main ###
 
+# Number of unit tests in autoprovisioningclient
+NUM_TESTS = 5
+
 usage = '''
  Run end-to-end certificate tests between autoprovisioningclient and sampleserver_justworks
  Usage Notes
@@ -58,14 +61,12 @@ parser = argparse.ArgumentParser(
     description=usage
 )
 
-parser.add_argument('--arch', nargs='?', choices = ['amd64', 'x86', 'arm'], help= 'Architecture, one of x86, amd64 or arm. Defaults to amd64', default='amd64')
-parser.add_argument('--build', nargs='?', choices = ['debug', 'release'], help= 'Build type, one of debug or release. Defaults to debug', default='debug')
+parser.add_argument('--arch', nargs='?', choices = ['amd64', 'x86', 'arm'], help= 'Architecture, one of x86, amd64 or arm. Defaults to amd64.', default='amd64')
+parser.add_argument('--build', nargs='?', choices = ['debug', 'release'], help= 'Build type, one of debug or release. Defaults to debug.', default='debug')
+parser.add_argument('--onetest', nargs='?', choices = ['1', '...', str(NUM_TESTS)], help= 'Run a single test, specified by number. By default all tests are run.')
 
 args = parser.parse_args()
 
-# Number of unit tests in autoprovisioningclient
-NUM_TESTS = 3
-
 iotivity_base_path = os.getcwd()
 os_name = platform.system()
 if os_name == 'Windows':
@@ -85,36 +86,45 @@ os.chdir(exe_path)
 
 output_text = ""
 num_failures = 0
-for i in range(1, NUM_TESTS + 1):\r
-    print '\nRunning test %d...\n' % i\r
-\r
-    # Clear state from previous test\r
-    cleanup(iotivity_base_path, exe_path)\r
-\r
-    # Start the device/server with a non-blocking call\r
-    #note: Popen can take file descriptors to redirect the processes stdin, stdout, stderr\r
-    try:\r
-        server_process = subprocess.Popen('sampleserver_justworks')\r
-    except:\r
-        print 'Failed to start sampleserver_justworks', sys.exc_info()[0]\r
-        sys.exit(-1)\r
-\r
-    # Run the auto provisioning client with the test number as argument, block until it returns\r
-    return_code = subprocess.call(["autoprovisioningclient", str(i)])\r
-\r
-    if return_code != 0:\r
-        num_failures += 1\r
-        print "Test %d failed" % i\r
-        output_text  += "Test %d failed\n" % i\r
-    else:\r
-        print "Test %d passed" % i\r
-\r
-\r
-    server_process.kill()\r
+
+test_range = range(1, NUM_TESTS + 1)    #default to running all tests
+if args.onetest:
+    try:
+        test_range = range(int(args.onetest), int(args.onetest) + 1)
+    except ValueError:
+        print 'invalid argument to --onetest'
+        sys.exit(-1)
+
+for i in test_range:
+    print '\nRunning test %d...\n' % i
+
+    # Clear state from previous test
+    cleanup(iotivity_base_path, exe_path)
+
+    # Start the device/server with a non-blocking call
+    #note: Popen can take file descriptors to redirect the processes stdin, stdout, stderr
+    try:
+        server_process = subprocess.Popen('sampleserver_justworks')
+    except:
+        print 'Failed to start sampleserver_justworks', sys.exc_info()[0]
+        sys.exit(-1)
+
+    # Run the auto provisioning client with the test number as argument, block until it returns
+    return_code = subprocess.call(["autoprovisioningclient", str(i)])
+
+    if return_code != 0:
+        num_failures += 1
+        print "Test %d failed" % i
+        output_text  += "Test %d failed\n" % i
+    else:
+        print "Test %d passed" % i
+
+
+    server_process.kill()
 
 
 print "\n------------------------------------"
-print " Test Results: %d of %d tests passed" % (NUM_TESTS - num_failures, NUM_TESTS)
+print " Test Results: %d of %d tests passed" % (len(test_range) - num_failures, len(test_range))
 print "------------------------------------"
 print output_text
 print '\n'
index 9dad739..3269355 100644 (file)
@@ -179,7 +179,7 @@ OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **
  * The function will return when security information for device with deviceID has been obtained or the
  * timeout has been exceeded.
  *
- * @param[in]  timeoutSeconds  Maximum time, in seconds, this function will listen for responses from 
+ * @param[in]  timeoutSeconds  Maximum time, in seconds, this function will listen for responses from
  *                             servers before returning.
  * @param[in]  deviceID        deviceID of target device.
  * @param[out] ppFoundDevice   OCProvisionDev_t of discovered device. Caller should use
@@ -187,7 +187,7 @@ OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **
  * @return OC_STACK_OK in case of success and other values otherwise.
  */
 OCStackResult OCDiscoverMultipleOwnerEnabledSingleDevice(unsigned short timeoutSeconds,
-                                                         const OicUuid_t* deviceID, 
+                                                         const OicUuid_t* deviceID,
                                                          OCProvisionDev_t **ppFoundDevice)
 {
     if ((NULL == ppFoundDevice) || (NULL != *ppFoundDevice) || (0 == timeoutSeconds) || (NULL == deviceID))
@@ -340,29 +340,49 @@ void OCDeleteDiscoveredDevices(OCProvisionDev_t *pList)
 }
 
 /**
- * this function sends ACL information to resource.
+ * This function sends ACL information to resource.
  *
  * @param[in] ctx Application context would be returned in result callback.
  * @param[in] selectedDeviceInfo Selected target device.
  * @param[in] acl ACL to provision.
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
             request recieves a response from resource server.
*            request receives a response from resource server.
  * @return  OC_STACK_OK in case of success and other value otherwise.
  */
 OCStackResult OCProvisionACL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
                              OCProvisionResultCB resultCallback)
 {
-    return SRPProvisionACL(ctx, selectedDeviceInfo, acl, OIC_SEC_ACL_V1, resultCallback);
+    /*
+     * Determine whether this is a version 1 or version 2 ACL. We can't just always use V2 here
+     * since we may be provisioning an IoTivity 1.2 device.
+     */
+
+    OicSecAclVersion_t aclVersion = OIC_SEC_ACL_V1; /* default to v1 */
+    if (acl->aces != NULL)
+    {
+        /* If any of the aces have the role subject, the ACL is v2 */
+        OicSecAce_t* ace = NULL;
+        LL_FOREACH(acl->aces, ace)
+        {
+            if (ace->subjectType == OicSecAceRoleSubject)
+            {
+                aclVersion = OIC_SEC_ACL_V2;
+                break;
+            }
+        }
+    }
+
+    return SRPProvisionACL(ctx, selectedDeviceInfo, acl, aclVersion, resultCallback);
 }
 
 /**
- * this function sends ACL information to resource.
+ * This function sends ACL information to resource.
  *
  * @param[in] ctx Application context would be returned in result callback.
  * @param[in] selectedDeviceInfo Selected target device.
  * @param[in] acl ACL to provision.
  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
             request recieves a response from resource server.
*            request recieves a response from resource server.
  * @return  OC_STACK_OK in case of success and other value otherwise.
  */
 OCStackResult OCProvisionACL2(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
@@ -412,7 +432,7 @@ OCStackResult OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDevice
     return SRPGetACLResource(ctx, selectedDeviceInfo, OIC_SEC_ACL_V1, resultCallback);
 }
 
-OCStackResult OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,\r
+OCStackResult OCGetACL2Resource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
                                OCProvisionResultCB resultCallback)
 {
     return SRPGetACLResource(ctx, selectedDeviceInfo, OIC_SEC_ACL_V2, resultCallback);
@@ -1504,6 +1524,26 @@ OCStackResult OCSaveOwnCertChain(const char* cert, const char* key, uint16_t *cr
 }
 
 /**
+ * Function to save own role certificate into Cred of SVR.
+ *
+ * @param[in] cert own role certificate to be saved in Cred of SVR.
+ * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
+ * @return  OC_STACK_OK in case of success and other value otherwise.
+ *
+ * @note The certificate public key must be the same as public key in the identity
+ *       certificate (installed by OCSaveOwnCertChain).
+ */
+OCStackResult OCSaveOwnRoleCert(const char* cert, uint16_t *credId)
+{
+    OicSecKey_t ownCert = { 0 };
+    ownCert.data = (uint8_t*)cert;
+    ownCert.len = strlen(cert) + 1;
+    ownCert.encoding = OIC_ENCODING_PEM;
+
+    return SRPSaveOwnRoleCert(&ownCert, credId);
+}
+
+/**
  * function to register notifier for Trustcertchain change.
  *
  * @param[in] ctx user context.
index 3ffcea4..1333cab 100644 (file)
@@ -49,6 +49,7 @@
 #include "utlist.h"
 #include "ocpayload.h"
 #include "srmutility.h"
+#include "certhelpers.h"
 
 #ifdef __WITH_DTLS__
 #include "crlresource.h"
@@ -115,6 +116,15 @@ struct GetRolesData {
     size_t numOfResults;                        /**< Number of results in result array.**/
 };
 
+typedef struct AssertRolesData AssertRolesData_t;
+struct AssertRolesData {
+    void *ctx;                                  /**< User-provided context **/
+    const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
+    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
+    OCProvisionResult_t *resArr;                /**< Result array.**/
+    size_t numOfResults;                        /**< Number of results in result array.**/
+};
+
 /**
  * Structure to carry PCONF provision API data to callback.
  */
@@ -322,7 +332,7 @@ static OCStackResult provisionCredentials(const OicSecCred_t *cred,
     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
     if (!secPayload)
     {
-        OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
@@ -460,7 +470,7 @@ static OCStackApplicationResult provisionCertCB(void *ctx, OCDoHandle UNUSED,
     return OC_STACK_DELETE_TRANSACTION;
 }
 
-static OCStackApplicationResult provisionIdentityCertCB(void *ctx, OCDoHandle UNUSED,
+static OCStackApplicationResult provisionCertificateCB(void *ctx, OCDoHandle UNUSED,
     OCClientResponse *clientResponse)
 {
     // Just call the callback provided to SRProvisionCredentials
@@ -514,7 +524,7 @@ OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint1
     if(!secPayload)
     {
         DeleteCredList(trustCertChainCred);
-        OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
@@ -664,8 +674,11 @@ static OCStackResult saveCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16
     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
     VERIFY_NOT_NULL_RETURN(TAG, cert, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, cert->data, ERROR,  OC_STACK_INVALID_PARAM);
-    VERIFY_NOT_NULL_RETURN(TAG, key, ERROR,  OC_STACK_INVALID_PARAM);
-    VERIFY_NOT_NULL_RETURN(TAG, key->data, ERROR,  OC_STACK_INVALID_PARAM);
+    if (key != NULL)
+    {
+        /* Key is optional. */
+        VERIFY_NOT_NULL_RETURN(TAG, key->data, ERROR, OC_STACK_INVALID_PARAM);
+    }
     VERIFY_NOT_NULL_RETURN(TAG, credId, ERROR,  OC_STACK_INVALID_PARAM);
     VERIFY_NOT_NULL_RETURN(TAG, usage, ERROR, OC_STACK_INVALID_PARAM);
 
@@ -679,7 +692,7 @@ static OCStackResult saveCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16
     res = GetDoxmDeviceID(&cred->subject);
     if (OC_STACK_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Cann't get the device id(GetDoxmDeviceID)");
+        OIC_LOG(ERROR, TAG, "Can't get the device id(GetDoxmDeviceID)");
         DeleteCredList(cred);
         return res;
     }
@@ -697,12 +710,15 @@ static OCStackResult saveCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16
     publicData->len = cert->len;
     publicData->encoding = cert->encoding;
 
-    OicSecKey_t *privateData = &cred->privateData;
-    privateData->data = (uint8_t *)OICCalloc(1, key->len);
-    VERIFY_NOT_NULL_RETURN(TAG, privateData->data, ERROR, OC_STACK_NO_MEMORY);
-    memcpy(privateData->data, key->data, key->len);
-    privateData->len = key->len;
-    privateData->encoding = key->encoding;
+    if (key != NULL)
+    {
+        OicSecKey_t *privateData = &cred->privateData;
+        privateData->data = (uint8_t *)OICCalloc(1, key->len);
+        VERIFY_NOT_NULL_RETURN(TAG, privateData->data, ERROR, OC_STACK_NO_MEMORY);
+        memcpy(privateData->data, key->data, key->len);
+        privateData->len = key->len;
+        privateData->encoding = key->encoding;
+    }
 
     res = AddCredential(cred);
     if(res != OC_STACK_OK)
@@ -722,6 +738,155 @@ OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_
     return saveCertChain(cert, key, credId, PRIMARY_CERT);
 }
 
+OCStackResult SRPSaveOwnRoleCert(OicSecKey_t * cert, uint16_t *credId)
+{
+    return saveCertChain(cert, NULL, credId, ROLE_CERT);
+}
+
+/**
+ * Callback handler of SRPAssertRoles.
+ *
+ * @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 SRPAssertRolesCB(void *ctx, OCDoHandle UNUSED,
+    OCClientResponse *clientResponse)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+    OC_UNUSED(UNUSED);
+    VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+    AssertRolesData_t *assertRolesData = (AssertRolesData_t*)ctx;
+    OCProvisionResultCB resultCallback = assertRolesData->resultCallback;
+    bool hasError = true;
+
+    if (clientResponse && (OC_STACK_RESOURCE_CHANGED == clientResponse->result))
+    {
+        hasError = false;
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "%s : NULL client response, or response indicating failure (%d)", __func__);
+    }
+
+    ((OCProvisionResultCB)(resultCallback))(assertRolesData->ctx, assertRolesData->numOfResults,
+        assertRolesData->resArr,
+        hasError);
+
+    OICFree(assertRolesData->resArr);
+    OICFree(assertRolesData);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackResult SRPAssertRoles(void *ctx, const OCProvisionDev_t *device, OCProvisionResultCB resultCallback)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    VERIFY_NOT_NULL_RETURN(TAG, device, ERROR, OC_STACK_INVALID_PARAM);
+    VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
+
+    OC_UNUSED(device);
+    OC_UNUSED(ctx);
+    OC_UNUSED(resultCallback);
+
+    /* 1. Retrieve all our stored role certificates */
+    RoleCertChain_t *roles = NULL;
+    OCStackResult res = GetAllRoleCerts(&roles);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to retrieve role certs");
+        return OC_STACK_ERROR;
+    }
+    if (roles == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Can't assert roles, no role certs installed");
+        return OC_STACK_ERROR;
+    }
+
+    /* 2. Encode them for transfer */
+    OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+    if (!secPayload)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
+        FreeRoleCertChainList(roles);
+        return OC_STACK_NO_MEMORY;
+    }
+    secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+    if(OC_STACK_OK != RolesToCBORPayload(roles, &secPayload->securityData, &secPayload->payloadSize))
+    {
+        OCPayloadDestroy((OCPayload *)secPayload);
+        OIC_LOG(ERROR, TAG, "RolesToCBORPayload failed");
+        FreeRoleCertChainList(roles);
+        return OC_STACK_NO_MEMORY;
+    }
+    OIC_LOG(DEBUG, TAG, "Created payload for asserting roles:");
+    OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+    FreeRoleCertChainList(roles);
+
+    /* 3. Post roles to the roles resource on the server */
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = { 0 };
+    if (!PMGenerateQuery(true,
+        device->endpoint.addr,
+        device->securePort,
+        device->connType,
+        query, sizeof(query), OIC_RSRC_ROLES_URI))
+    {
+        OCPayloadDestroy((OCPayload *)secPayload);
+        OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : 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 = &SRPAssertRolesCB;
+    AssertRolesData_t *assertRolesData = (AssertRolesData_t *)OICCalloc(1, sizeof(AssertRolesData_t));
+    if (assertRolesData == NULL)
+    {
+        OCPayloadDestroy((OCPayload *)secPayload);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    assertRolesData->deviceInfo = device;
+    assertRolesData->resultCallback = resultCallback;
+    assertRolesData->numOfResults = 0;
+    assertRolesData->ctx = ctx;
+
+    int noOfRiCalls = 1;
+    assertRolesData->resArr = (OCProvisionResult_t*)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
+    if (assertRolesData->resArr == NULL)
+    {
+        OICFree(assertRolesData);
+        OCPayloadDestroy((OCPayload *)secPayload);
+        OIC_LOG(ERROR, TAG, "Unable to allocate memory");
+        return OC_STACK_NO_MEMORY;
+    }
+    cbData.context = (void *)assertRolesData;
+    cbData.cd = NULL;
+    OCMethod method = OC_REST_POST;
+    OCDoHandle handle = NULL;
+
+    OIC_LOG(DEBUG, TAG, "Sending roles to server");
+    OCStackResult ret = OCDoRequest(&handle, method, query,
+        &device->endpoint, (OCPayload*)secPayload,
+        device->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    if (ret != OC_STACK_OK)
+    {
+        OICFree(assertRolesData->resArr);
+        OICFree(assertRolesData);
+        OIC_LOG_V(ERROR, TAG, "%s OCDoRequest failed", __func__);
+    }
+    OCPayloadDestroy((OCPayload *)secPayload);
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    VERIFY_SUCCESS_RETURN(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
+
+    return ret;
+}
+
 #endif // __WITH_DTLS__ || __WITH_TLS__
 
 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
@@ -855,11 +1020,19 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
             VERIFY_NOT_NULL_RETURN(TAG, cred, ERROR, OC_STACK_ERROR);
 
             cred->publicData.encoding = OIC_ENCODING_PEM;
-            cred->credUsage = OICStrdup(PRIMARY_CERT);
 
-            /* Create credential data (used by the response handler provisionIdentityCertCB and freed there) */
-            CredentialData_t *credData = (CredentialData_t *)OICCalloc(1, sizeof(CredentialData_t)); 
-            if (NULL == credData)
+            if (OCInternalIsValidRoleCertificate(deviceCert.data, deviceCert.len, NULL, NULL) == OC_STACK_OK)
+            {
+                cred->credUsage = OICStrdup(ROLE_CERT);
+            }
+            else
+            {
+                cred->credUsage = OICStrdup(PRIMARY_CERT);
+            }
+
+            /* Create credential data (used by the response handler provisionCertificateCB and freed there) */
+            CredentialData_t *credData = (CredentialData_t *)OICCalloc(1, sizeof(CredentialData_t));
+            if ((NULL == credData) || (NULL == cred->credUsage))
             {
                 DeleteCredList(cred);
                 OIC_LOG(ERROR, TAG, "Memory allocation problem");
@@ -874,8 +1047,8 @@ OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t k
             credData->resultCallback = resultCallback;
             credData->resArr = NULL;
 
-            /* Note: the callback of type OCClientResponseHandler, thin wrapper that calls resultCallback */
-            OCStackResult res = provisionCredentials(cred, pDev1, credData, &provisionIdentityCertCB); 
+            /* Note: the callback is of type OCClientResponseHandler, thin wrapper that calls resultCallback */
+            OCStackResult res = provisionCredentials(cred, pDev1, credData, &provisionCertificateCB);
             if (res != OC_STACK_OK)
             {
                 OICFree(credData);
@@ -990,7 +1163,7 @@ OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceI
     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
     if(!secPayload)
     {
-        OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
@@ -1146,7 +1319,7 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
     if(!secPayload)
     {
-        OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "Failed to allocate memory");
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
@@ -2074,7 +2247,7 @@ OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDi
     removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
     if (!removeData)
     {
-        OIC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to allocate memory");
         res = OC_STACK_NO_MEMORY;
         goto error;
     }
@@ -2091,7 +2264,7 @@ OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDi
         (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
     if (!removeData->removeRes)
     {
-        OIC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to allocate memory");
         res = OC_STACK_NO_MEMORY;
         goto error;
     }
@@ -2216,7 +2389,7 @@ OCStackResult SRPRemoveDeviceWithoutDiscovery(void* ctx, const OCProvisionDev_t*
     removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
     if (!removeData)
     {
-        OIC_LOG(ERROR, TAG, "SRPRemoveDeviceWithoutDiscovery : Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "SRPRemoveDeviceWithoutDiscovery : Failed to allocate memory");
         res = OC_STACK_NO_MEMORY;
         goto error;
     }
@@ -2233,7 +2406,7 @@ OCStackResult SRPRemoveDeviceWithoutDiscovery(void* ctx, const OCProvisionDev_t*
         (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
     if (!removeData->removeRes)
     {
-        OIC_LOG(ERROR, TAG, "SRPRemoveDeviceWithoutDiscovery : Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "SRPRemoveDeviceWithoutDiscovery : Failed to allocate memory");
         res = OC_STACK_NO_MEMORY;
         goto error;
     }
@@ -2362,7 +2535,7 @@ OCStackResult SRPSyncDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDisc
     removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
     if (!removeData)
     {
-        OIC_LOG(ERROR, TAG, "SRPSyncDevice : Failed to memory allocation");
+        OIC_LOG(ERROR, TAG, "SRPSyncDevice : Failed to allocate memory");
         res = OC_STACK_NO_MEMORY;
         goto error;
     }
@@ -3006,7 +3179,7 @@ static void registerResultForGetRolesResourceCB(GetRolesData_t *getRolesData,
                     /* Take ownership of the buffers from certificate and optData, rather than copy. */
                     currentEntry->chains[i].certificate = curr->certificate;
                     currentEntry->chains[i].optData = curr->optData;
-                    
+
                     curr->certificate.data = NULL;
                     curr->certificate.len = 0;
                     curr->optData.data = NULL;
index 019e445..c448bfb 100644 (file)
@@ -1877,7 +1877,18 @@ static bool IsSameACE(OicSecAce_t* ace1, OicSecAce_t* ace2)
 {
     if(ace1 && ace2)
     {
-        if(memcmp(ace1->subjectuuid.id, ace2->subjectuuid.id, sizeof(ace1->subjectuuid.id)) != 0)
+        if(ace1->subjectType != ace2->subjectType)
+        {
+            return false;
+        }
+        if(ace1->subjectType == OicSecAceUuidSubject &&
+            memcmp(ace1->subjectuuid.id, ace2->subjectuuid.id, sizeof(ace1->subjectuuid.id)) != 0)
+        {
+            return false;
+        }
+        else if(ace1->subjectType == OicSecAceRoleSubject &&
+            strcmp(ace1->subjectRole.id, ace2->subjectRole.id) != 0 &&
+            strcmp(ace1->subjectRole.authority, ace2->subjectRole.authority) != 0)
         {
             return false;
         }
@@ -1919,10 +1930,22 @@ static void printACE(const OicSecAce_t *ace)
     OIC_LOG_V(INFO, TAG, "ACE @ %p", ace);
     OIC_LOG_V(INFO, TAG, "    permission = %#x", (uint32_t)ace->permission);
 
-    // Log the subjectuuid.
-    char uuidString[UUID_STRING_SIZE];
-    bool convertedUUID = OCConvertUuidToString(ace->subjectuuid.id, uuidString);
-    OIC_LOG_V(INFO, TAG, "    subjectuuid = %s", convertedUUID ? uuidString : "incorrect format");
+    // Log the subject
+    if (ace->subjectType == OicSecAceUuidSubject)
+    {
+        char uuidString[UUID_STRING_SIZE];
+        bool convertedUUID = OCConvertUuidToString(ace->subjectuuid.id, uuidString);
+        OIC_LOG_V(INFO, TAG, "    subject UUID = %s", convertedUUID ? uuidString : "incorrect format");
+    }
+    else if (ace->subjectType == OicSecAceRoleSubject)
+    {
+        OIC_LOG_V(DEBUG, TAG, "    role id = %s", ace->subjectRole.id);
+        OIC_LOG_V(DEBUG, TAG, "    authority = %s", ace->subjectRole.authority);
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "    subject = (subject of unknown type)");
+    }
 
     // Log all resources this ACE applies to.
     OicSecRsrc_t *resource = NULL;
@@ -2249,6 +2272,11 @@ static OCEntityHandlerResult HandleACLPostRequest(const OCEntityHandlerRequest *
             }
         }
     }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "ACL post request with no payload.");
+        ehRet = OC_EH_ERROR;
+    }
 
     //Send response to request originator
     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
@@ -2725,7 +2753,7 @@ const OicSecAce_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAce_t **
     // Find the next ACL corresponding to the 'subjectID' and return it.
     LL_FOREACH(begin, ace)
     {
-        if ((OicSecAceUuidSubject == ace->subjectType) && 
+        if ((OicSecAceUuidSubject == ace->subjectType) &&
             (0 == memcmp(&(ace->subjectuuid), subjectId, sizeof(OicUuid_t))))
         {
             OIC_LOG(DEBUG, TAG, "GetACLResourceData: found matching ACE:");
index 12ab4bf..28011b7 100644 (file)
@@ -321,8 +321,8 @@ OCStackResult OCInternalIsValidRoleCertificate(const uint8_t *buf, size_t bufLen
 
     valid = false;
     /* Check for at least one subjAltName with a role in it. */
-    for (const mbedtls_x509_general_names *nameCur = &parsedCert.subject_alt_names; 
-            NULL != nameCur; 
+    for (const mbedtls_x509_general_names *nameCur = &parsedCert.subject_alt_names;
+            NULL != nameCur;
             nameCur = nameCur->next)
     {
         if (MBEDTLS_X509_GENERALNAME_DIRECTORYNAME == nameCur->general_name.name_type)
@@ -444,7 +444,8 @@ OCStackResult OCInternalIsValidCertChain(const uint8_t *buf, size_t bufLen)
 
 static const mbedtls_x509_crt_profile s_certProfile = {
     MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),            /* MD algorithms */
-    MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY),             /* Allowed key type */
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY) |            /* Allowed key types */
+    MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA),
     MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1),     /* EC curves */
     0                                                   /* RSA minimum key length - not used because we only use EC key pairs */
 };
@@ -489,7 +490,7 @@ OCStackResult OCInternalVerifyRoleCertificate(const OicSecKey_t *certificate, co
         goto exit;
     }
 
-    if (NULL != optData)
+    if ((NULL != optData) && (0 != optData->len))
     {
         mbedRet = mbedtls_x509_crt_parse(&certChain, optData->data, optData->len);
         if (0 > mbedRet)
@@ -541,20 +542,22 @@ OCStackResult OCInternalVerifyRoleCertificate(const OicSecKey_t *certificate, co
                      dirName = dirName->next)
                 {
                     if ((MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN) == dirName->oid.len) &&
-                        (0 == memcmp(MBEDTLS_OID_AT_CN, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN))))
+                        (0 == memcmp(MBEDTLS_OID_AT_CN, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN))) &&
+                        (rolesTmp[rolesTmpCount].id[0] == '\0'))
                     {
                         /* When checking validity above, we made sure the role ID and authority were not too
                          * long to fit in an OicSecRole_t. Here we only assert, but don't check again in release code.
-                         * id was also initialized as all zeroes, so string will automatically be null-terminated.
+                         * id was also initialized as all zeroes, so the string will automatically be null-terminated.
                          */
-                        assert(dirName->val.len < ROLEID_LENGTH); 
+                        assert(dirName->val.len < ROLEID_LENGTH);
                         memcpy(rolesTmp[rolesTmpCount].id, dirName->val.p, dirName->val.len);
                         advanceCount = true;
                     }
                     else if ((MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT) == dirName->oid.len) &&
-                             (0 == memcmp(MBEDTLS_OID_AT_ORG_UNIT, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT))))
+                             (0 == memcmp(MBEDTLS_OID_AT_ORG_UNIT, dirName->oid.p, MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_ORG_UNIT)))&&
+                             (rolesTmp[rolesTmpCount].authority[0] == '\0'))
                     {
-                        assert(dirName->val.len < ROLEID_LENGTH); 
+                        assert(dirName->val.len < ROLEID_LENGTH);
                         memcpy(rolesTmp[rolesTmpCount].authority, dirName->val.p, dirName->val.len);
                     }
 
index af2cdc7..3b665b9 100644 (file)
@@ -324,7 +324,7 @@ size_t GetCredKeyDataSize(const OicSecCred_t* cred)
 #endif
         }
     }
-    OIC_LOG_V(DEBUG, TAG, "Cred Key Data Size : %zd\n", size);
+    OIC_LOG_V(DEBUG, TAG, "Cred Key Data Size : %u", (unsigned int) size);
     return size;
 }
 
@@ -614,7 +614,7 @@ static void logCredMetadata()
         OIC_LOG_V(DEBUG, TAG, "privateData length: %d, encoding: %d", temp->privateData.len, temp->privateData.encoding);
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
-        OIC_LOG_V(DEBUG, TAG, "publicData length: %d, encoding: %d", temp->publicData.len, temp->publicData.encoding);           
+        OIC_LOG_V(DEBUG, TAG, "publicData length: %d, encoding: %d", temp->publicData.len, temp->publicData.encoding);
         if (temp->credUsage)
         {
             OIC_LOG_V(DEBUG, TAG, "credUsage: %s", temp->credUsage);
@@ -694,7 +694,7 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
         }
 #endif //MULTIPLE_OWNER
 
-        if ((SIGNED_ASYMMETRIC_KEY == cred->credType || ASYMMETRIC_KEY == cred->credType) 
+        if ((SIGNED_ASYMMETRIC_KEY == cred->credType || ASYMMETRIC_KEY == cred->credType)
             && cred->publicData.data)
         {
             mapSize++;
@@ -753,7 +753,7 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
         //PublicData -- Not Mandatory
-        if ((SIGNED_ASYMMETRIC_KEY == cred->credType || ASYMMETRIC_KEY == cred->credType) 
+        if ((SIGNED_ASYMMETRIC_KEY == cred->credType || ASYMMETRIC_KEY == cred->credType)
             && cred->publicData.data)
         {
             cborEncoderResult = SerializeEncodingToCbor(&credMap,
@@ -2853,7 +2853,7 @@ OCStackResult GetCredRownerId(OicUuid_t *rowneruuid)
 /* Caller must call OICFree on *der when finished. */
 static int ConvertPemCertToDer(const char *pem, size_t pemLen, uint8_t** der, size_t* derLen)
 {
-    const char* pemHeader = "-----BEGIN CERTIFICATE-----"; /* no newlines allowed here */\r
+    const char* pemHeader = "-----BEGIN CERTIFICATE-----"; /* no newlines allowed here */
     const char* pemFooter = "-----END CERTIFICATE-----";
 
     mbedtls_pem_context ctx;
@@ -2892,7 +2892,7 @@ exit:
 /* Caller must call OICFree on *pem when finished. */
 static int ConvertDerCertToPem(const uint8_t* der, size_t derLen, uint8_t** pem)
 {
-    const char* pemHeader = "-----BEGIN CERTIFICATE-----\n";\r
+    const char* pemHeader = "-----BEGIN CERTIFICATE-----\n";
     const char* pemFooter = "-----END CERTIFICATE-----\n";
 
     /* Get the length required for output */
@@ -2918,7 +2918,7 @@ static int ConvertDerCertToPem(const uint8_t* der, size_t derLen, uint8_t** pem)
     }
 
     /* Try the conversion */
-    ret = mbedtls_pem_write_buffer(pemHeader, 
+    ret = mbedtls_pem_write_buffer(pemHeader,
         pemFooter,
         der,
         derLen,
@@ -2943,7 +2943,7 @@ static OCStackResult GetCaCert(ByteArray_t * crt, const char * usage, OicEncodin
         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
         return OC_STACK_INVALID_PARAM;
     }
-    
+
     switch (desiredEncoding)
     {
     case OIC_ENCODING_PEM:
@@ -3064,6 +3064,116 @@ OCStackResult GetPemCaCert(ByteArray_t * crt, const char * usage)
     return GetCaCert(crt, usage, OIC_ENCODING_PEM);
 }
 
+static int cloneSecKey(OicSecKey_t * dst, OicSecKey_t * src)
+{
+    if ((src == NULL) || (dst == NULL))
+    {
+        return -1;
+    }
+
+    if (src->len > 0)
+    {
+        dst->data = OICCalloc(src->len, 1);
+        if (dst->data == NULL)
+        {
+            OIC_LOG_V(ERROR, TAG, "%s memory allocation failed", __func__);
+            return -1;
+        }
+        memcpy(dst->data, src->data, src->len);
+    }
+    else
+    {
+        dst->data = NULL;
+    }
+
+    dst->len = src->len;
+    dst->encoding = src->encoding;
+
+    return 0;
+}
+
+static int cloneSecOpt(OicSecOpt_t * dst, OicSecOpt_t * src)
+{
+    if ((src == NULL) || (dst == NULL))
+    {
+        return -1;
+    }
+
+    if (src->len > 0)
+    {
+        dst->data = OICCalloc(src->len, 1);
+        if (dst == NULL)
+        {
+            OIC_LOG_V(ERROR, TAG, "%s memory allocation failed", __func__);
+            OICFree(dst);
+            return -1;
+        }
+        memcpy(dst->data, src->data, src->len);
+    }
+    else
+    {
+        dst->data = NULL;
+    }
+
+    dst->len = src->len;
+    dst->encoding = src->encoding;
+    dst->revstat = src->revstat;
+
+    return 0;
+}
+
+/* Caller must call FreeRoleCertChainList on roleEntries when finished. */
+OCStackResult GetAllRoleCerts(RoleCertChain_t ** output)
+{
+    OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+
+    *output = NULL;
+
+    OicSecCred_t * temp = NULL;
+    LL_FOREACH(gCred, temp)
+    {
+        if ((SIGNED_ASYMMETRIC_KEY == temp->credType) &&
+            (temp->credUsage != NULL) &&
+            (0 == strcmp(temp->credUsage, ROLE_CERT)))
+        {
+            if (temp->publicData.data == NULL)
+            {
+                OIC_LOG_V(WARNING, TAG, "%s missing certificate data in role certificate", __func__);
+                continue;
+            }
+
+            RoleCertChain_t * add = (RoleCertChain_t *) OICCalloc(1, sizeof(RoleCertChain_t));
+            if (add == NULL)
+            {
+                OIC_LOG_V(ERROR, TAG, "%s Failed to allocate memory", __func__);
+                goto error;
+            }
+            LL_APPEND(*output, add);
+            add->credId = temp->credId;
+            if (cloneSecKey(&add->certificate, &temp->publicData) != 0)
+            {
+                OIC_LOG_V(ERROR, TAG, "%s failed to copy certificate data", __func__);
+                goto error;
+            }
+
+            if (cloneSecOpt(&add->optData, &temp->optionalData) != 0)
+            {
+                OIC_LOG_V(ERROR, TAG, "%s failed to copy optional data", __func__);
+                goto error;
+            }
+        }
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_OK;
+
+error:
+    FreeRoleCertChainList(*output);
+    *output = NULL;
+    OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+    return OC_STACK_ERROR;
+}
+
 void GetPemOwnCert(ByteArray_t * crt, const char * usage)
 {
     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
@@ -3101,7 +3211,7 @@ void GetPemOwnCert(ByteArray_t * crt, const char * usage)
                 mustAddNull = false; /* mbedTLS always NULL-terminates. */
                 pemLen = strlen((char *)pem) + 1;
                 break;
-                
+
             case OIC_ENCODING_PEM:
             case OIC_ENCODING_BASE64:
                 pem = temp->publicData.data;
@@ -3139,7 +3249,7 @@ void GetPemOwnCert(ByteArray_t * crt, const char * usage)
             /* If we're appending, subtract one from crt->len below so we overwrite the current terminating
              * NULL with the beginning of the new data.
              */
-            if (0 < crt->len) 
+            if (0 < crt->len)
             {
                 assert(crt->data[crt->len - 1] == '\0');
                 memcpy(crt->data + crt->len - 1, pem, pemLen);
@@ -3188,7 +3298,7 @@ void GetDerKey(ByteArray_t * key, const char * usage)
     key->len = 0;
     LL_FOREACH(gCred, temp)
     {
-        if ((SIGNED_ASYMMETRIC_KEY == temp->credType || ASYMMETRIC_KEY == temp->credType) && 
+        if ((SIGNED_ASYMMETRIC_KEY == temp->credType || ASYMMETRIC_KEY == temp->credType) &&
             temp->privateData.len > 0 &&
             NULL != temp->credUsage &&
             0 == strcmp(temp->credUsage, usage))
@@ -3197,7 +3307,7 @@ void GetDerKey(ByteArray_t * key, const char * usage)
             if (temp->privateData.encoding == OIC_ENCODING_PEM)
             {
                 /* Convert PEM to DER */
-                const char* pemHeader = "-----BEGIN EC PRIVATE KEY-----"; /* no newlines allowed here */\r
+                const char* pemHeader = "-----BEGIN EC PRIVATE KEY-----"; /* no newlines allowed here */
                 const char* pemFooter = "-----END EC PRIVATE KEY-----";
 
                 if (temp->privateData.data[temp->privateData.len - 1] != 0)
index 8e959c3..8f44f11 100644 (file)
@@ -468,10 +468,11 @@ static void ProcessAccessRequest(SRMRequestContext_t *context)
             OCStackResult res = GetEndpointRoles(context->endPoint, &roles, &roleCount);
             if (OC_STACK_OK != res)
             {
-                OIC_LOG_V(ERROR, TAG, "Could not locate any roles for endpoint: %d", res);
+                OIC_LOG_V(ERROR, TAG, "Error getting asserted roles for endpoint: %d", res);
             }
             else
             {
+                OIC_LOG_V(DEBUG, TAG, "Found %u asserted roles for endpoint", (unsigned int) roleCount);
                 do
                 {
                     currentAce = GetACLResourceDataByRoles(roles, roleCount, &aceSavePtr);
index 97a872f..32c461e 100644 (file)
@@ -67,9 +67,9 @@ static OCResourceHandle gRolesHandle        = NULL;
 static RolesEntry_t     *gRoles             = 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. 
+ * The value of payload size is increased until reaching max cbor size.
  */
 static const uint16_t CBOR_SIZE = 2048;
 
@@ -93,7 +93,7 @@ static void InvalidateRoleCache(RolesEntry_t *entry)
 
 /* Caller must call OICFree on publicKey when finished. */
 static OCStackResult GetPeerPublicKeyFromEndpoint(const CAEndpoint_t *endpoint,
-                                                  uint8_t **publicKey, 
+                                                  uint8_t **publicKey,
                                                   size_t *publicKeyLength)
 {
     CASecureEndpoint_t sep;
@@ -168,7 +168,6 @@ static void FreeRolesEntry(RolesEntry_t *rolesEntry)
     }
 
     FreeRoleCertChainList(rolesEntry->chains);
-    OICFree(rolesEntry->chains);
     OICFree(rolesEntry->publicKey);
     OICFree(rolesEntry->cachedRoles);
     OICFree(rolesEntry);
@@ -282,7 +281,7 @@ static OCStackResult AddRoleCertificate(const RoleCertChain_t *roleCert, const u
     else
     {
         /* We haven't seen this public key before and need a new entry. */
-        targetEntry = (RolesEntry_t *)OICCalloc(1, sizeof(RolesEntry_t *));
+        targetEntry = (RolesEntry_t *)OICCalloc(1, sizeof(RolesEntry_t));
         if (NULL == targetEntry)
         {
             OIC_LOG(ERROR, TAG, "No memory for new targetEntry");
@@ -303,7 +302,7 @@ static OCStackResult AddRoleCertificate(const RoleCertChain_t *roleCert, const u
         LL_PREPEND(gRoles, targetEntry);
     }
 
-    // @todo: Detect duplicates and don't add them again
+    // @todo: (IOT-1949) Detect duplicates and don't add them again
     res = DuplicateRoleCertChain(roleCert, &copy);
     if (OC_STACK_OK != res)
     {
@@ -313,7 +312,6 @@ static OCStackResult AddRoleCertificate(const RoleCertChain_t *roleCert, const u
 
     // Assign our own credId.
     copy->credId = gIdCounter++;
-
     LL_APPEND(targetEntry->chains, copy);
 
     res = OC_STACK_OK;
@@ -325,12 +323,12 @@ exit:
         FreeRoleCertChain(copy);
     }
 
-    OIC_LOG_V(DEBUG, TAG, "AddRoleCertificate IN: %d", res);
+    OIC_LOG_V(DEBUG, TAG, "AddRoleCertificate Out: %d", res);
 
     return res;
 }
 
-static OCStackResult RolesToCBORPayload(const RoleCertChain_t *roles, uint8_t **cborPayload,
+OCStackResult RolesToCBORPayload(const RoleCertChain_t *roles, uint8_t **cborPayload,
                                         size_t *cborSize)
 {
     OCStackResult ret = OC_STACK_OK;
@@ -400,7 +398,7 @@ static OCStackResult RolesToCBORPayload(const RoleCertChain_t *roles, uint8_t **
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding subject tag");
         cborEncoderResult = cbor_encode_text_string(&roleMap, EMPTY_UUID, sizeof(EMPTY_UUID) - 1);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding subject value");
-        
+
         // publicData - mandatory
         cborEncoderResult = SerializeEncodingToCbor(&roleMap, OIC_JSON_PUBLICDATA_NAME, &currChain->certificate);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding publicData");
@@ -489,7 +487,7 @@ exit:
     return ret;
 }
 
-/* Caller must call DeleteRoleCredentials on roleEntries when finished. */
+/* Caller must call FreeRoleCertChainList on roleEntries when finished. */
 OCStackResult CBORPayloadToRoles(const uint8_t *cborPayload, size_t size, RoleCertChain_t **roleEntries)
 {
     if (NULL == cborPayload || 0 == size || NULL == roleEntries)
@@ -727,7 +725,7 @@ static OCEntityHandlerResult HandleGetRequest(OCEntityHandlerRequest *ehRequest)
     ehRet = (OC_STACK_OK == res) ? OC_EH_OK : OC_EH_ERROR;
 
 exit:
-    
+
     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
 
     OICFree(payload);
@@ -755,7 +753,7 @@ static OCEntityHandlerResult HandlePostRequest(OCEntityHandlerRequest *ehRequest
     if (OC_STACK_OK != res)
     {
         OIC_LOG_V(ERROR, TAG, "Could not get peer's public key: %d", res);
-        ehRet = OC_EH_ERROR; 
+        ehRet = OC_EH_ERROR;
         goto exit;
     }
 
@@ -829,7 +827,7 @@ static OCEntityHandlerResult HandleDeleteRequest(OCEntityHandlerRequest *ehReque
     {
         return ehRet;
     }
-    
+
     // Parsing REST query to get the credId
     ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
     while (GetNextQuery(&parseIter))
@@ -884,7 +882,7 @@ static OCEntityHandlerResult HandleDeleteRequest(OCEntityHandlerRequest *ehReque
     RoleCertChain_t *curr2 = NULL;
     LL_FOREACH_SAFE(entry->chains, curr1, curr2)
     {
-        // credId of zero means all creds; we never assign zero as a credId.
+        // credId of zero means delete all creds; we never assign zero as a credId.
         if ((0 == credId) || (curr1->credId == credId))
         {
             LL_DELETE(entry->chains, curr1);
@@ -972,7 +970,7 @@ OCStackResult DeInitRolesResource()
     gRolesHandle = NULL;
 
     FreeRolesList(gRoles);
-    
+
     gRoles = NULL;
 
     return res;
@@ -1133,7 +1131,7 @@ OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **role
         return res;
     }
 
-    for (const RoleCertChain_t *chain = targetEntry->chains; NULL != chain; chain = chain->next)
+    for (RoleCertChain_t *chain = targetEntry->chains; NULL != chain; chain = chain->next)
     {
         OicSecRole_t *currCertRoles = NULL;
         size_t currCertRolesCount = 0;
@@ -1148,7 +1146,9 @@ OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **role
         if (OC_STACK_OK != res)
         {
             OIC_LOG_V(ERROR, TAG, "Failed to verify a role certificate: %d", res);
-            /* Don't exit; try all certificates presented. */
+            /* Remove the invalid cert chain, but don't exit; try all certificates presented. */
+            LL_DELETE(targetEntry->chains, chain);
+            FreeRoleCertChain(chain);
         }
         else
         {
@@ -1166,14 +1166,14 @@ OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **role
                 OICFree(publicKey);
                 return OC_STACK_NO_MEMORY;
             }
-            memcpy(rolesToReturn + (rolesToReturnCount * sizeof(rolesToReturn[0])), 
-                currCertRoles, 
+            memcpy(rolesToReturn + (rolesToReturnCount * sizeof(rolesToReturn[0])),
+                currCertRoles,
                 currCertRolesCount * sizeof(currCertRoles[0]));
             rolesToReturnCount += currCertRolesCount;
             OICFree(currCertRoles);
         }
 
-        /* 
+        /*
          * Set the cacheValidUntil value to be the earliest notValidUntil date amongst
          * all the certificates.
          *
index a4424a2..d50d716 100644 (file)
@@ -483,6 +483,7 @@ bool SRMIsSecurityResourceURI(const char* uri)
         OIC_RSRC_CRED_URI,
         OIC_RSRC_CSR_URI,
         OIC_RSRC_ACL_URI,
+        OIC_RSRC_ACL2_URI,
         OIC_RSRC_DOXM_URI,
         OIC_RSRC_PSTAT_URI,
         OIC_RSRC_PCONF_URI,
@@ -551,6 +552,15 @@ OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
         }
     }
 
+    svrLen = strlen(OIC_RSRC_ACL2_URI);
+    if (uriLen == svrLen)
+    {
+        if (0 == strncmp(uri, OIC_RSRC_ACL2_URI, svrLen))
+        {
+            return OIC_R_ACL2_TYPE;
+        }
+    }
+
     svrLen = strlen(OIC_RSRC_AMACL_URI);
     if (uriLen == svrLen)
     {
index 8a07321..4b89eab 100644 (file)
@@ -175,6 +175,7 @@ const char * OIC_JSON_EMPTY_STRING = "";
 // Certificates provided by Cloud
 const char * TRUST_CA = "oic.sec.cred.trustca";
 const char * PRIMARY_CERT = "oic.sec.cred.cert";
+const char * ROLE_CERT = "oic.sec.cred.rolecert";
 
 // Certificates provided by manufacturer
 const char * MF_TRUST_CA = "oic.sec.cred.mfgtrustca";
index 8bdfdea..a1badd4 100644 (file)
@@ -59,11 +59,16 @@ OCResetSVRDB
 OCSaveTrustCertChain
 OCSaveOwnCertChain
 OCSelectOwnershipTransferMethod
+OCSaveOwnRoleCert
 OCSetOwnerTransferCallbackData
 OCSetOxmAllowStatus
 OCUnlinkDevices
 OCVerifyCSRSignature
 
+; @todo: Remove or revise SRPAssertRoles once IOT-1952 is resolved. It should
+; not be here in the release
+SRPAssertRoles
+
 SetClosePinDisplayCB
 SetDisplayPinWithContextCB
 UnsetDisplayPinWithContextCB