From: Chul Lee Date: Mon, 14 Nov 2016 04:49:36 +0000 (+0900) Subject: Manufacturer certificate based ownership transfer support. X-Git-Tag: 1.3.0~1052^2~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e904ff29687c0f8be109afe46ea117a361a4c68a;p=platform%2Fupstream%2Fiotivity.git Manufacturer certificate based ownership transfer support. 1. Add manufacturer certificate OxM callbacks : resource/csdk/security/provisioning/src/oxmmanufacturercert.c : resource/csdk/security/provisioning/include/oxm/oxmmanufacturercert.h 2. Apply the manufacturer cert based OxM on the client & server. : resource/csdk/security/provisioning/src/ownershiptransfermanager.c : resource/csdk/security/src/doxmresource.c 3. Add manufacturer certificate supported sample server : resource/csdk/security/provisioning/sample/sampleserver_mfg.cpp 4. Add API to set the allowed/not-allowed OxM which is OCSetOxmAllowStatus() : resource/csdk/security/provisioning/src/ocprovisioningmanager.c : resource/csdk/security/provisioning/include/ocprovisioningmanager.h 5. Add OCStackResult code to handle not allowed OxM exception. : resource/csdk/stack/include/octypes.h : resource/src/OCException.cpp : resource/include/StringConstants.h : resource/unittests/OCExceptionTest.cpp 6. Update the SConscript according to above modifications. : resource/csdk/security/provisioning/SConscript : resource/csdk/security/provisioning/sample/SConscript Change-Id: Ibb4b4eec33a1e39234f808e32cc3b96aff4879ad Signed-off-by: Chul Lee Reviewed-on: https://gerrit.iotivity.org/gerrit/14275 Tested-by: jenkins-iotivity Reviewed-by: Randeep Singh (cherry picked from commit 7b7e5a97b1acdf4a265915bd4eaf745dd8262b03) Reviewed-on: https://gerrit.iotivity.org/gerrit/14503 --- diff --git a/resource/csdk/octbstack_product_secured.def b/resource/csdk/octbstack_product_secured.def index fd7c85b..c11c83e 100644 --- a/resource/csdk/octbstack_product_secured.def +++ b/resource/csdk/octbstack_product_secured.def @@ -32,6 +32,7 @@ OCRemoveDeviceWithUuid OCResetDevice OCSetOwnerTransferCallbackData OCUnlinkDevices +OCSetOxmAllowStatus SetGeneratePinCB SetInputPinCB diff --git a/resource/csdk/security/provisioning/SConscript b/resource/csdk/security/provisioning/SConscript index 78a62eb..ceb3154 100644 --- a/resource/csdk/security/provisioning/SConscript +++ b/resource/csdk/security/provisioning/SConscript @@ -104,6 +104,7 @@ provisioning_src = [ 'src/ocprovisioningmanager.c', 'src/oxmjustworks.c', 'src/oxmrandompin.c', + 'src/oxmmanufacturercert.c', 'src/provisioningdatabasemanager.c' ] if provisioning_env.get('MULTIPLE_OWNER') == '1': diff --git a/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h b/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h index f302bd6..2df0540 100644 --- a/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h +++ b/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h @@ -47,6 +47,17 @@ typedef struct OTMContext OTMContext_t; OCStackResult OTMDoOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDeviceList, OCProvisionResultCB resultCB); +/** + * 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 OTMSetOxmAllowStatus(const OicSecOxm_t oxm, const bool allowStatus); + + /* *Callback for load secret for temporal secure session * diff --git a/resource/csdk/security/provisioning/include/ocprovisioningmanager.h b/resource/csdk/security/provisioning/include/ocprovisioningmanager.h index 22f5734..7a4f289 100644 --- a/resource/csdk/security/provisioning/include/ocprovisioningmanager.h +++ b/resource/csdk/security/provisioning/include/ocprovisioningmanager.h @@ -81,6 +81,16 @@ 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 _ENABLE_MULTIPLE_OWNER_ /** * API to perfrom multiple ownership transfer for MOT enabled device. diff --git a/resource/csdk/security/provisioning/include/oxm/oxmmanufacturercert.h b/resource/csdk/security/provisioning/include/oxm/oxmmanufacturercert.h new file mode 100644 index 0000000..0a9bca7 --- /dev/null +++ b/resource/csdk/security/provisioning/include/oxm/oxmmanufacturercert.h @@ -0,0 +1,81 @@ +//****************************************************************** +// +// Copyright 2016 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 _OXM_MANUFACTURER_CERTIFICATE_H_ +#define _OXM_MANUFACTURER_CERTIFICATE_H_ + +#include "ocstack.h" +#include "securevirtualresourcetypes.h" +#include "ownershiptransfermanager.h" +#include "pmtypes.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Callback implementation to prepare manufacturer certificate based OT. + * + * @param otmCtx Context of OTM, It includes current device information. + * + * @return ::OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult PrepareMCertificateCallback(OTMContext_t *otmCtx); + +/** + * Callback implementation to establish a secure channel with RSA cipher suite. + * + * @param otmCtx Context of OTM, It includes current device information. + * + * @return ::OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult CreateSecureSessionMCertificateCallback(OTMContext_t *otmCtx); + +/** + * Generate payload for select OxM request. + * + * @param otmCtx Context of OTM, It includes current device information. + * @param cborPayload is the DOXM CBOR payload including the selected OxM. + * @note Returned memory should be deallocated by caller. + * @param cborSize is the size of the cborPayload. + * + * @return ::OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult CreateMCertificateBasedSelectOxmPayload(OTMContext_t *otmCtx, uint8_t **cborPayload, + size_t *cborSize); + +/** + * Generate payload for owner transfer request. + * + * @param otmCtx Context of OTM, It includes current device information. + * @param cborPaylaod is the DOXM CBOR payload including the owner information. + * @note Returned memory should be deallocated by caller. + * @param cborSize is the size of the cborPayload. + * + * @return ::OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult CreateMCertificateBasedOwnerTransferPayload(OTMContext_t *otmCtx, uint8_t **cborPayload, + size_t *cborSize); + +#ifdef __cplusplus +} +#endif +#endif //_OXM_MANUFACTURER_CERTIFICATE_H_ + diff --git a/resource/csdk/security/provisioning/sample/SConscript b/resource/csdk/security/provisioning/sample/SConscript index 99814dd..1ec4546 100644 --- a/resource/csdk/security/provisioning/sample/SConscript +++ b/resource/csdk/security/provisioning/sample/SConscript @@ -103,6 +103,7 @@ if target_os in ['linux', 'tizen']: provisioningclient = provisioning_env.Program('provisioningclient', 'provisioningclient.c') sampleserver_justworks = provisioning_env.Program('sampleserver_justworks', 'sampleserver_justworks.cpp') sampleserver_randompin = provisioning_env.Program('sampleserver_randompin', 'sampleserver_randompin.cpp') +sampleserver_mfg = provisioning_env.Program('sampleserver_mfg', 'sampleserver_mfg.cpp') if provisioning_env.get('MULTIPLE_OWNER') == '1': subownerclient = provisioning_env.Program('subownerclient', 'subownerclient.c') @@ -127,6 +128,8 @@ justworksdat = provisioning_env.Install(sec_provisioning_build_dir, sec_provisioning_src_dir + 'oic_svr_db_server_justworks.dat') randompindat = provisioning_env.Install(sec_provisioning_build_dir, sec_provisioning_src_dir+ 'oic_svr_db_server_randompin.dat') +mfgdat = provisioning_env.Install(sec_provisioning_build_dir, + sec_provisioning_src_dir+ 'oic_svr_db_server_mfg.dat') randompin_with_emptyuuid_dat = provisioning_env.Install(sec_provisioning_build_dir, sec_provisioning_src_dir+ 'oic_svr_db_randompin_with_empty_deviceid.dat') @@ -145,16 +148,16 @@ if provisioning_env.get('WITH_TCP') == True: if provisioning_env.get('MULTIPLE_OWNER') == '1': Alias("samples", [ provisioningclient, subownerclient, - sampleserver_justworks, sampleserver_randompin, + sampleserver_justworks, sampleserver_randompin, sampleserver_mfg, clientdat, subownerclientdat, - justworksdat, randompindat, randompin_with_emptyuuid_dat + justworksdat, randompindat, mfgdat, randompin_with_emptyuuid_dat ]) else: Alias("samples", [ provisioningclient, - sampleserver_justworks, sampleserver_randompin, + sampleserver_justworks, sampleserver_randompin, sampleserver_mfg, clientdat, - justworksdat, randompindat, randompin_with_emptyuuid_dat + justworksdat, randompindat, mfgdat, randompin_with_emptyuuid_dat ]) provisioning_env.AppendTarget('samples') diff --git a/resource/csdk/security/provisioning/sample/provisioningclient.c b/resource/csdk/security/provisioning/sample/provisioningclient.c index 45dc3f5..6b90720 100644 --- a/resource/csdk/security/provisioning/sample/provisioningclient.c +++ b/resource/csdk/security/provisioning/sample/provisioningclient.c @@ -2099,6 +2099,12 @@ int main() goto PMCLT_ERROR; } + // Client can choose a allowed/not-allowed OxM method. + if(OC_STACK_OK != OCSetOxmAllowStatus(OIC_DECENTRALIZED_PUBLIC_KEY, false)) + { + OIC_LOG(WARNING, TAG, "Failed to disable OIC_DECENTRALIZED_PUBLIC_KEY OxM"); + } + #ifdef _ENABLE_MULTIPLE_OWNER_ SetPreconfigPin("12341234", 8); #endif //_ENABLE_MULTIPLE_OWNER_ diff --git a/resource/csdk/security/provisioning/sample/sampleserver_mfg.cpp b/resource/csdk/security/provisioning/sample/sampleserver_mfg.cpp new file mode 100644 index 0000000..c347a42 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/sampleserver_mfg.cpp @@ -0,0 +1,480 @@ +/****************************************************************** +* +* Copyright 2016 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. +* +******************************************************************/ +/////////////////////////////////////////////////////////////////////// +//NOTE : This sample server is generated based on ocserverbasicops.cpp +/////////////////////////////////////////////////////////////////////// +#include "iotivity_config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_PTHREAD_H +#include +#endif +#include +#include "ocstack.h" +#include "ocpayload.h" + +#ifdef HAVE_WINDOWS_H +#include +/** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */ +#ifdef ERROR +#undef ERROR +#endif //ERROR +#endif //HAVE_WINDOWS_H +#include "platform_features.h" +#include "logger.h" + + +#define TAG "SAMPLE_MANUFACTURER_CERT" + +int gQuitFlag = 0; + +/* Structure to represent a LED resource */ +typedef struct LEDRESOURCE{ + OCResourceHandle handle; + bool state; + int power; +} LEDResource; + +static LEDResource LED; +// This variable determines instance number of the LED resource. +// Used by POST method to create a new instance of LED resource. +static int gCurrLedInstance = 0; +#define SAMPLE_MAX_NUM_POST_INSTANCE 2 +static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE]; + +char *gResourceUri= (char *)"/a/led"; + +//Secure Virtual Resource database for Iotivity Server +//It contains Server's Identity and the manufacturer certificate +static char CRED_FILE[] = "oic_svr_db_server_mfg.dat"; + +/* Function that creates a new LED resource by calling the + * OCCreateResource() method. + */ +int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower); + +/* This method converts the payload to JSON format */ +OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest); + +/* Following methods process the PUT, GET, POST + * requests + */ +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload); +OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload); +OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResponse *response, + OCRepPayload **payload); + +/* Entity Handler callback functions */ +OCEntityHandlerResult +OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* callbackParam); + +const char *getResult(OCStackResult result) { + switch (result) { + case OC_STACK_OK: + return "OC_STACK_OK"; + case OC_STACK_RESOURCE_CREATED: + return "OC_STACK_RESOURCE_CREATED"; + case OC_STACK_RESOURCE_DELETED: + return "OC_STACK_RESOURCE_DELETED"; + case OC_STACK_INVALID_URI: + return "OC_STACK_INVALID_URI"; + case OC_STACK_INVALID_QUERY: + return "OC_STACK_INVALID_QUERY"; + case OC_STACK_INVALID_IP: + return "OC_STACK_INVALID_IP"; + case OC_STACK_INVALID_PORT: + return "OC_STACK_INVALID_PORT"; + case OC_STACK_INVALID_CALLBACK: + return "OC_STACK_INVALID_CALLBACK"; + case OC_STACK_INVALID_METHOD: + return "OC_STACK_INVALID_METHOD"; + case OC_STACK_NO_MEMORY: + return "OC_STACK_NO_MEMORY"; + case OC_STACK_COMM_ERROR: + return "OC_STACK_COMM_ERROR"; + case OC_STACK_INVALID_PARAM: + return "OC_STACK_INVALID_PARAM"; + case OC_STACK_NOTIMPL: + return "OC_STACK_NOTIMPL"; + case OC_STACK_NO_RESOURCE: + return "OC_STACK_NO_RESOURCE"; + case OC_STACK_RESOURCE_ERROR: + return "OC_STACK_RESOURCE_ERROR"; + case OC_STACK_SLOW_RESOURCE: + return "OC_STACK_SLOW_RESOURCE"; + case OC_STACK_NO_OBSERVERS: + return "OC_STACK_NO_OBSERVERS"; + #ifdef WITH_PRESENCE + case OC_STACK_PRESENCE_STOPPED: + return "OC_STACK_PRESENCE_STOPPED"; + #endif + case OC_STACK_ERROR: + return "OC_STACK_ERROR"; + default: + return "UNKNOWN"; + } +} + +OCRepPayload* getPayload(const char* uri, int64_t power, bool state) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if(!payload) + { + OIC_LOG(ERROR, TAG, "Failed to allocate Payload"); + return NULL; + } + + OCRepPayloadSetUri(payload, uri); + OCRepPayloadSetPropBool(payload, "state", state); + OCRepPayloadSetPropInt(payload, "power", power); + + return payload; +} + +//This function takes the request as an input and returns the response +OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest) +{ + if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION) + { + OIC_LOG(ERROR, TAG, "Incoming payload not a representation"); + return NULL; + } + + OCRepPayload* input = (OCRepPayload*)(ehRequest->payload); + + LEDResource *currLEDResource = &LED; + + if (ehRequest->resource == gLedInstance[0].handle) + { + currLEDResource = &gLedInstance[0]; + gResourceUri = (char *) "/a/led/0"; + } + else if (ehRequest->resource == gLedInstance[1].handle) + { + currLEDResource = &gLedInstance[1]; + gResourceUri = (char *) "/a/led/1"; + } + + if(OC_REST_PUT == ehRequest->method) + { + // Get pointer to query + int64_t pow; + if(OCRepPayloadGetPropInt(input, "power", &pow)) + { + currLEDResource->power =pow; + } + + bool state; + if(OCRepPayloadGetPropBool(input, "state", &state)) + { + currLEDResource->state = state; + } + } + + return getPayload(gResourceUri, currLEDResource->power, currLEDResource->state); +} + +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult; + + OCRepPayload *getResp = constructResponse(ehRequest); + + if(getResp) + { + *payload = getResp; + ehResult = OC_EH_OK; + } + else + { + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult; + + OCRepPayload *putResp = constructResponse(ehRequest); + + if(putResp) + { + *payload = putResp; + ehResult = OC_EH_OK; + } + else + { + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResponse *response, OCRepPayload **payload) +{ + OCRepPayload *respPLPost_led = NULL; + OCEntityHandlerResult ehResult = OC_EH_OK; + + /* + * The entity handler determines how to process a POST request. + * Per the REST paradigm, POST can also be used to update representation of existing + * resource or create a new resource. + * In the sample below, if the POST is for /a/led then a new instance of the LED + * resource is created with default representation (if representation is included in + * POST payload it can be used as initial values) as long as the instance is + * lesser than max new instance count. Once max instance count is reached, POST on + * /a/led updated the representation of /a/led (just like PUT) + */ + + if (ehRequest->resource == LED.handle) + { + if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE) + { + // Create new LED instance + char newLedUri[15] = "/a/led/"; + int newLedUriLength = strlen(newLedUri); + snprintf (newLedUri + newLedUriLength, sizeof(newLedUri)-newLedUriLength, "%d", gCurrLedInstance); + + respPLPost_led = OCRepPayloadCreate(); + OCRepPayloadSetUri(respPLPost_led, gResourceUri); + OCRepPayloadSetPropString(respPLPost_led, "createduri", newLedUri); + + if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0)) + { + OIC_LOG (INFO, TAG, "Created new LED instance"); + gLedInstance[gCurrLedInstance].state = 0; + gLedInstance[gCurrLedInstance].power = 0; + gCurrLedInstance++; + strncpy ((char *)response->resourceUri, newLedUri, MAX_URI_LENGTH); + ehResult = OC_EH_RESOURCE_CREATED; + } + } + else + { + respPLPost_led = constructResponse(ehRequest); + } + } + else + { + for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++) + { + if (ehRequest->resource == gLedInstance[i].handle) + { + if (i == 0) + { + respPLPost_led = constructResponse(ehRequest); + break; + } + else if (i == 1) + { + respPLPost_led = constructResponse(ehRequest); + } + } + } + } + + if (respPLPost_led != NULL) + { + *payload = respPLPost_led; + ehResult = OC_EH_OK; + } + else + { + OIC_LOG_V (INFO, TAG, "Payload was NULL"); + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult +OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* callbackParam) +{ + OIC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag); + (void)callbackParam; + OCEntityHandlerResult ehResult = OC_EH_ERROR; + + OCEntityHandlerResponse response; + memset(&response, 0, sizeof(response)); + + // Validate pointer + if (!entityHandlerRequest) + { + OIC_LOG (ERROR, TAG, "Invalid request pointer"); + return OC_EH_ERROR; + } + + OCRepPayload* payload = NULL; + + if (flag & OC_REQUEST_FLAG) + { + OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG"); + if (entityHandlerRequest) + { + if (OC_REST_GET == entityHandlerRequest->method) + { + OIC_LOG (INFO, TAG, "Received OC_REST_GET from client"); + ehResult = ProcessGetRequest (entityHandlerRequest, &payload); + } + else if (OC_REST_PUT == entityHandlerRequest->method) + { + OIC_LOG (INFO, TAG, "Received OC_REST_PUT from client"); + ehResult = ProcessPutRequest (entityHandlerRequest, &payload); + } + else if (OC_REST_POST == entityHandlerRequest->method) + { + OIC_LOG (INFO, TAG, "Received OC_REST_POST from client"); + ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload); + } + else + { + OIC_LOG_V (INFO, TAG, "Received unsupported method %d from client", + entityHandlerRequest->method); + ehResult = OC_EH_ERROR; + } + + if (ehResult == OC_EH_OK && ehResult != OC_EH_FORBIDDEN) + { + // Format the response. Note this requires some info about the request + response.requestHandle = entityHandlerRequest->requestHandle; + response.resourceHandle = entityHandlerRequest->resource; + response.ehResult = ehResult; + response.payload = (OCPayload*)(payload); + response.numSendVendorSpecificHeaderOptions = 0; + memset(response.sendVendorSpecificHeaderOptions, 0, + sizeof(response.sendVendorSpecificHeaderOptions)); + memset(response.resourceUri, 0, sizeof(response.resourceUri)); + // Indicate that response is NOT in a persistent buffer + response.persistentBufferFlag = 0; + + // Send the response + if (OCDoResponse(&response) != OC_STACK_OK) + { + OIC_LOG(ERROR, TAG, "Error sending response"); + ehResult = OC_EH_ERROR; + } + } + } + } + + OCPayloadDestroy(response.payload); + return ehResult; +} + +/* SIGINT handler: set gQuitFlag to 1 for graceful termination */ +void handleSigInt(int signum) +{ + if (signum == SIGINT) + { + gQuitFlag = 1; + } +} + +FILE* server_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + +int main() +{ + struct timespec timeout; + + OIC_LOG(DEBUG, TAG, "OCServer is starting..."); + + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink}; + + OCRegisterPersistentStorageHandler(&ps); + + if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK) + { + OIC_LOG(ERROR, TAG, "OCStack init error"); + return 0; + } + + /* + * Declare and create the example resource: LED + */ + createLEDResource(gResourceUri, &LED, false, 0); + + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000L; + + // Break from loop with Ctrl-C + OIC_LOG(INFO, TAG, "Entering ocserver main loop..."); + signal(SIGINT, handleSigInt); + while (!gQuitFlag) + { + if (OCProcess() != OC_STACK_OK) + { + OIC_LOG(ERROR, TAG, "OCStack process error"); + return 0; + } + nanosleep(&timeout, NULL); + } + + OIC_LOG(INFO, TAG, "Exiting ocserver main loop..."); + + if (OCStop() != OC_STACK_OK) + { + OIC_LOG(ERROR, TAG, "OCStack process error"); + } + + return 0; +} + +int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower) +{ + if (!uri) + { + OIC_LOG(ERROR, TAG, "Resource URI cannot be NULL"); + return -1; + } + + ledResource->state = resourceState; + ledResource->power= resourcePower; + OCStackResult res = OCCreateResource(&(ledResource->handle), + "core.led", + OC_RSRVD_INTERFACE_DEFAULT, + uri, + OCEntityHandlerCb, + NULL, + OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE); + OIC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res)); + + return 0; +} diff --git a/resource/csdk/security/provisioning/src/ocprovisioningmanager.c b/resource/csdk/security/provisioning/src/ocprovisioningmanager.c index e06e954..b538ace 100644 --- a/resource/csdk/security/provisioning/src/ocprovisioningmanager.c +++ b/resource/csdk/security/provisioning/src/ocprovisioningmanager.c @@ -227,6 +227,19 @@ OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* return OTMSetOwnershipTransferCallbackData(oxm, callbackData); } +/** + * 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) +{ + return OTMSetOxmAllowStatus(oxm, allowStatus); +} + OCStackResult OCDoOwnershipTransfer(void* ctx, OCProvisionDev_t *targetDevices, OCProvisionResultCB resultCallback) diff --git a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c index 1bf238f..499ac30 100644 --- a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c +++ b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c @@ -60,8 +60,9 @@ #include "ownershiptransfermanager.h" #include "securevirtualresourcetypes.h" #include "oxmjustworks.h" -#ifdef _ENABLE_MULTIPLE_OWNER_ #include "oxmrandompin.h" +#include "oxmmanufacturercert.h" +#ifdef _ENABLE_MULTIPLE_OWNER_ #include "oxmpreconfpin.h" #endif //_ENABLE_MULTIPLE_OWNER_ #include "otmcontextlist.h" @@ -69,12 +70,22 @@ #include "pmutility.h" #include "srmutility.h" #include "provisioningdatabasemanager.h" -#include "oxmrandompin.h" #include "ocpayload.h" #include "payload_logging.h" +#include "pkix_interface.h" #define TAG "OIC_OTM" + +#define ALLOWED_OXM 1 +#define NOT_ALLOWED_OXM 0 + +/** + * List of allowed oxm list. + * All oxm methods are allowed as default. + */ +static uint8_t g_OxmAllowStatus[OIC_OXM_COUNT] = {ALLOWED_OXM, ALLOWED_OXM, ALLOWED_OXM, NOT_ALLOWED_OXM}; + /** * Variables for pointing the OTMContext to be used in the DTLS handshake result callback. */ @@ -108,8 +119,11 @@ OCStackResult OTMSetOTCallback(OicSecOxm_t oxm, OTMCallbackData_t* callbacks) callbacks->createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload; break; case OIC_MANUFACTURER_CERTIFICATE: - OIC_LOG(ERROR, TAG, "OIC_MANUFACTURER_CERTIFICATE not supported yet."); - return OC_STACK_INVALID_METHOD; + callbacks->loadSecretCB = PrepareMCertificateCallback; + callbacks->createSecureSessionCB = CreateSecureSessionMCertificateCallback; + callbacks->createSelectOxmPayloadCB = CreateMCertificateBasedSelectOxmPayload; + callbacks->createOwnerTransferPayloadCB = CreateMCertificateBasedOwnerTransferPayload; + break; case OIC_DECENTRALIZED_PUBLIC_KEY: OIC_LOG(ERROR, TAG, "OIC_DECENTRALIZED_PUBLIC_KEY not supported yet."); return OC_STACK_INVALID_METHOD; @@ -144,6 +158,8 @@ exit: static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethods, size_t numberOfMethods, OicSecOxm_t *selectedMethod) { + bool isOxmSelected = false; + OIC_LOG(DEBUG, TAG, "IN SelectProvisioningMethod"); if(numberOfMethods == 0 || !supportedMethods) @@ -152,10 +168,25 @@ static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethod return OC_STACK_ERROR; } - *selectedMethod = supportedMethods[0]; for(size_t i = 0; i < numberOfMethods; i++) { - if(*selectedMethod < supportedMethods[i]) + if(ALLOWED_OXM == g_OxmAllowStatus[supportedMethods[i]]) + { + *selectedMethod = supportedMethods[i]; + isOxmSelected = true; + break; + } + } + if(!isOxmSelected) + { + OIC_LOG(ERROR, TAG, "Can not find the allowed OxM."); + return OC_STACK_NOT_ALLOWED_OXM; + } + + for(size_t i = 0; i < numberOfMethods; i++) + { + if(*selectedMethod < supportedMethods[i] && + ALLOWED_OXM == g_OxmAllowStatus[supportedMethods[i]]) { *selectedMethod = supportedMethods[i]; } @@ -320,6 +351,18 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res) OicUuid_t emptyUuid = { .id={0}}; SetUuidForPinBasedOxm(&emptyUuid); } + else if(OIC_MANUFACTURER_CERTIFICATE == otmCtx->selectedDeviceInfo->doxm->oxmSel) + { + //Revert back certificate related callbacks. + if(CA_STATUS_OK != CAregisterPkixInfoHandler(GetPkixInfo)) + { + OIC_LOG(WARNING, TAG, "Failed to revert PkixInfoHandler."); + } + if(CA_STATUS_OK != CAregisterGetCredentialTypesHandler(InitCipherSuiteList)) + { + OIC_LOG(WARNING, TAG, "Failed to revert CredentialTypesHandler."); + } + } for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++) { @@ -799,7 +842,6 @@ static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle if (OC_STACK_RESOURCE_CHANGED == clientResponse->result) { OCStackResult res = OC_STACK_ERROR; - OicSecOxm_t selOxm = otmCtx->selectedDeviceInfo->doxm->oxmSel; //DTLS Handshake //Load secret for temporal secure session. @@ -1399,7 +1441,6 @@ static OCStackResult PostOwnerTransferModeToResource(OTMContext_t* otmCtx) } OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; - OicSecOxm_t selectedOxm = deviceInfo->doxm->oxmSel; char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0}; if(!PMGenerateQuery(false, @@ -1865,6 +1906,23 @@ error: return res; } +OCStackResult OTMSetOxmAllowStatus(const OicSecOxm_t oxm, const bool allowStatus) +{ + OIC_LOG_V(INFO, TAG, "IN %s : oxm=%d, allow status=%s", + __func__, oxm, (allowStatus ? "true" : "false")); + + if(OIC_OXM_COUNT <= oxm) + { + return OC_STACK_INVALID_PARAM; + } + + g_OxmAllowStatus[oxm] = (allowStatus ? ALLOWED_OXM : NOT_ALLOWED_OXM); + + OIC_LOG_V(INFO, TAG, "OUT %s", __func__); + + return OC_STACK_OK; +} + OCStackResult PostProvisioningStatus(OTMContext_t* otmCtx) { OIC_LOG(INFO, TAG, "IN PostProvisioningStatus"); diff --git a/resource/csdk/security/provisioning/src/oxmmanufacturercert.c b/resource/csdk/security/provisioning/src/oxmmanufacturercert.c new file mode 100644 index 0000000..4ba1e86 --- /dev/null +++ b/resource/csdk/security/provisioning/src/oxmmanufacturercert.c @@ -0,0 +1,143 @@ +/* ***************************************************************** + * + * Copyright 2016 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. + * + * *****************************************************************/ + +#include + +#include "ocstack.h" +#include "securevirtualresourcetypes.h" +#include "doxmresource.h" +#include "credresource.h" +#include "cacommon.h" +#include "cainterface.h" +#include "casecurityinterface.h" +#include "ocrandom.h" +#include "oic_malloc.h" +#include "logger.h" +#include "pbkdf2.h" +#include "global.h" +#include "base64.h" +#include "oxmmanufacturercert.h" +#include "ownershiptransfermanager.h" +#include "srmresourcestrings.h" +#include "pkix_interface.h" +#include "mbedtls/ssl_ciphersuites.h" + +#define TAG "OXM_MCertificate" + +OCStackResult CreateMCertificateBasedSelectOxmPayload(OTMContext_t* otmCtx, uint8_t **payload, size_t *size) +{ + if (!otmCtx || !otmCtx->selectedDeviceInfo || !payload || *payload || !size) + { + return OC_STACK_INVALID_PARAM; + } + + otmCtx->selectedDeviceInfo->doxm->oxmSel = OIC_MANUFACTURER_CERTIFICATE; + + return DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, payload, size, true); +} + +OCStackResult CreateMCertificateBasedOwnerTransferPayload(OTMContext_t* otmCtx, uint8_t **payload, size_t *size) +{ + if (!otmCtx || !otmCtx->selectedDeviceInfo || !payload || *payload || !size) + { + return OC_STACK_INVALID_PARAM; + } + + OicUuid_t uuidPT = {.id={0}}; + *payload = NULL; + *size = 0; + + if (OC_STACK_OK != GetDoxmDeviceID(&uuidPT)) + { + OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return OC_STACK_ERROR; + } + memcpy(otmCtx->selectedDeviceInfo->doxm->owner.id, uuidPT.id , UUID_LENGTH); + + return DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, payload, size, true); +} + +OCStackResult PrepareMCertificateCallback(OTMContext_t *otmCtx) +{ + OIC_LOG(INFO, TAG, "IN PrepareMCertificateCallback"); + + if (CA_STATUS_OK != CAregisterPkixInfoHandler(GetManufacturerPkixInfo)) + { + OIC_LOG(ERROR, TAG, "Failed to register PkixInfohandler"); + return OC_STACK_ERROR; + } + + if (CA_STATUS_OK != CAregisterGetCredentialTypesHandler(InitManufacturerCipherSuiteList)) + { + OIC_LOG(ERROR, TAG, "Failed to register CredentialTypesHandler"); + return OC_STACK_ERROR; + } + + OIC_LOG(INFO, TAG, "OUT PrepareMCertificateCallback"); + + return OC_STACK_OK; +} + +OCStackResult CreateSecureSessionMCertificateCallback(OTMContext_t* otmCtx) +{ + OIC_LOG(INFO, TAG, "IN CreateSecureSessionMCertificateCallback"); + + if (!otmCtx || !otmCtx->selectedDeviceInfo) + { + return OC_STACK_INVALID_PARAM; + } + + CAResult_t caresult = CAEnableAnonECDHCipherSuite(false); + if (CA_STATUS_OK != caresult) + { + OIC_LOG_V(ERROR, TAG, "Failed to disable anon cipher suite"); + return OC_STACK_ERROR; + } + OIC_LOG(INFO, TAG, "Anonymous cipher suite disabled."); + + caresult = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + otmCtx->selectedDeviceInfo->endpoint.adapter); + if (CA_STATUS_OK != caresult) + { + OIC_LOG_V(ERROR, TAG, "Failed to select TLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"); + return OC_STACK_ERROR; + } + OIC_LOG(INFO, TAG, "TLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 cipher suite selected."); + + OCProvisionDev_t* selDevInfo = otmCtx->selectedDeviceInfo; + CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t)); + if (NULL == endpoint) + { + return OC_STACK_NO_MEMORY; + } + memcpy(endpoint,&selDevInfo->endpoint,sizeof(CAEndpoint_t)); + endpoint->port = selDevInfo->securePort; + caresult = CAInitiateHandshake(endpoint); + OICFree(endpoint); + if (CA_STATUS_OK != caresult) + { + OIC_LOG_V(ERROR, TAG, "DTLS handshake failure."); + return OC_STACK_ERROR; + } + + OIC_LOG(INFO, TAG, "OUT CreateSecureSessionMCertificateCallback"); + + return OC_STACK_OK; +} diff --git a/resource/csdk/security/provisioning/unittest/otmunittest.cpp b/resource/csdk/security/provisioning/unittest/otmunittest.cpp index 825b401..69c4c67 100644 --- a/resource/csdk/security/provisioning/unittest/otmunittest.cpp +++ b/resource/csdk/security/provisioning/unittest/otmunittest.cpp @@ -29,6 +29,7 @@ #include "ocprovisioningmanager.h" #include "oxmjustworks.h" #include "oxmrandompin.h" +#include "oxmmanufacturercert.h" #include "securevirtualresourcetypes.h" #include "provisioningdatabasemanager.h" #ifdef _ENABLE_MULTIPLE_OWNER_ @@ -115,6 +116,40 @@ TEST(RandomPinOxMTest, NullParam) EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); } +TEST(ManufacturerCertOxMTest, NullParam) +{ + OTMContext_t* otmCtx = NULL; + OCStackResult res = OC_STACK_ERROR; + uint8_t *payloadRes = NULL; + size_t size = 0; + + res = PrepareMCertificateCallback(otmCtx); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateSecureSessionMCertificateCallback(otmCtx); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateMCertificateBasedSelectOxmPayload(otmCtx, &payloadRes, &size); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateMCertificateBasedOwnerTransferPayload(otmCtx, &payloadRes, &size); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + OTMContext_t otmCtx2; + otmCtx2.selectedDeviceInfo = NULL; + + res = InputPinCodeCallback(&otmCtx2); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateSecureSessionMCertificateCallback(&otmCtx2); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateMCertificateBasedSelectOxmPayload(&otmCtx2, &payloadRes, &size); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateMCertificateBasedOwnerTransferPayload(&otmCtx2, &payloadRes, &size); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); +} /**************************************** * Test the OTM modules with sample server diff --git a/resource/csdk/security/src/doxmresource.c b/resource/csdk/security/src/doxmresource.c index 28f9e38..1a42753 100644 --- a/resource/csdk/security/src/doxmresource.c +++ b/resource/csdk/security/src/doxmresource.c @@ -52,6 +52,10 @@ #include "srmutility.h" #include "pinoxmcommon.h" +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) +#include "pkix_interface.h" +#endif + #define TAG "OIC_SRM_DOXM" #define CHAR_ZERO ('0') @@ -1227,6 +1231,30 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest } #endif // __WITH_DTLS__ or __WITH_TLS__ } +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) + else if (OIC_MANUFACTURER_CERTIFICATE == newDoxm->oxmSel) + { + //Save the owner's UUID to derive owner credential + memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t)); + gDoxm->oxmSel = newDoxm->oxmSel; + //Update new state in persistent storage + if (UpdatePersistentStorage(gDoxm)) + { + ehRet = OC_EH_OK; + } + else + { + OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage"); + ehRet = OC_EH_ERROR; + } + CAResult_t caRes = CAEnableAnonECDHCipherSuite(false); + VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR); + OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED"); + + VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterPkixInfoHandler(GetManufacturerPkixInfo), ERROR); + VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterGetCredentialTypesHandler(InitManufacturerCipherSuiteList), ERROR); + } +#endif // __WITH_DTLS__ or __WITH_TLS__ } /* @@ -1297,6 +1325,13 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage"); ehRet = OC_EH_ERROR; } +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) + if (OIC_MANUFACTURER_CERTIFICATE == gDoxm->oxmSel) + { + CAregisterPkixInfoHandler(GetPkixInfo); + CAregisterGetCredentialTypesHandler(InitCipherSuiteList); + } +#endif // __WITH_DTLS__ or __WITH_TLS__ } } } diff --git a/resource/csdk/stack/include/octypes.h b/resource/csdk/stack/include/octypes.h index 9a7dc85..9126635 100644 --- a/resource/csdk/stack/include/octypes.h +++ b/resource/csdk/stack/include/octypes.h @@ -982,6 +982,7 @@ typedef enum * This error is pushed from DTLS interface when handshake failure happens */ OC_STACK_AUTHENTICATION_FAILURE, + OC_STACK_NOT_ALLOWED_OXM, /** Insert all new error codes here!.*/ #ifdef WITH_PRESENCE diff --git a/resource/include/StringConstants.h b/resource/include/StringConstants.h index b0a111f..4f856c2 100644 --- a/resource/include/StringConstants.h +++ b/resource/include/StringConstants.h @@ -124,6 +124,7 @@ namespace OC static const char DUPLICATE_UUID[] = "Duplicate UUID in DB"; static const char INCONSISTENT_DB[] = "Data in provisioning DB is inconsistent"; static const char AUTHENTICATION_FAILURE[] = "Authentication failure"; + static const char NOT_ALLOWED_OXM[] = "Not allowed ownership transfer method"; static const char PUBLISH_RESOURCE_FAILED[] = "Publish Resource failure"; static const char FORBIDDEN_REQ[] = "Forbidden request"; static const char INTERNAL_SERVER_ERROR[] = "Internal server error"; diff --git a/resource/src/OCException.cpp b/resource/src/OCException.cpp index a8d2d5d..6f2f6b6 100644 --- a/resource/src/OCException.cpp +++ b/resource/src/OCException.cpp @@ -109,6 +109,8 @@ std::string OC::OCException::reason(const OCStackResult sr) return OC::Exception::INCONSISTENT_DB; case OC_STACK_AUTHENTICATION_FAILURE: return OC::Exception::AUTHENTICATION_FAILURE; + case OC_STACK_NOT_ALLOWED_OXM: + return OC::Exception::NOT_ALLOWED_OXM; case OC_STACK_FORBIDDEN_REQ: return OC::Exception::FORBIDDEN_REQ; case OC_STACK_INTERNAL_SERVER_ERROR: diff --git a/resource/unittests/OCExceptionTest.cpp b/resource/unittests/OCExceptionTest.cpp index f3fe50e..3c4fcf0 100644 --- a/resource/unittests/OCExceptionTest.cpp +++ b/resource/unittests/OCExceptionTest.cpp @@ -74,6 +74,7 @@ namespace OC OC_STACK_DUPLICATE_UUID, OC_STACK_INCONSISTENT_DB, OC_STACK_AUTHENTICATION_FAILURE, + OC_STACK_NOT_ALLOWED_OXM, OC_STACK_FORBIDDEN_REQ, OC_STACK_INTERNAL_SERVER_ERROR }; @@ -121,6 +122,7 @@ namespace OC OC::Exception::DUPLICATE_UUID, OC::Exception::INCONSISTENT_DB, OC::Exception::AUTHENTICATION_FAILURE, + OC::Exception::NOT_ALLOWED_OXM, OC::Exception::FORBIDDEN_REQ, OC::Exception::INTERNAL_SERVER_ERROR };