Commit b6d5d3c4 authored by lankamadan's avatar lankamadan Committed by Uze Choi

[easysetup] Security feature integration for ownership transfer - Dev In Progress

- Sconscript modifications for security feature addition
- EnrolleeSecurity class for handling security handshake
- Modifications to support ownership step before provisioning when the enrollee needs security

Change-Id: I26b4fa9a4376691b8bfb42bcb023962337147c0b
Signed-off-by: default avatarlankamadan <lanka.madan@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/4461Tested-by: default avatarjenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: default avatarUze Choi <uzchoi@samsung.com>
Tested-by: default avatarUze Choi <uzchoi@samsung.com>
parent 6c84fd45
......@@ -21,9 +21,11 @@
######################################################################
# easy-setup project build script
######################################################################
import os
import os.path
Import('env')
easysetup_path = os.curdir
######################################################################
#building Resource client, resourceBroker and resourceCache
######################################################################
......@@ -53,7 +55,7 @@ if target_os not in ['windows', 'winrt']:
easy_setup_env.AppendUnique(CXXFLAGS = ['-Wall', '-std=c++0x'])
if target_os == 'linux':
easy_setup_env.AppendUnique(LIBS = ['pthread'])
easy_setup_env.AppendUnique(LIBS = ['pthread', 'dl'])
if target_os in ['android']:
easy_setup_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
......@@ -68,13 +70,16 @@ if target_os == 'linux':
easy_setup_env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
easy_setup_env.AppendUnique(CXXFLAGS = ['-pthread'])
easy_setup_env.PrependUnique(LIBS = ['oc', 'octbstack', 'oc_logger', 'pthread', 'connectivity_abstraction'])
if env.get('SECURED') == '1':
easy_setup_env.PrependUnique(LIBS = ['ocprovision', 'ocpmapi'])
if target_os == 'arduino':
easy_setup_env.AppendUnique(CPPPATH = [
'../../resource/oc_logger/include',
'../../resource/csdk/logger/include',
'../../resource/csdk/stack/include',
'../../extlibs/cjson',
env.get('SRC_DIR') + '/resource/c_common/oic_malloc/include',
env.get('SRC_DIR') + '/resource/oc_logger/include',
env.get('SRC_DIR') + '/resource/csdk/logger/include',
env.get('SRC_DIR') + '/resource/csdk/stack/include',
env.get('SRC_DIR') + '/extlibs/cjson',
'sdk/enrollee/arduino/wifi',
'sdk/enrollee/api',
'sdk/enrollee/src',
......@@ -86,13 +91,20 @@ if target_os in ['android','linux']:
env.get('SRC_DIR') + '/resource/c_common/oic_malloc/include',
env.get('SRC_DIR') + '/resource/include',
env.get('SRC_DIR') + '/resource/csdk/logger/include',
env.get('SRC_DIR') + '/resource/csdk/stack/include',
env.get('SRC_DIR') + '/resource/csdk/logger/include',
env.get('SRC_DIR') + '/resource/csdk/stack/include',
env.get('SRC_DIR') + '/resource/csdk/logger/include',
env.get('SRC_DIR') + '/resource/csdk/security/include',
env.get('SRC_DIR') + '/extlibs/cjson',
'/ser/sdk/common',
env.get('SRC_DIR') + '/extlibs/sqlite3',
'/sdk/common',
'sdk/mediator/include',
'sdk/mediator/src'])
if env.get('SECURED') == '1':
easy_setup_env.AppendUnique(CPPPATH = [
env.get('SRC_DIR') + '/resource/csdk/security/provisioning/include',
env.get('SRC_DIR') + '/resource/csdk/security/provisioning/include/internal',
env.get('SRC_DIR') + '/resource/csdk/security/provisioning/include/oxm'])
######################################################################
# Source files and Targets
......@@ -112,17 +124,29 @@ if target_os == 'android':
'sdk/mediator/src/provisioning.cpp'])
easy_setup_env.InstallTarget(es_sdk_shared, 'libESSDK')
print"easysetup_path %s" % easysetup_path
es_src = None
if target_os == 'linux':
es_sdk_shared = easy_setup_env.SharedLibrary('ESSDKLibrary',
['sdk/mediator/src/RemoteEnrollee.cpp',
'sdk/mediator/src/RemoteEnrolleeResource.cpp',
'sdk/mediator/src/EasySetup.cpp',
'sdk/mediator/src/prov_adapter.cpp',
'sdk/mediator/src/ESException.cpp',
'sdk/mediator/src/wifi_provisioning.cpp',
'sdk/mediator/src/provisioning.cpp'])
if env.get('SECURED') == '1':
env.AppendUnique(es_src = [os.path.join(easysetup_path, 'sdk/mediator/src/EnrolleeSecurity.cpp')])
es_common_src = ['sdk/mediator/src/RemoteEnrollee.cpp',
'sdk/mediator/src/RemoteEnrolleeResource.cpp',
'sdk/mediator/src/EasySetup.cpp',
'sdk/mediator/src/prov_adapter.cpp',
'sdk/mediator/src/ESException.cpp',
'sdk/mediator/src/wifi_provisioning.cpp',
'sdk/mediator/src/provisioning.cpp']
env.AppendUnique(es_src = es_common_src)
es_sdk_shared = easy_setup_env.SharedLibrary('ESSDKLibrary', env.get('es_src'))
easy_setup_env.InstallTarget(es_sdk_shared, 'libESSDK')
print "Files path is %s" % env.get('es_src')
#Go to build sample apps
SConscript('sampleapp/SConscript')
......
......@@ -55,6 +55,9 @@ mediator_env.PrependUnique(CPPPATH = [
env.get('SRC_DIR') + '/service/easy-setup/sdk/common'])
mediator_env.PrependUnique(LIBS = ['oc', 'octbstack', 'oc_logger', 'pthread', 'connectivity_abstraction', 'coap', 'ESSDKLibrary'])
if env.get('SECURED') == '1':
mediator_env.PrependUnique(LIBS = ['ocpmapi', 'ocprovision'])
mediator = mediator_env.Program('mediator', 'mediator_cpp.cpp')
......
......@@ -19,6 +19,7 @@
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <iostream>
#include<stdio.h>
#include "oic_string.h"
#include "EasySetup.h"
......@@ -28,6 +29,8 @@
#define ES_SAMPLE_APP_TAG "ES_SAMPLE_APP_TAG"
#define DECLARE_MENU(FUNC, ...) { #FUNC, FUNC }
#define JSON_DB_PATH "./oic_svr_db_client.json"
using namespace OC;
using namespace OIC::Service;
......@@ -35,6 +38,8 @@ static EasySetup *easySetupIntance = nullptr;
static EnrolleeNWProvInfo netInfo;
static RemoteEnrollee::shared_ptr remoteEnrollee = nullptr;
static std::string ipaddress, ssid, pwd;
struct CloseApp
{
};
......@@ -88,20 +93,21 @@ void initEasySetup()
easySetupIntance = EasySetup::getInstance();
std::string ipaddress ("192.168.0.100");
std::cout << "Enter the target enrollee ipv4 address ";
ipaddress = "192.168.0.150";
//std::cout << "Enter the target enrollee ipv4 address ";
std::string ssid;
std::cout << "Enter the ssid of the target Enrolleer ";
std:: cin >> ssid;
ssid = "hello";
//std::cout << "Enter the ssid of the target Enrolleer ";
//std:: cin >> ssid;
std::string pwd;
std::cout << "Enter the pwd of the target Enrolleer ";
std::cin >> pwd;
pwd = "helalalal";
//std::cout << "Enter the pwd of the target Enrolleer ";
//std::cin >> pwd;
netInfo.connType = CT_ADAPTER_IP;
netInfo.isSecured = false;
netInfo.needSecuredEasysetup = false;
OICStrcpy(netInfo.netAddressInfo.WIFI.ipAddress, IPV4_ADDR_SIZE - 1, ipaddress.c_str());
OICStrcpy(netInfo.netAddressInfo.WIFI.ssid, NET_WIFI_SSID_SIZE - 1, ssid.c_str());
OICStrcpy(netInfo.netAddressInfo.WIFI.pwd, NET_WIFI_PWD_SIZE - 1, pwd.c_str());
......@@ -154,11 +160,19 @@ void runEasySetupMenu()
};
}
static FILE* client_open(const char *UNUSED_PARAM, const char *mode)
{
(void)UNUSED_PARAM;
return fopen(JSON_DB_PATH, mode);
}
void configurePlatform()
{
OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
PlatformConfig config
{
OC::ServiceType::InProc, ModeType::Client, "0.0.0.0", 0, OC::QualityOfService::LowQos
OC::ServiceType::InProc, ModeType::Both, "0.0.0.0", 0, OC::QualityOfService::LowQos, NULL
};
OCPlatform::Configure(config);
}
......
......@@ -21,6 +21,7 @@
#ifndef ES_COMMON_H_
#define ES_COMMON_H_
#include <string>
#ifndef WITH_ARDUINO
#include <memory>
#endif
......@@ -32,8 +33,8 @@
#define OIC_STRING_MAX_VALUE 100
#define IPV4_ADDR_SIZE 16
#define IP_PORT 55555
#define NET_WIFI_SSID_SIZE 16
#define NET_WIFI_PWD_SIZE 16
#define NET_WIFI_SSID_SIZE 100
#define NET_WIFI_PWD_SIZE 100
/**
* @brief Mac address length for BT port
......@@ -188,9 +189,13 @@ typedef union
*/
typedef struct
{
EnrolleeInfo netAddressInfo; /**< Enroller Network Info**/
OCConnectivityType connType; /**< Connectivity Type**/
bool isSecured; /**< Secure connection**/
EnrolleeInfo netAddressInfo; /**< Enroller Network Info**/
OCConnectivityType connType; /**< Connectivity Type**/
bool isSecured; /**< Secure connection**/
// TODO : Ideally isSecured should be renamed to needSecuredEasysetup.
// To provide backward compatibility to v1.0 release, a new variable is being added.
// If isSecured is not used by other applications, isSecured will be depricated.
bool needSecuredEasysetup; /**< Need of secure ownership transfer during easysetup**/
} EnrolleeNWProvInfo;
/**
......@@ -198,6 +203,8 @@ typedef struct
*/
typedef void (*OCProvisioningStatusCB)(EasySetupInfo *easySetupInfo);
#ifndef WITH_ARDUINO
namespace OIC
{
namespace Service
......@@ -218,7 +225,40 @@ namespace OIC
ES_PROVISIONED
} CurrentESState;
#ifndef WITH_ARDUINO
typedef enum
{
ES_SEC_UNKNOWN = 0,
ES_SEC_OWNED,
ES_SEC_ACL_PROVISIONED,
ES_SEC_CREDS_PROVISIONED
} EnrolleeSecState;
/**
* Security Provisioning Status
*/
typedef struct {
/// UUID of the target device
std::string devUUID;
/// EasySetup result
ESResult res;
} SecProvisioningResult;
/**
* Callback function definition for providing Enrollee security status .
*/
typedef std::function< void(SecProvisioningResult) > EnrolleeSecStatusCb;
/**
* Callback definition to be invoked when the security stack expects a pin from application.
*/
typedef std::function< void(std::string&) > SecurityPinCb;
/**
* Callback definition to be invoked when the stack expects a db path.
*/
typedef std::function< void(std::string&) > SecProvisioningDbPathCb;
class ProvisioningStatus
{
public:
......@@ -267,9 +307,8 @@ namespace OIC
EasySetupState m_easySetupState;
EnrolleeNWProvInfo m_enrolleeNWProvInfo;
};
#endif
}
}
#endif //WITH_ARDUINO
#endif
#endif //ES_COMMON_H_
......@@ -21,6 +21,8 @@
#include "resourceHandler.h"
#include "ocpayload.h"
#include "oic_string.h"
/**
* @var ES_RH_TAG
* @brief Logging tag for module name.
......@@ -172,6 +174,10 @@ OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
{
sprintf(g_prov.tnn, "%s", tnn);
}
else
{
OC_LOG (ERROR, ES_RH_TAG, "value is not available");
}
OC_LOG_V(INFO, ES_RH_TAG, "g_prov.tnn %s", g_prov.tnn);
......@@ -180,6 +186,10 @@ OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
{
sprintf(g_prov.cd, "%s", cd);
}
else
{
OC_LOG (ERROR, ES_RH_TAG, "value is not available");
}
OC_LOG_V(INFO, ES_RH_TAG, "g_prov.cd %s", g_prov.cd);
......
......@@ -28,6 +28,7 @@ namespace OIC
namespace Service
{
class RemoteEnrolleeResource;
class EnrolleeSecurity;
/**
* This class represents Remote Enrollee device instance.
......@@ -61,10 +62,30 @@ namespace OIC
typedef std::function< void(std::shared_ptr< EasySetupStatus >) >
EasySetupStatusCB;
#ifdef __WITH_DTLS__
/**
* Register Security status and other information callback handlers.
*
* @param enrolleeSecStatusCb Callback to get security status callbacks.
* @param secProvisioningDbCb Callback to be invoked when the stack expects a
* path for the provisioning db.
* @param securityPinCb Callback to get security pin during pin based ownership transfer.
*
* @throws InvalidParameterException If callback is an empty function or null.
* @throws ESBadRequestException If registration is already completed.
*
* @see SecProvisioningResult
*/
ESResult registerSecurityCallbackHandler(EnrolleeSecStatusCb enrolleeSecStatusCb,
SecurityPinCb securityPinCb, SecProvisioningDbPathCb secProvisioningDbPathCb);
#endif //__WITH_DTLS__
/**
* Register EasySetup status handler.
*
* @param callback Callback to get EasySetup status.
* @param secProvisioningDbCB Callback to be invoked when the stack expects a
* path for the provisioning db.
*
* @throws InvalidParameterException If callback is an empty function or null.
* @throws ESBadRequestException If registration is already completed.
......@@ -80,32 +101,37 @@ namespace OIC
*
* @see RemoteEnrollee
*/
virtual void startProvisioning();
void startProvisioning();
/**
* Stop provisioning process that is currently in progress.
*
* @throws BadRequestException If provisioning is not in progress.
*/
virtual void stopProvisioning();
void stopProvisioning();
/**
* Check if the Enrollee device provisioned.
*/
virtual bool isEnrolleeProvisioned();
bool isEnrolleeProvisioned();
/**
* Get the Provisioning information provided for the current Enrollee.
*
* @return EnrolleeNWProvInfo Provisioning information provided for the current Enrollee.
*/
virtual EnrolleeNWProvInfo& getEnrolleeProvisioningInfo ();
EnrolleeNWProvInfo& getEnrolleeProvisioningInfo ();
private:
std::shared_ptr< RemoteEnrolleeResource > m_remoteResource;
EasySetupStatusCB m_easySetupStatusCb;
EnrolleeSecStatusCb m_enrolleeSecStatusCb;
SecurityPinCb m_securityPinCb;
SecProvisioningDbPathCb m_secProvisioningDbPathCb;
EnrolleeNWProvInfo m_enrolleeNWProvInfo;
std::shared_ptr< EnrolleeSecurity > m_enrolleeSecurity;
CurrentESState m_currentESState;
bool m_needSecuredEasysetup;
void provisioningStatusHandler (std::shared_ptr< ProvisioningStatus > provStatus);
};
......
//******************************************************************
//
// 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.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "EnrolleeSecurity.h"
#include "oxmjustworks.h"
#include "oxmrandompin.h"
#include "RemoteEnrolleeResource.h"
#include "logger.h"
#include "ESException.h"
#include "oic_malloc.h"
namespace OIC
{
namespace Service
{
//TODO : Currently discovery timeout for owned and unowned devices is fixed as 5
// The value should be accepted from the application as a parameter during ocplatform
// config call
#define ES_SEC_DISCOVERY_TIMEOUT 5
EnrolleeSecurity::EnrolleeSecurity(
std::shared_ptr< RemoteEnrolleeResource > remoteEnrolleeResource,
std::string secDbPath)
{
m_enrolleeSecState = EnrolleeSecState::ES_SEC_UNKNOWN;
//Initializing the provisioning client stack using the db path provided by the
// application.
// Note : If the path is NULL or empty, the PDM.db should be present in the same path.
OCStackResult result = OCSecure::provisionInit(secDbPath);
if (result != OC_STACK_OK)
{
throw ESPlatformException(result);
}
}
ESResult EnrolleeSecurity::registerCallbackHandler(
EnrolleeSecStatusCb enrolleeSecStatusCb, SecurityPinCb securityPinCb,
SecProvisioningDbPathCb secProvisioningDbPathCb)
{
m_enrolleeSecStatusCb = enrolleeSecStatusCb;
m_securityPinCb = securityPinCb;
m_secProvisioningDbPathCb = secProvisioningDbPathCb;
return ES_ERROR;
}
std::shared_ptr< OC::OCSecureResource > EnrolleeSecurity::findEnrollee(std::string host,
DeviceList_t &list)
{
for (unsigned int i = 0; i < list.size(); i++)
{
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Device %d ID %s ", i + 1,
list[i]->getDeviceID().c_str());
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "From IP :%s", list[i]->getDevAddr().c_str());
if(list[i]->getDevAddr() == host)
{
return list[i];
}
}
return nullptr;
}
void EnrolleeSecurity::ownershipTransferCb(OC::PMResultList_t *result, int hasError)
{
if (hasError)
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG,"Error!!! in OwnershipTransfer");
}
else
{
OC_LOG(DEBUG, ENROLEE_SECURITY_TAG,"Transferred Ownership successfuly for device : ");
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",result->at(0).deviceId.id);
delete result;
//TODO : Decide if we have to manage the owned/unowned devices.
//pOwnedDevList.push_back(pUnownedDevList[transferDevIdx]);
//pUnownedDevList.erase(pUnownedDevList.begin() + transferDevIdx);
}
}
/**
* Callback function for provisioning ACL, Credentials.
*
* @param[in] result Result list
* @param[in] hasError indicates if the result has error
*/
void EnrolleeSecurity::provisionCb(OC::PMResultList_t *result, int hasError)
{
if (hasError)
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Error in provisioning operation!");
}
else
{
OC_LOG(DEBUG, ENROLEE_SECURITY_TAG, "Received provisioning results: ");
for (unsigned int i = 0; i < result->size(); i++)
{
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Result is = %d for device",result->at(i).res); OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "UUID : %s",result->at(0).deviceId.id);
}
delete result;
}
}
ESResult EnrolleeSecurity::performOwnershipTransfer()
{
ESResult res = ES_ERROR;
OC::DeviceList_t pUnownedDevList, pOwnedDevList;
pOwnedDevList.clear();
pUnownedDevList.clear();
OCStackResult result = OCSecure::discoverOwnedDevices(ES_SEC_DISCOVERY_TIMEOUT,
pOwnedDevList);
if (result != OC_STACK_OK)
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "Owned Discovery failed.");
res = ES_ERROR;
return res;
}
else if (pOwnedDevList.size())
{
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found owned devices. Count =%d",
pOwnedDevList.size());
std::shared_ptr< OC::OCSecureResource > ownedDevice =
findEnrollee(
m_remoteEnrolleeResource->m_enrolleeNWProvInfo.netAddressInfo.WIFI.ipAddress,
pOwnedDevList);
if(ownedDevice)
{
res = ES_OK;
}
}
else
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "No Secure devices found.");
res = ES_ERROR;
return res;
}
result = OCSecure::discoverUnownedDevices(ES_SEC_DISCOVERY_TIMEOUT,
pUnownedDevList);
if (result != OC_STACK_OK)
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "UnOwned Discovery failed.");
res = ES_ERROR;
return res;
}
else if (pUnownedDevList.size())
{
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Found Unowned devices. Count =%d",
pUnownedDevList.size());
std::shared_ptr< OC::OCSecureResource > unownedDevice =
findEnrollee(
m_remoteEnrolleeResource->m_enrolleeNWProvInfo.netAddressInfo.WIFI.ipAddress,
pUnownedDevList);
if (unownedDevice)
{
OTMCallbackData_t justWorksCBData;
justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
justWorksCBData.createOwnerTransferPayloadCB =
CreateJustWorksOwnerTransferPayload;
OCSecure::setOwnerTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData, NULL);
OC_LOG_V(DEBUG, ENROLEE_SECURITY_TAG, "Transfering ownership for : %s ",
unownedDevice->getDeviceID().c_str());
OC::ResultCallBack ownershipTransferCb = std::bind(
&EnrolleeSecurity::ownershipTransferCb, this, std::placeholders::_1,
std::placeholders::_2);
if (unownedDevice->doOwnershipTransfer(ownershipTransferCb) != OC_STACK_OK)
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "OwnershipTransferCallback is failed");
res = ES_ERROR;
}
else
{
if(provisionCreds() == ES_OK)
{
OC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
"provisionCreds success. Continuing with provisioning ACL");
if (provisionAcl() == ES_OK)
{
OC_LOG(DEBUG, ENROLEE_SECURITY_TAG,
"provisionAcl success.");
//returning success;
res = ES_OK;
}
else
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "provisionAcl failed.");
res = ES_ERROR;
}
}
else
{
OC_LOG(ERROR, ENROLEE_SECURITY_TAG, "provisionCreds failed.");