From: Sachin Agrawal Date: Mon, 28 Sep 2015 16:38:19 +0000 (-0700) Subject: Merge branch 'security-CKM' into 'master' X-Git-Tag: 1.0.0-RC2~22 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7781b2b225c53d7ce6a13cbe0aba56c37d69009b;p=contrib%2Fiotivity.git Merge branch 'security-CKM' into 'master' * security-CKM: Removed automatic switching to X.509 in CA implement unit tests for CK manager Add sample of PKIX provisioning Conflicts: resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c Change-Id: If1e8367e3729b152602d1585bc433f083354c5e1 Signed-off-by: Sachin Agrawal Reviewed-on: https://gerrit.iotivity.org/gerrit/3233 Tested-by: jenkins-iotivity --- diff --git a/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/Door_sample.cpp b/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/Door_sample.cpp new file mode 100755 index 0000000..c4db6bc --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/Door_sample.cpp @@ -0,0 +1,574 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 +#include +#include +#include +#include +#include +#include +#include "ocstack.h" +#include "logger.h" +#include "cJSON.h" +#include "global.h" +#include "cainterface.h" +#include "cacommon.h" +#include "ocstackinternal.h" +#include "payload_logging.h" +#include "ocpayload.h" + + +#define TAG "DEMO" +#define DEFAULT_CONTEXT_VALUE 0x99 +#define STATE "state" +#define OPEN_DURATION "openDuration" +#define OPEN_ALARM "openAlarm" + +static const char MULTICAST_DISCOVERY_QUERY[] = "/oic/res"; + +volatile sig_atomic_t gQuitFlag = 0; +OCPersistentStorage ps = {0, 0, 0, 0, 0}; +static const char *gResourceUri = "/a/door"; +uint8_t lightIpAddr[4] = {}; +uint16_t lightPortNu; +static bool isUpdated = false; +static std::string coapServerIP; +static std::string coapServerPort; +static std::string coapServerResource; +static OCConnectivityType ocConnType; + +static std::string address; + +static int coapSecureResource; + +static const char CRED_FILE[] = "oic_svr_db_door.json"; + +CAEndpoint_t endpoint = {CA_DEFAULT_ADAPTER, CA_DEFAULT_FLAGS, 0, {0}, 0}; + +// myDoorState_t variable to store resource's state . +typedef enum +{ + STATE_OPEN, /**< State is opened */ + STATE_CLOSED /**< State is closed*/ +} myDoorState_t; + +//Structure to represent a door resource and its attributes +typedef struct DOORRESOURCE +{ + OCResourceHandle handle; + myDoorState_t state; //ReadOnly, The state of the door (open or closed)" + char *openDuration; //ReadOnly, The time duration the door has been open + bool openAlarm ; //The state of the door open alarm + +} DoorResource; + +static DoorResource Door; + +int parseClientResponse(OCClientResponse * clientResponse) +{ + if(!clientResponse) + { + return 0; + } + + OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources; + + // Initialize all global variables + coapServerResource.clear(); + coapSecureResource = 0; + + while (res) + { + coapServerResource.assign(res->uri); + OC_LOG_V(INFO, TAG, "Uri -- %s", coapServerResource.c_str()); + + if (res->secure) + { + endpoint.port = res->port; + coapSecureResource = 1; + } + + OC_LOG_V(INFO, TAG, "Secure -- %s", coapSecureResource == 1 ? "YES" : "NO"); + + // If we discovered a secure resource, exit from here + if (coapSecureResource) + { + break; + } + + res = res->next; + } + + return 0; +} + +OCRepPayload* getPayload(const char* uri, int64_t state, char* openDuration, bool openAlarm) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if (!payload) + { + OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload")); + return nullptr; + } + + OCRepPayloadSetUri(payload, uri); + OCRepPayloadSetPropInt(payload, STATE, state); + OCRepPayloadSetPropString(payload, OPEN_DURATION, openDuration); + OCRepPayloadSetPropBool(payload, OPEN_ALARM, openAlarm); + + 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) + { + OC_LOG(ERROR, TAG, PCF("Incoming payload not a representation")); + return nullptr; + } + + DoorResource *currdoorResource = &Door; + + return getPayload(gResourceUri, currdoorResource->state, currdoorResource->openDuration, currdoorResource->openAlarm); +} + +OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult = OC_EH_ERROR; + + OCRepPayload *getResp = constructResponse(ehRequest); + + if(getResp) + { + *payload = getResp; + ehResult = OC_EH_OK; + } + + return ehResult; +} + +OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* /*callbackParam*/) +{ + OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag); + + OCEntityHandlerResult ehResult = OC_EH_ERROR; + OCEntityHandlerResponse response; + + // Validate pointer + if (!entityHandlerRequest) + { + OC_LOG (ERROR, TAG, "Invalid request pointer"); + return OC_EH_ERROR; + } + + OCRepPayload* payload = nullptr; + + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG"); + + if (entityHandlerRequest) + { + switch(entityHandlerRequest->method) + { + case OC_REST_GET: + { + OC_LOG (INFO, TAG, "Received OC_REST_GET from client"); + ehResult = ProcessGetRequest (entityHandlerRequest, &payload); + } + break; + default: + { + OC_LOG_V (INFO, TAG, "Received unsupported method %d from client", + entityHandlerRequest->method); + ehResult = OC_EH_ERROR; + } + break; + } + + 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 = reinterpret_cast(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) + { + OC_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) +{ + return fopen(CRED_FILE, mode); +} + +void SetPersistentHandler(OCPersistentStorage *ps) +{ + if (ps) + { + ps->open = server_fopen; + ps->read = fread; + ps->write = fwrite; + ps->close = fclose; + ps->unlink = unlink; + + OCRegisterPersistentStorageHandler(ps); + } +} + +/** + * GetResult is returned result to string. + * @param result [IN] stack result + * @return converted OCStackResult as string for debugging + */ +static 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"; + case OC_STACK_UNAUTHORIZED_REQ: + return "OC_STACK_UNAUTHORIZED_REQ"; + #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"; + } +} + + +/** + * CreateDoorResource creates a new door resource by calling the OCCreateResource() method. + * @param uri [IN] uri + * @param doorResource [IN] info of resource + * @return ::OC_STACK_OK on success, some other value upon failure. + */ +int createDoorResource (const char *uri, DoorResource *doorResource) +{ + if (!uri) + { + OC_LOG(ERROR, TAG, "Resource URI cannot be NULL"); + + } + + doorResource->state = STATE_CLOSED; //1:closed , 0: open + char str[] = "10min"; + doorResource->openDuration = str; + doorResource->openAlarm = false; + OCStackResult res = OCCreateResource(&(doorResource->handle), + "core.door", + OC_RSRVD_INTERFACE_DEFAULT, + uri, + OCEntityHandlerCb, + NULL, + OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE); + + OC_LOG_V(INFO, TAG, "Created Door resource with result: %s", getResult(res)); + return 0; +} + +OCStackApplicationResult putReqCB(void * ctx, OCDoHandle /*handle*/, OCClientResponse *clientResponse) +{ + if (ctx == (void *)DEFAULT_CONTEXT_VALUE) + { + OC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully"); + } + + if (clientResponse) + { + OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result)); + OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber); + OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload); + if ((OCSecurityPayload*)clientResponse->payload) + { + OC_LOG_V(INFO, TAG, "=============> Put Response", + ((OCSecurityPayload*)clientResponse->payload)->securityData); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +OCStackApplicationResult getReqCB(void * /*ctx*/, OCDoHandle /*handle*/, OCClientResponse *clientResponse) +{ + OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully"); + + if (clientResponse) + { + OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result)); + OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber); + OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload); + if ((OCSecurityPayload*)clientResponse->payload) + { + OC_LOG(INFO, TAG, PCF("=============> Get Response")); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +// This is a function called back when a device is discovered +OCStackApplicationResult discoveryReqCB(void* /*ctx*/, OCDoHandle /*handle*/, + OCClientResponse * clientResponse) +{ + OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully"); + + if (clientResponse) + { + OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result)); + OC_LOG_V(INFO, TAG, + "Device =============> Discovered @ %s:%d", + clientResponse->devAddr.addr, + clientResponse->devAddr.port); + + if (clientResponse->result == OC_STACK_OK) + { + OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload); + ocConnType = clientResponse->connType; + parseClientResponse(clientResponse); + } + } + + return OC_STACK_KEEP_TRANSACTION; + +} + + + +void initAddress() +{ + static bool initFlag = false; + if (!initFlag) + { + OC_LOG(INFO, TAG, "Enter IP address (with optional port) of the Server hosting resource\n"); + OC_LOG(INFO, TAG, "IPv4: 192.168.0.15:45454\n"); + OC_LOG(INFO, TAG, "IPv6: [fe80::20c:29ff:fe1b:9c5]:45454\n"); + + std::cin >> address; + } + initFlag = true; +} + +// Local function to send get request of light resource +void SendGetRequest() +{ + OCStackResult ret; + OC_LOG(INFO, TAG, "Send Get REQ to Light server"); + + initAddress(); + + char szQueryUri[64] = { '\0'}; + OCDoHandle handle; + OCCallbackData cbData; + cbData.cb = getReqCB; + cbData.context = (void *)DEFAULT_CONTEXT_VALUE; + cbData.cd = NULL; + OC_LOG_V(INFO, TAG, "Get payload from Door sample = /a/light "); + snprintf(szQueryUri, sizeof(szQueryUri), "coaps://%s/a/light", const_cast (address.c_str())); // lightPortNu); + ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, NULL, ocConnType, OC_LOW_QOS, + &cbData, NULL, 0); + if (ret != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + } +} + + +void *input_function(void * /*data*/) +{ + char input; + char szQueryUri[64] = { 0 }; + OCDoHandle handle; + OCCallbackData cbData; + cbData.cb = discoveryReqCB; + cbData.context = (void *)DEFAULT_CONTEXT_VALUE; + cbData.cd = NULL; + + strcpy(szQueryUri, MULTICAST_DISCOVERY_QUERY); + + while (1) + { + std::cin >> input; + switch (input) + { + case 'D': + case 'd': + if (isUpdated == false) + { + OC_LOG(INFO, TAG, "isUpdated is false..."); + OCDoResource(&handle, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT, OC_LOW_QOS, &cbData, NULL, 0); + + } + break; + case 'G': + case 'g': + isUpdated = true; + if (isUpdated == true) + { + OC_LOG(INFO, TAG, "isUpdated is true..."); + SendGetRequest(); + } + break; + case 'Q': + case 'q': + gQuitFlag = 1; + return 0; + default: break; + } + } + return 0; +} + +static void PrintUsage() +{ + OC_LOG(INFO, TAG, "*******************************************"); + OC_LOG(INFO, TAG, "Input D or d to discover Resources"); + OC_LOG(INFO, TAG, "Input G or g to initiate Get Request"); + OC_LOG(INFO, TAG, "Input Q or q to exit"); + OC_LOG(INFO, TAG, "*******************************************"); +} + +int main() +{ + + OC_LOG(INFO, TAG, "OCServer is starting..."); + SetPersistentHandler(&ps); + //PrintUsage(); + if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack init error"); + return 0; + } + + /* + * Declare and create the example resource: Door + */ + createDoorResource(gResourceUri, &Door); + PrintUsage(); + + //select ciphersuite for certificates + CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000L; + + // Break from loop with Ctrl-C + OC_LOG(INFO, TAG, "Entering ocserver main loop..."); + signal(SIGINT, handleSigInt); + int thr_id; + pthread_t p_thread; + thr_id = pthread_create(&p_thread, NULL, input_function, (void *)NULL); + if (thr_id < 0) + { + OC_LOG(ERROR, TAG, "create thread error"); + return 0; + } + + while (!gQuitFlag) + { + + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + return 0; + } + + + nanosleep(&timeout, NULL); + } + + pthread_join(p_thread, NULL); + + OC_LOG(INFO, TAG, "Exiting ocserver main loop..."); + + if (OCStop() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + } + + return 0; +} diff --git a/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/oic_svr_db_door.json b/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/oic_svr_db_door.json new file mode 100644 index 0000000..21aa0e7 --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/oic_svr_db_door.json @@ -0,0 +1,46 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/res/d", + "/oic/res/types/d", + "/oic/presence" + ], + "perms": 2, + "ownrs" : [ + "ZG9vckRldmljZVVVSUQwMA==" + ] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/crl", + "/oic/sec/cred" + ], + "perms": 6, + "ownrs" : [ + "ZG9vckRldmljZVVVSUQwMA==" + ] + } + ], + "pstat": { + "isop": false, + "deviceid": "ZG9vckRldmljZVVVSUQwMA==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": false, + "deviceid": "ZG9vckRldmljZVVVSUQwMA==" + } +} diff --git a/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/Light_sample.cpp b/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/Light_sample.cpp new file mode 100755 index 0000000..9a3f82e --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/Light_sample.cpp @@ -0,0 +1,334 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 +#include +#include +#include +#include +#include +#include "ocstack.h" +#include "logger.h" +#include "cJSON.h" +#include "global.h" +#include "cainterface.h" +#include "cacommon.h" +#include "ocpayload.h" + +#define TAG "DEMO" + +volatile sig_atomic_t gQuitFlag = 0; +OCPersistentStorage ps = {0, 0, 0, 0, 0}; +const char *gResourceUri = (char *)"/a/light"; + +//Secure Virtual Resource database for Iotivity Server +//It contains Server's Identity and the PSK credentials +//of other devices which the server trusts +static char CRED_FILE[] = "oic_svr_db_light.json"; + + +//Structure to represent a light resource and its attributes +typedef struct LIGHTRESOURCE +{ + OCResourceHandle handle; + //Attributes + int brightness; // 0-100 +} LightResource; + +// Structure to represent a light resource and its attributes +static LightResource Light; + +OCRepPayload* getPayload(const char* uri, int64_t brightness) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if(!payload) + { + OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload")); + return nullptr; + } + + OCRepPayloadSetUri(payload, uri); + OCRepPayloadSetPropInt(payload, "brightness", brightness); + + return payload; +} + +//This function takes the request as an input and returns the response +OCRepPayload* constructResponse(OCEntityHandlerRequest *ehRequest) +{ + if(!ehRequest) + { + return nullptr; + } + + if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION) + { + OC_LOG(ERROR, TAG, PCF("Incoming payload not a representation")); + return nullptr; + } + + return getPayload(gResourceUri, Light.brightness); +} + +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult = OC_EH_ERROR; + + OCRepPayload *getResp = constructResponse(ehRequest); + + if(getResp && payload) + { + *payload = getResp; + ehResult = OC_EH_OK; + } + + return ehResult; +} + + +OCEntityHandlerResult OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* /*callbackParam*/) +{ + OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag); + + OCEntityHandlerResult ehResult = OC_EH_ERROR; + OCEntityHandlerResponse response; + + // Validate pointer + if (!entityHandlerRequest) + { + OC_LOG (ERROR, TAG, "Invalid request pointer"); + return OC_EH_ERROR; + } + + OCRepPayload* payload = nullptr; + + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG"); + if (entityHandlerRequest) + { + switch(entityHandlerRequest->method) + { + case OC_REST_GET: + { + OC_LOG (INFO, TAG, "Received OC_REST_GET from client"); + ehResult = ProcessGetRequest (entityHandlerRequest, &payload); + } + break; + default: + { + OC_LOG_V (INFO, TAG, "Received unsupported method %d from client", + entityHandlerRequest->method); + ehResult = OC_EH_ERROR; + } + break; + } + + 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 = reinterpret_cast(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) + { + OC_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) +{ + return fopen(CRED_FILE, mode); +} + +void SetPersistentHandler(OCPersistentStorage *ps) + +{ + + if (ps) + + { + + ps->open = server_fopen; + + ps->read = fread; + + ps->write = fwrite; + + ps->close = fclose; + + ps->unlink = unlink; + + + OCRegisterPersistentStorageHandler(ps); + + } + +} +/** + * GetResult is returned result to string. + * @param result [IN] stack result + * @return converted OCStackResult as string for debugging + */ +static 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"; + case OC_STACK_ERROR: + return "OC_STACK_ERROR"; + default: + return "UNKNOWN"; + } +} + +/** + * CreateLightResource creates a new light resource by calling the OCCreateResource() method. + * @param uri [IN] uri + * @param lightResource [IN] info of resource + * @return ::OC_STACK_OK on success, some other value upon failure. + */ +int createLightResource (const char *uri, LightResource *lightResource) +{ + if (!uri) + { + OC_LOG(ERROR, TAG, "Resource URI cannot be NULL"); + + } + + lightResource->brightness = 0; + OCStackResult res = OCCreateResource(&(lightResource->handle), + "core.light", + OC_RSRVD_INTERFACE_DEFAULT, + uri, + OCEntityHandlerCb, + NULL, + OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE); + + OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res)); + return 0; +} + + +int main() +{ + OC_LOG(DEBUG, TAG, "OCServer is starting..."); + SetPersistentHandler(&ps); + if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack init error"); + return 0; + } + + /* + * Declare and create the example resource: Light + */ + createLightResource(gResourceUri, &Light); + + CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000L; + + // Break from loop with Ctrl-C + OC_LOG(INFO, TAG, "Entering ocserver main loop..."); + signal(SIGINT, handleSigInt); + while (!gQuitFlag) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + return 0; + } + + nanosleep(&timeout, NULL); + } + + OC_LOG(INFO, TAG, "Exiting ocserver main loop..."); + + if (OCStop() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + } + + return 0; +} diff --git a/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/oic_svr_db_light.json b/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/oic_svr_db_light.json new file mode 100755 index 0000000..d10b71e --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/oic_svr_db_light.json @@ -0,0 +1,46 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/res/d", + "/oic/res/types/d", + "/oic/presence" + ], + "perms": 2, + "ownrs" : [ + "bGlnaHREZXZpY2VVVUlEMA==" + ] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/crl", + "/oic/sec/cred" + ], + "perms": 6, + "ownrs" : [ + "bGlnaHREZXZpY2VVVUlEMA==" + ] + } + ], + "pstat": { + "isop": false, + "deviceid": "bGlnaHREZXZpY2VVVUlEMA==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": false, + "deviceid": "bGlnaHREZXZpY2VVVUlEMA==" + } +} diff --git a/resource/csdk/security/provisioning/ck_manager/sample/README.txt b/resource/csdk/security/provisioning/ck_manager/sample/README.txt new file mode 100644 index 0000000..5338d76 --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/README.txt @@ -0,0 +1,132 @@ +# Open three terminal windows in linux +# The first one use for start Light server +# Note: Here and below $PROJ_DIR is root directory of iotivity project (e.g /path/to/iotivity) +$ cd $PROJ_DIR/out/linux/x86_64/release/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource +$ cp $PROJ_DIR/resource/csdk/security/provisioning/ck_manager/sample/Light_Resource/*.json ./ +$ ./Light_server + +# Second terminal window use for start Door server +$ cp $PROJ_DIR/resource/csdk/security/provisioning/ck_manager/sample/Door_Resource/*.json ./ +$ ./Door_server + +# And third terminal window use for start provisioning_client +# provisioning_client ask for input ACL data: +# 1. Controller device. Enter ID of the doorDeviceUUID00 +# 2. Controlee device. Enter ID of the lightDeviceUUID0 +# 3. Subject : doorDeviceUUID00 +# 4. Num. of Resource : 1 +# 5. [1]Resource : /a/light +# 6. permissions: CRUDN +# 7. Num. of Rowner : 1 +# 8. [1]Rowner : lightDeviceUUID0 +# +# After successfull sending acl provisioning_client will ask you for CRL data: +# 1. Enter number of revoced certificates(1..9): 1 +# 2. Revoced certificate 0: Serial number (E. g.: 100): 3 +# And then you should see message about successfull sending CRL +# +# Note: provisioning_client send ACL and CRL only to Light sever + +$ cd $PROJ_DIR/out/linux/x86_64/release/resource/csdk/security/provisioning/ck_manager/sample +$ rm ckminfo.dat +$ cp $PROJ_DIR/resource/csdk/security/provisioning/ck_manager/sample/oic_svr_db_pt.json ./ +$ ./provisioningclient +Provisioning device ID : doorDeviceUUID00 +Provisioning Success~!! +Provisioning device ID : lightDeviceUUID0 +Provisioning Success~!! +Sending credential is succeed~!! +****************************************************************************** +-Set ACL policy for target device +****************************************************************************** +-URN identifying the subject +ex) doorDeviceUUID00 (16 Numbers except to '-') +Subject : doorDeviceUUID00 +Num. of Resource : 1 +-URI of resource +ex) /a/light (Max_URI_Length: 64 Byte ) +[1]Resource : /a/light +-Set the permission(C,R,U,D,N) +ex) CRUDN, CRU_N,..(5 Charaters) +Permission : CRUDN +Num. of Rowner : 1 +-URN identifying the rowner +ex) lightDeviceUUID0 (16 Numbers except to '-') +[1]Rowner : lightDeviceUUID0 +Sending ACL is succeed~!! +Enter number of revoced certificates (1..9) +1 +Revoked certificate 0: +Serial number (E. g.: 100): +2 +Sending CRL is succeed~!! + +# Change window to terminal where Door server is running +# Enter 'd' for discovery. You should see output like this: +21:56.283 INFO: DEMO: isUpdated is false... +21:56.495 INFO: DEMO: Callback Context for DISCOVER query recvd successfully +21:56.495 INFO: DEMO: StackResult: OC_STACK_OK +21:56.495 INFO: DEMO: Device =============> Discovered @ 10.0.2.15:37942 +21:56.495 INFO: DEMO: Payload Type: Discovery +21:56.495 INFO: DEMO: Resource #1 +21:56.495 INFO: DEMO: URI:/a/light +21:56.495 INFO: DEMO: SID: +21:56.495 INFO: DEMO: F0 5A 6C 8B 59 66 48 89 BE 1E 4E EF FA 23 4E FD +21:56.495 INFO: DEMO: Resource Types: +21:56.495 INFO: DEMO: core.light +21:56.495 INFO: DEMO: Interfaces: +21:56.495 INFO: DEMO: oic.if.baseline +21:56.495 INFO: DEMO: Bitmap: 3 +21:56.495 INFO: DEMO: Secure?: true +21:56.495 INFO: DEMO: Port: 43910 +21:56.495 INFO: DEMO: +21:56.495 INFO: DEMO: Uri -- /a/light +21:56.495 INFO: DEMO: Secure -- YES +21:56.591 INFO: DEMO: Callback Context for DISCOVER query recvd successfully +21:56.591 INFO: DEMO: StackResult: OC_STACK_OK +21:56.591 INFO: DEMO: Device =============> Discovered @ 10.0.2.15:55808 +21:56.591 INFO: DEMO: Payload Type: Discovery +21:56.591 INFO: DEMO: Resource #1 +21:56.591 INFO: DEMO: URI:/a/door +21:56.591 INFO: DEMO: SID: +21:56.591 INFO: DEMO: E9 68 45 ED 5D E1 4A F3 86 31 FD 0E 5E 25 EB B3 +21:56.591 INFO: DEMO: Resource Types: +21:56.591 INFO: DEMO: core.door +21:56.591 INFO: DEMO: Interfaces: +21:56.591 INFO: DEMO: oic.if.baseline +21:56.591 INFO: DEMO: Bitmap: 3 +21:56.591 INFO: DEMO: Secure?: true +21:56.591 INFO: DEMO: Port: 41403 +21:56.591 INFO: DEMO: +21:56.591 INFO: DEMO: Uri -- /a/door +21:56.591 INFO: DEMO: Secure -- YES + +# If you can see /a/light discowered then this is success. +# Next you should enter g to start get request +# Enter address : 10.0.2.15:43910 +# Port you can find here +21:56.495 INFO: DEMO: URI:/a/light +21:56.495 INFO: DEMO: SID: +21:56.495 INFO: DEMO: F0 5A 6C 8B 59 66 48 89 BE 1E 4E EF FA 23 4E FD +21:56.495 INFO: DEMO: Resource Types: +21:56.495 INFO: DEMO: core.light +21:56.495 INFO: DEMO: Interfaces: +21:56.495 INFO: DEMO: oic.if.baseline +21:56.495 INFO: DEMO: Bitmap: 3 +21:56.495 INFO: DEMO: Secure?: true +21:56.495 INFO: DEMO: Port: 43910 + +# If you see this lines in output: +22:31.647 INFO: DEMO: Callback Context for GET query recvd successfully +22:31.647 INFO: DEMO: StackResult: OC_STACK_OK +22:31.647 INFO: DEMO: SEQUENCE NUMBER: 2 +22:31.647 INFO: DEMO: Payload Type: Representation +22:31.647 INFO: DEMO: Resource #1 +22:31.647 INFO: DEMO: URI:/a/light +22:31.647 INFO: DEMO: Resource Types: +22:31.647 INFO: DEMO: Interfaces: +22:31.647 INFO: DEMO: Values: +22:31.647 INFO: DEMO: brightness(int):0 +22:31.647 INFO: DEMO: =============> Get Response +# then certificate did not rejected with CRL +# if not then it did. diff --git a/resource/csdk/security/provisioning/ck_manager/sample/oic_svr_db_pt.json b/resource/csdk/security/provisioning/ck_manager/sample/oic_svr_db_pt.json new file mode 100644 index 0000000..49fb2a8 --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/oic_svr_db_pt.json @@ -0,0 +1,43 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad" + ], + "perms": 2, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlEMA=="] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/cred" + ], + "perms": 7, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlEMA=="] + } + ], + "pstat": { + "isop": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlEMA==", + "ch": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlEMA==", + "ownr": "YWRtaW5EZXZpY2VVVUlEMA==" + } +} diff --git a/resource/csdk/security/provisioning/ck_manager/sample/provisioningclient.c b/resource/csdk/security/provisioning/ck_manager/sample/provisioningclient.c new file mode 100644 index 0000000..466cfe9 --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/sample/provisioningclient.c @@ -0,0 +1,701 @@ +/****************************************************************** +* +* 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 +#include +#include + +#include "logger.h" +#include "oic_malloc.h" +#include "utlist.h" +#include "ocprovisioningmanager.h" +#include "secureresourceprovider.h" +#include "oxmjustworks.h" +#include "oic_string.h" +#include "securevirtualresourcetypes.h" +#include "cacommon.h" +#include "ck_manager.h" +#include "ckm_info.h" +#include "crlresource.h" + +#define MAX_URI_LENGTH (64) +#define MAX_PERMISSION_LENGTH (5) +#define CREATE (1) +#define READ (2) +#define UPDATE (4) +#define DELETE (8) +#define NOTIFY (16) +#define DASH '-' +#define PREDEFINED_TIMEOUT (10) +#define MAX_OWNED_DEVICE (10) +#define DATE_LENGTH (14) +#define TAG "provisioningclient" + +static OicSecAcl_t *gAcl = NULL; +static OicSecCrl_t *gCrl = NULL; +static char PROV_TOOL_DB_FILE[] = "oic_svr_db_pt.json"; +static int gOwnershipState = 0; + +typedef enum +{ + ownershipDone = 1 << 1, + finalizeDone = 1 << 2, + provisionAclDone = 1 << 3, + provisionCert1Done = 1 << 4, + provisionCert2Done = 1 << 5, + provisionCrlDone = 1 << 6 +} StateManager; + + +/** + * Perform cleanup for ACL + * @param[in] ACL + */ +static void deleteACL(OicSecAcl_t *acl) +{ + if (acl) + { + /* Clean Resources */ + for (size_t i = 0; i < (acl)->resourcesLen; i++) + { + OICFree((acl)->resources[i]); + } + OICFree((acl)->resources); + + /* Clean Owners */ + OICFree((acl)->owners); + + /* Clean ACL node itself */ + OICFree((acl)); + + acl = NULL; + } +} + +void deleteCrl(OicSecCrl_t *crl) +{ + if (crl) + { + //Clean ThisUpdate + OICFree(crl->ThisUpdate.data); + + //clean CrlData + OICFree(crl->CrlData.data); + + //Clean crl itself + OICFree(crl); + } +} + +/** + * Calculate ACL permission from string to bit + * + * @param[in] temp_psm Input data of ACL permission string + * @param[in,out] pms The pointer of ACL permission value + * @return 0 on success otherwise -1. + */ +static int CalculateAclPermission(const char *temp_pms, uint16_t *pms) +{ + int i = 0; + + if (NULL == temp_pms || NULL == pms) + { + return -1; + } + *pms = 0; + while (temp_pms[i] != '\0') + { + switch (temp_pms[i]) + { + case 'C': + { + *pms += CREATE; + i++; + break; + } + case 'R': + { + *pms += READ; + i++; + break; + } + case 'U': + { + *pms += UPDATE; + i++; + break; + } + case 'D': + { + *pms += DELETE; + i++; + break; + } + case 'N': + { + *pms += NOTIFY; + i++; + break; + } + case '_': + { + i++; + break; + } + default: + { + return -1; + } + } + } + return 0; +} + +/** + * Get the ACL property from user + * + * @param[in] ACL Datastructure to save user inputs + * @return 0 on success otherwise -1. + */ +static int InputACL(OicSecAcl_t *acl) +{ + int ret; + char temp_id [UUID_LENGTH + 4] = {0,}; + char temp_rsc[MAX_URI_LENGTH + 1] = {0,}; + char temp_pms[MAX_PERMISSION_LENGTH + 1] = {0,}; + printf("******************************************************************************\n"); + printf("-Set ACL policy for target device\n"); + printf("******************************************************************************\n"); + //Set Subject. + printf("-URN identifying the subject\n"); + printf("ex) doorDeviceUUID00 (16 Numbers except to '-')\n"); + printf("Subject : "); + char *ptr = NULL; + ret = scanf("%19ms", &ptr); + if(1==ret) + { + OICStrcpy(temp_id, sizeof(temp_id), ptr); + OICFree(ptr); + } + else + { + printf("Error while input\n"); + return -1; + } + int j = 0; + for (int i = 0; temp_id[i] != '\0'; i++) + { + if (DASH != temp_id[i]) + { + if(j>UUID_LENGTH) + { + printf("Invalid input\n"); + return -1; + } + acl->subject.id[j++] = temp_id[i]; + } + } + + //Set Resource. + printf("Num. of Resource : \n"); + ret = scanf("%zu", &acl->resourcesLen); + printf("-URI of resource\n"); + printf("ex) /a/light (Max_URI_Length: 64 Byte )\n"); + acl->resources = (char **)OICCalloc(acl->resourcesLen, sizeof(char *)); + if (NULL == acl->resources) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + return -1; + } + for (size_t i = 0; i < acl->resourcesLen; i++) + { + printf("[%zu]Resource : ", i + 1); + char *ptr_tempRsc = NULL; + ret = scanf("%64ms", &ptr_tempRsc); + if (1==ret) + { + OICStrcpy(temp_rsc, sizeof(temp_rsc), ptr_tempRsc); + OICFree(ptr_tempRsc); + } + else + { + printf("Error while input\n"); + return -1; + } + acl->resources[i] = OICStrdup(temp_rsc); + + if (NULL == acl->resources[i]) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + return -1; + } + } + // Set Permission + do + { + printf("-Set the permission(C,R,U,D,N)\n"); + printf("ex) CRUDN, CRU_N,..(5 Charaters)\n"); + printf("Permission : "); + char *ptr_temp_pms = NULL; + ret = scanf("%5ms", &ptr_temp_pms); + if(1 == ret) + { + OICStrcpy(temp_pms, sizeof(temp_pms), ptr_temp_pms); + OICFree(ptr_temp_pms); + + } + else + { + printf("Error while input\n"); + return -1; + } + } + while (0 != CalculateAclPermission(temp_pms, &(acl->permission)) ); + // Set Rowner + printf("Num. of Rowner : "); + ret = scanf("%zu", &acl->ownersLen); + printf("-URN identifying the rowner\n"); + printf("ex) lightDeviceUUID0 (16 Numbers except to '-')\n"); + acl->owners = (OicUuid_t *)OICCalloc(acl->ownersLen, sizeof(OicUuid_t)); + if (NULL == acl->owners) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + return -1; + } + for (size_t i = 0; i < acl->ownersLen; i++) + { + printf("[%zu]Rowner : ", i + 1); + char *ptr_temp_id = NULL; + ret = scanf("%19ms", &ptr_temp_id); + if (1 == ret) + { + OICStrcpy(temp_id, sizeof(temp_id), ptr_temp_id); + OICFree(ptr_temp_id); + } + else + { + printf("Error while input\n"); + return -1; + } + j = 0; + for (int k = 0; temp_id[k] != '\0'; k++) + { + if (DASH != temp_id[k]) + { + acl->owners[i].id[j++] = temp_id[k]; + } + } + } + return 0; +} + + +//FILE *client_fopen(const char *path, const char *mode) +FILE *client_fopen(const char* UNUSED_PARAM , const char *mode) +{ + (void)UNUSED_PARAM; + return fopen(PROV_TOOL_DB_FILE, mode); +} + +void PrintfResult(const char* procName, void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + printf("-----------------------------------------------------------\n"); + if(!hasError) + { + printf("%s was successfully done.\n", procName); + } + else + { + for(int i = 0; i < nOfRes; i++) + { + printf("UUID : "); + for(int j = 0; j < UUID_LENGTH; j++) + { + printf("%c", arr[i].deviceId.id[j]); + } + printf("\t"); + printf("Result=%d\n", arr[i].res); + } + } + + if(ctx) + { + printf("Context is %s\n", (char*)ctx); + } + printf("-----------------------------------------------------------\n"); +} + +void ProvisionCertCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Provision Credential", ctx, nOfRes, arr, hasError); + } + else printf("Cert provisioning error\n-----------------------------------------"); +} + +void ProvisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Provision ACL", ctx, nOfRes, arr, hasError); + } +} + +void ProvisionCrlCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Provision CRL", ctx, nOfRes, arr, hasError); + } +} + + + +void OwnershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Ownership transfer", ctx, nOfRes, arr, hasError); + } +} + +static short IsCKMInfoFileExists() +{ + FILE *ckmInf = fopen(CA_STORAGE_FILE, "r"); + if (NULL != ckmInf) + { + fclose(ckmInf); + return 1; + } + return 0; +} + +static PKIError InitCA() +{ + FUNCTION_INIT(); + + if (IsCKMInfoFileExists()) + { + CHECK_CALL(InitCKMInfo); + } + else + { + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + ByteArray CAPubKey = BYTE_ARRAY_INITIALIZER; + ByteArray CAPrivKey = BYTE_ARRAY_INITIALIZER; + ByteArray rootCert = BYTE_ARRAY_INITIALIZER; + + + uint8_t rootCertData[ISSUER_MAX_CERT_SIZE]; + uint8_t CAPubKeyData[PUBLIC_KEY_SIZE]; + uint8_t CAPrivKeyData[PRIVATE_KEY_SIZE]; + const char rootNameStr[] = "Sample_Root"; + + CAPubKey.data = CAPubKeyData; + CAPubKey.len = PUBLIC_KEY_SIZE; + CAPrivKey.data = CAPrivKeyData; + CAPrivKey.len = PRIVATE_KEY_SIZE; + rootCert.data = rootCertData; + rootCert.len = ISSUER_MAX_CERT_SIZE; + rootName.data = (uint8_t *)rootNameStr; + rootName.len = strlen(rootNameStr); + + CHECK_CALL(SetRootName, rootName); + CHECK_CALL(GenerateCAKeyPair, &CAPrivKey, &CAPubKey); + CHECK_CALL(SetSerialNumber, 1); + CHECK_CALL(CKMIssueRootCertificate, NULL, NULL, &rootCert); + CHECK_CALL(SetCACertificate, &rootCert); + } + + FUNCTION_CLEAR(); +} + +static int InputCRL(OicSecCrl_t *crlRes) +{ + FUNCTION_INIT( + ByteArray crl = BYTE_ARRAY_INITIALIZER; + ); + + const int MAX_Revoked_NUMBER = 9; + uint8_t uint8ThisUpdateTime[DATE_LENGTH] = "130101000005Z"; + uint32_t revokedNumbers[MAX_Revoked_NUMBER]; + const uint8_t* revocationDates[MAX_Revoked_NUMBER]; + // const uint8_t revocationDatesContent[MAX_Revoked_NUMBER][DATE_LENGTH]; + uint32_t nuberOfRevoked = 0; + printf("Enter number of Revoked certificates(1..%d)\n", MAX_Revoked_NUMBER); + scanf("%u", &nuberOfRevoked); + + for (size_t i = 0; i < nuberOfRevoked; ++i) + { + printf("Revoked certificate %d:", i); + printf("Serial number (E. g.: 100):"); + scanf("%u", &revokedNumbers[i]); + revocationDates[i] = (const uint8_t*)"130101000005Z"; + } + + crl.len = CRL_MIN_SIZE + nuberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4)/* + 1000*/; + crl.data = (uint8_t *)OICCalloc(1, crl.len); + + CHECK_CALL(CKMIssueCRL, uint8ThisUpdateTime, nuberOfRevoked, revokedNumbers, + revocationDates, &crl); + PRINT_BYTE_ARRAY("CRL:\n",crl); + CHECK_CALL(SetCertificateRevocationList, &crl); + crlRes->CrlData = crl; + crlRes->ThisUpdate.data = uint8ThisUpdateTime; + crlRes->ThisUpdate.len = DATE_LENGTH; + crlRes->CrlId = 1; + + + FUNCTION_CLEAR( + //OICFree(crl.data); + ); +} + + +/** + * Provisioning client sample using ProvisioningAPI + */ +int main() +{ + OCStackResult res = OC_STACK_OK; + + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = { .open = client_fopen, + .read = fread, + .write = fwrite, + .close = fclose, + .unlink = unlink}; + + OCRegisterPersistentStorageHandler(&ps); + + if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER)) + { + OC_LOG(ERROR, TAG, "OCStack init error"); + goto error; + } + + OCProvisionDev_t* pDeviceList = NULL; + res = OCDiscoverUnownedDevices(PREDEFINED_TIMEOUT, &pDeviceList); + if(OC_STACK_OK != res) + { + OC_LOG_V(ERROR, TAG, "Failed to PMDeviceDiscovery : %d", res); + goto error; + } + + OCProvisionDev_t* pCurDev = pDeviceList; + int i; + while(pCurDev !=NULL) + { + for(i = 0; i < UUID_LENGTH; i++) + { + printf("%c", pCurDev->doxm->deviceID.id[i]); + } + printf("\n"); + pCurDev = pCurDev->next; + } + + //Register callback function to each OxM + OTMCallbackData_t justWorksCBData = {.loadSecretCB=NULL, + .createSecureSessionCB=NULL, + .createSelectOxmPayloadCB=NULL, + .createOwnerTransferPayloadCB=NULL}; + justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback; + justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback; + justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload; + justWorksCBData.createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload; + OTMSetOwnershipTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData); + + char* myContext = "OTM Context"; + //Perform ownership transfer + res = OCDoOwnershipTransfer((void*)myContext, pDeviceList, OwnershipTransferCB); + if(OC_STACK_OK == res) + { + OC_LOG(INFO, TAG, "Request for ownership transfer is sent successfully."); + } + else + { + OC_LOG_V(ERROR, TAG, "Failed to OCDoOwnershipTransfer : %d", res); + } + + gOwnershipState = 0; + while (gOwnershipState == 0) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); + } + +// Credential & ACL provisioning between two devices. + + OCProvisionDev_t *pOwnedList = NULL; + OCProvisionDev_t *pOwnedDevices [MAX_OWNED_DEVICE] = {0,}; + int nOwnedDevice = 0; + + res = OCDiscoverOwnedDevices(PREDEFINED_TIMEOUT, &pOwnedList); + if (OC_STACK_OK == res) + { + printf("################## Owned Device List #######################\n"); + while (pOwnedList != NULL) + { + nOwnedDevice ++; + printf(" %d : ", nOwnedDevice); + for (int i = 0; i < UUID_LENGTH; i++) + { + printf("%c", pOwnedList->doxm->deviceID.id[i]); + } + printf("\n"); + pOwnedDevices[nOwnedDevice] = pOwnedList; + pOwnedList = pOwnedList->next; + } + } + else + { + OC_LOG(ERROR, TAG, "Error while Owned Device Discovery"); + } + + int Device1 = 0; + int Device2 = 0; + + printf("Select 2 devices for Credential & ACL provisioning\n"); + printf("Device 1: "); + scanf("%d", &Device1); + printf("Device 2: "); + scanf("%d", &Device2); + + + gAcl = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t)); + if (NULL == gAcl) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + goto error; + } + + if (PKI_SUCCESS != InitCA()) + { + OC_LOG(ERROR, TAG, "CA init error"); + goto error; + } + + + char *ctx = "DUMMY"; + + res = OCProvisionCredentials(ctx, SIGNED_ASYMMETRIC_KEY, 0, pOwnedDevices[Device1], + NULL, ProvisionCertCB); + if (OC_STACK_OK != res) OC_LOG_V(ERROR, TAG, "Failed to provision Device 1 : %d", res); + gOwnershipState = 0; + while ( gOwnershipState == 0 ) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); + } + + res = OCProvisionCredentials(ctx, SIGNED_ASYMMETRIC_KEY, 0, pOwnedDevices[Device2], + NULL, ProvisionCertCB); + if (OC_STACK_OK != res) + { + OC_LOG_V(ERROR, TAG, "Failed to provision Device 2 : %d", res); + } + + gOwnershipState = 0; + while (gOwnershipState == 0) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); + } + + printf("Input ACL for Device2\n"); + if (0 == InputACL(gAcl)) + { + printf("Success Input ACL\n"); + } + else + { + OC_LOG(ERROR, TAG, "InputACL error"); + goto error; + } + res = OCProvisionACL(ctx, pOwnedDevices[Device2], gAcl, &ProvisionAclCB); + if (OC_STACK_OK != res) + { + OC_LOG_V(ERROR, TAG, "Failed to ACL provision Device 2 : %d", res); + } + + gOwnershipState = 0; + while (gOwnershipState == 0) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); + } + gCrl = (OicSecCrl_t *)OICMalloc(sizeof(OicSecCrl_t)); + if (PKI_SUCCESS != InputCRL(gCrl)) + { + OC_LOG(ERROR, TAG, "CA init error"); + goto error; + } + + PRINT_BYTE_ARRAY("gCrl = \n", gCrl->CrlData); + + + res = OCProvisionCRL(ctx, pOwnedDevices[Device2], gCrl, &ProvisionCrlCB); + if (OC_STACK_OK != res) OC_LOG_V(ERROR, TAG, "Failed to CRL provision Device 2 : %d", res); + + gOwnershipState = 0; + while (gOwnershipState == 0) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); + } + + if (OCStop() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + +error: + deleteACL(gAcl); + OCDeleteDiscoveredDevices(&pDeviceList); + OCDeleteDiscoveredDevices(&pOwnedList); + + return 0; +} diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/pki_test.cpp b/resource/csdk/security/provisioning/ck_manager/unittest/pki_test.cpp new file mode 100644 index 0000000..e2dc42d --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/unittest/pki_test.cpp @@ -0,0 +1,968 @@ +/****************************************************************** + * + * 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 + * + * LICENSE-2.0" target="_blank">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 +#include +#include +#include "ocstack.h" + +#include "cert_generator.h" +#include "ck_manager.h" +#include "pki.h" +#include "sn_store.h" +#include "der_dec.h" +#include "crl.h" +#include "crl_generator.h" +#include "crlresource.h" +#include "ckm_info.h" + + +#define RUNS 1 +#define MAX_LEN 1000 +#define TEST_SN 50 +#define READ_WRITE_BLOCK_N 1ul +#define N_LENGTH_BYTES 3 + +const char *CKMI_JSON_FILE_NAME = "CKMInfo.json"; + +#define CRL_DEFAULT_CRL_ID 1 +#define CRL_DEFAULT_THIS_UPDATE "150101000000Z" +#define CRL_DEFAULT_CRL_DATA "-" + +#define NUMBER_OF_REVOKED 2 + +OCPersistentStorage ps = { NULL, NULL, NULL, NULL, NULL}; + +//#define NUM_ACE_FOR_WILDCARD_IN_CKM1_JSON (2) + +FILE* ckm_fopen(const char * /*path*/, const char *mode) +{ + return fopen(CKMI_JSON_FILE_NAME, mode); +} + +void SetPersistentHandler(OCPersistentStorage *ps) +{ + if(ps) + { + ps->open = ckm_fopen; + ps->read = fread; + ps->write = fwrite; + ps->close = fclose; + ps->unlink = unlink; + } +} + +// Length of test certificate +#define SIMPLE_CRT_LEN 469 + +class PKITest : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + SetPersistentHandler(&ps); + OCStackResult res = OCRegisterPersistentStorageHandler(&ps); + ASSERT_TRUE(res == OC_STACK_OK); + } + + static void TearDownTestCase() + { + } + + static CertificateX509 g_certificate; + + static const ByteArray g_caPublicKey; + + static const ByteArray g_derCode ; + + static ByteArray g_serNum; +}; + +CertificateX509 PKITest::g_certificate; + +const ByteArray PKITest::g_derCode = {(uint8_t[]) + { + 0x30, 0x82, 0x01, 0xd1, 0x30, 0x82, 0x01, 0x77, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0xd7, 0x56, 0x8c, 0xfc, 0x53, 0x18, 0xb0, 0xab, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x02, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, + 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, + 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x35, 0x30, 0x33, 0x31, 0x32, 0x31, 0x32, 0x32, 0x35, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x37, + 0x30, 0x33, 0x31, 0x31, 0x31, 0x32, 0x32, 0x35, 0x31, 0x31, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, + 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, + 0x74, 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x8c, 0xc8, 0x92, + 0x1d, 0xaa, 0x7f, 0xf0, 0xe4, 0xb2, 0x75, 0xd6, 0x4a, 0xf1, 0xd5, 0x14, 0x3f, 0x1a, 0x09, 0xc5, + 0x3e, 0x52, 0xd6, 0xda, 0xa0, 0xbf, 0x90, 0x43, 0xd1, 0x6b, 0xfe, 0xd1, 0xb3, 0x75, 0x5c, 0xdd, + 0x69, 0xac, 0x42, 0xa1, 0xcb, 0x03, 0x16, 0xee, 0xa4, 0x30, 0xa5, 0x8d, 0x36, 0x8f, 0xc5, 0x7b, + 0xb4, 0xb5, 0x6a, 0x7d, 0x9b, 0x16, 0x04, 0x46, 0xab, 0xae, 0xbb, 0x56, 0xa1, 0xa3, 0x50, 0x30, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x5c, 0x0e, 0x30, 0xa8, + 0x8e, 0x7f, 0xc9, 0x02, 0xcd, 0xa8, 0xed, 0x0d, 0x1a, 0x1b, 0xd9, 0x7d, 0xe6, 0xce, 0x2a, 0x59, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x5c, 0x0e, 0x30, + 0xa8, 0x8e, 0x7f, 0xc9, 0x02, 0xcd, 0xa8, 0xed, 0x0d, 0x1a, 0x1b, 0xd9, 0x7d, 0xe6, 0xce, 0x2a, + 0x59, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, + 0x02, 0x21, 0x00, 0xf6, 0x79, 0xed, 0x69, 0xd5, 0xe5, 0xba, 0x42, 0x14, 0xfc, 0xce, 0x47, 0xf1, + 0x61, 0x1c, 0x51, 0x11, 0x2b, 0xba, 0x04, 0x70, 0x56, 0x78, 0xaf, 0xa9, 0xa6, 0x98, 0x8f, 0x4b, + 0xa8, 0x11, 0x67, 0x02, 0x20, 0x3a, 0xdf, 0xf1, 0x74, 0xc9, 0x2f, 0xfb, 0x84, 0x46, 0xde, 0xbc, + 0x2d, 0xda, 0xe3, 0x05, 0xb4, 0x81, 0x31, 0x45, 0xf7, 0x3d, 0x71, 0x46, 0x07, 0xa7, 0xd8, 0xcb, + 0xae, 0x1e, 0x1b, 0x1c, 0x5a + }, SIMPLE_CRT_LEN }; + + +const ByteArray PKITest::g_caPublicKey = {(uint8_t[]) +{ + 0x8c, 0xc8, 0x92, 0x1d, 0xaa, 0x7f, 0xf0, 0xe4, 0xb2, 0x75, 0xd6, 0x4a, 0xf1, 0xd5, 0x14, 0x3f, + 0x1a, 0x09, 0xc5, 0x3e, 0x52, 0xd6, 0xda, 0xa0, 0xbf, 0x90, 0x43, 0xd1, 0x6b, 0xfe, 0xd1, 0xb3, + 0x75, 0x5c, 0xdd, 0x69, 0xac, 0x42, 0xa1, 0xcb, 0x03, 0x16, 0xee, 0xa4, 0x30, 0xa5, 0x8d, 0x36, + 0x8f, 0xc5, 0x7b, 0xb4, 0xb5, 0x6a, 0x7d, 0x9b, 0x16, 0x04, 0x46, 0xab, 0xae, 0xbb, 0x56, 0xa1 +}, PUBLIC_KEY_SIZE }; + + +ByteArray PKITest::g_serNum = {(uint8_t[SERIAL_NUMBER_MAX_LEN]) {0}, SERIAL_NUMBER_MAX_LEN}; + +//registering persistent storage test +TEST(CKManager, RegisterPersistentStorage) +{ + SetPersistentHandler(&ps); + ASSERT_EQ(OC_STACK_OK, OCRegisterPersistentStorageHandler(&ps)); +} + +//check decoding predefined certificate +TEST(X509Certificate, DecodeTest) +{ + ByteArray code = PKITest::g_derCode; + + ASSERT_EQ(DecodeCertificate(code, &PKITest::g_certificate), PKI_SUCCESS); + code.data = NULL; + ASSERT_NE(DecodeCertificate(code, &PKITest::g_certificate), PKI_SUCCESS); +} + +//check decoding of random symbols sequence +TEST(X509Certificate, RandomDecode) +{ + srand((unsigned int)time(NULL)); + + ByteArray code; + INIT_BYTE_ARRAY(code); + + for (unsigned int i = 0; i < RUNS; i++) + { + code.len = rand() % MAX_LEN; + code.data = (uint8_t *)malloc(code.len * sizeof(uint8_t)); + + EXPECT_NE(code.data, (uint8_t *)NULL); + + for (unsigned int j = 0; j < code.len; j++) + { + code.data[j] = (uint8_t)(rand() % 128 + 1); + } + + EXPECT_NE(PKI_SUCCESS, DecodeCertificate(code, &PKITest::g_certificate)); + + free(code.data); + } +} +//testing validity check of predefined certificate +TEST(X509Certificate, testCheckValidity) +{ + CertificateX509 tempCrt; + ASSERT_EQ(PKI_SUCCESS, DecodeCertificate(PKITest::g_derCode, &tempCrt)); + ASSERT_EQ(PKI_SUCCESS, CheckValidity(tempCrt.validFrom, tempCrt.validTo)); + ByteArray temp = tempCrt.validTo; + + tempCrt.validTo = tempCrt.validFrom; + tempCrt.validFrom = temp; + ASSERT_EQ(PKI_CERT_DATE_INVALID, CheckValidity(tempCrt.validFrom, tempCrt.validTo)); +} + +//testing signature check of predefined certificate +TEST(X509Certificate, CheckSignature) +{ + ByteArray code = PKITest::g_derCode; + + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(code, PKITest::g_caPublicKey)); + code.data = NULL; + ASSERT_NE(PKI_SUCCESS, CheckCertificate(code, PKITest::g_caPublicKey)); +} + +//test saving certificate into file +TEST_F(PKITest, DERCertificateFile) +{ + uint8_t derData[ISSUER_MAX_CERT_SIZE] = {0}; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + + ByteArray certDer = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + certDer.data = derData; + certDer.len = ISSUER_MAX_CERT_SIZE; + + pubKeyIss.data = caPubKey; + pubKeyIss.len = sizeof(caPubKey); + privKeyIss.data = caPrivKey; + privKeyIss.len = sizeof(caPrivKey); + rootName.data = (uint8_t *)"ROOT1"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + + for (int i = 1; i <= RUNS; i++) + { + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKeyIss, &pubKeyIss)); + ASSERT_EQ(PKI_SUCCESS, SetSerialNumber(i)); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + ASSERT_EQ(PKI_SUCCESS, CKMIssueRootCertificate(0, 0, &certDer)); + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + ASSERT_EQ(PKI_SUCCESS, GenerateDERCertificateFile (&certDer, "der_cert")); + } + ASSERT_EQ(CloseCKMInfo(), PKI_SUCCESS); +} + +//test checking time validity of generated certificate +TEST_F(PKITest, TimeValidity) +{ + uint8_t derData[ISSUER_MAX_CERT_SIZE] = {0}; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + + ByteArray certDer = BYTE_ARRAY_INITIALIZER; + ByteArray pubKey = BYTE_ARRAY_INITIALIZER; + ByteArray privKey = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + privKey.data = caPrivKey; + privKey.len = sizeof(caPrivKey); + + certDer.data = derData; + certDer.len = sizeof(derData); + + pubKey.data = caPubKey; + pubKey.len = sizeof(caPubKey); + + rootName.data = (uint8_t *)"ROOT3"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + + for (int i = 1; i <= RUNS; i++) + { + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKey, &pubKey)); + ASSERT_EQ(PKI_SUCCESS, SetSerialNumber(i)); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + + ASSERT_EQ(PKI_SUCCESS, CKMIssueRootCertificate(0, 0, &certDer)); + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKey)); + + certDer.len = sizeof(derData); + ASSERT_EQ(PKI_SUCCESS, CKMIssueRootCertificate(0, (uint8_t *)"130101000000Z", &certDer)); + ASSERT_EQ(PKI_CERT_DATE_INVALID, CheckCertificate(certDer, pubKey)); + + certDer.len = sizeof(derData); + ASSERT_EQ(PKI_SUCCESS, CKMIssueRootCertificate((uint8_t *)"160101000000Z", 0, &certDer)); + ASSERT_EQ(PKI_CERT_DATE_INVALID, CheckCertificate(certDer, pubKey)); + } + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//testing certificate generation by certificate signing request +TEST_F(PKITest, CertificateSigningRequest) +{ + uint8_t certData[ISSUER_MAX_CERT_SIZE] = {0}; + uint8_t csrData[CSR_MAX_SIZE] = {0}; + uint8_t subjPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t subjPrivKey[PRIVATE_KEY_SIZE] = {0}; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + uint8_t *subjName = (uint8_t *)"Subject05"; + + ByteArray certDer = BYTE_ARRAY_INITIALIZER; + ByteArray csrDer = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeySubj = BYTE_ARRAY_INITIALIZER; + ByteArray privKeySubj = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + certDer.data = certData; + certDer.len = sizeof(certData); + csrDer.data = csrData; + csrDer.len = CSR_MAX_SIZE; + + pubKeyIss.data = caPubKey; + pubKeyIss.len = sizeof(caPubKey); + privKeyIss.data = caPrivKey; + privKeyIss.len = sizeof(caPrivKey); + pubKeySubj.data = subjPubKey; + pubKeySubj.len = sizeof(subjPubKey); + privKeySubj.data = subjPrivKey; + privKeySubj.len = sizeof(subjPrivKey); + rootName.data = (uint8_t *)"ROOT2"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + + ASSERT_EQ(GenerateCAKeyPair(&privKeyIss, &pubKeyIss), PKI_SUCCESS); + ASSERT_EQ(SetSerialNumber(1), PKI_SUCCESS); + ASSERT_EQ(SetRootName(rootName), PKI_SUCCESS); + + for (int i = 1; i <= RUNS; i++) + { + ASSERT_EQ(PKI_SUCCESS, GenerateKeyPair(&privKeySubj, &pubKeySubj)); + ASSERT_EQ(PKI_SUCCESS, GenerateCSR(subjName, subjPubKey, subjPrivKey, &csrDer)); + ASSERT_EQ(PKI_SUCCESS, GenerateCertificateByCSR(&csrDer, &certDer)); + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + certDer.data[0]++; + ASSERT_NE(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + certDer.data[0]--; + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + } + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//test public key structure parsing +TEST(X509Certificate, testParsePublicKey) +{ + ASSERT_EQ(PKI_SUCCESS, ParsePublicKey((ByteArray*)&PKITest::g_caPublicKey)); + + size_t length = 3; + uint8_t shortAr[length]; + ByteArray shortArray = {shortAr, length}; + ASSERT_EQ(PKI_WRONG_ARRAY_LEN, ParsePublicKey(&shortArray)); + + uint8_t uncompressed[PUBLIC_KEY_SIZE + 2]; + uncompressed[0] = 0; + uncompressed[1] = ASN1_UNCOMPRESSED_KEY; + memcpy(&uncompressed[2], PKITest::g_caPublicKey.data, PUBLIC_KEY_SIZE); + ByteArray uncomprArr = {uncompressed, PUBLIC_KEY_SIZE+2}; + ParsePublicKey(&uncomprArr); + ASSERT_EQ((size_t)PUBLIC_KEY_SIZE, uncomprArr.len); + ASSERT_EQ(0, memcmp(uncomprArr.data, PKITest::g_caPublicKey.data, PUBLIC_KEY_SIZE)); +} + +//test checking of certificate generated by OpenSSL +TEST(OpenSSLCompatibility, verifyOpenSslCertSign) +{ + ByteArray crtDer = BYTE_ARRAY_INITIALIZER; + CertificateX509 certificate; + + FILE *fileCert = fopen("01.der", "rb"); + ASSERT_TRUE(fileCert != NULL); + + //get the length + fseek(fileCert, 0, SEEK_END); + crtDer.len = ftell(fileCert); + fseek(fileCert, 0, SEEK_SET); + //allocate memory + crtDer.data = (uint8_t*)malloc(crtDer.len+1); + //read the content + EXPECT_EQ(READ_WRITE_BLOCK_N, fread(crtDer.data, crtDer.len, READ_WRITE_BLOCK_N, fileCert)); + fclose(fileCert); + + ByteArray pubKey = BYTE_ARRAY_INITIALIZER; + FILE * fileKey = fopen("capub.der", "rb"); + ASSERT_TRUE(fileKey != NULL); + fseek(fileKey, 0, SEEK_END); + pubKey.len = ftell(fileKey); + fseek(fileKey, 0, SEEK_SET); + //openssl generates a public key that is longer than 64 bytes + //with additional 27 bytes prepending the actual key + if(pubKey.len > PUBLIC_KEY_SIZE){ + fseek(fileKey, (pubKey.len - PUBLIC_KEY_SIZE), SEEK_SET); + pubKey.len = PUBLIC_KEY_SIZE; + } + pubKey.data = (uint8_t*)malloc(pubKey.len+1); + //read the content + EXPECT_EQ(READ_WRITE_BLOCK_N, fread(pubKey.data, pubKey.len, READ_WRITE_BLOCK_N, fileKey)); + fclose(fileKey); + + EXPECT_EQ(PKI_SUCCESS, DecodeCertificate(crtDer, &certificate)); + EXPECT_EQ(PKI_SUCCESS, CheckCertificate(crtDer, pubKey)); + + free(crtDer.data); + free(pubKey.data); +} + +//test parsing of certificate chain generated by OpenSSL +TEST(CertificateChain, LoadCertificateChain) +{ + ByteArray crtChainDer[MAX_CHAIN_LEN] = {{0,0},}; + CertificateX509 crtChain[MAX_CHAIN_LEN] = {{{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},}; + ByteArray msg = BYTE_ARRAY_INITIALIZER; + uint8_t chainLength; + + FILE *file = fopen("cert_chain.dat", "rb"); + + ASSERT_TRUE(file != NULL); + + while (!feof (file)) + { + msg.data = (uint8_t *) realloc (msg.data, msg.len + 1); + msg.data[msg.len] = fgetc (file); + msg.len++; + } + msg.len--; + fclose (file); + INC_BYTE_ARRAY(msg, 3); + EXPECT_EQ(PKI_SUCCESS, LoadCertificateChain (msg, crtChainDer, &chainLength)); +#ifdef X509_DEBUG + printf("chain len: %d\n", chainLength); +#endif + EXPECT_EQ(PKI_UNKNOWN_OID, ParseCertificateChain (crtChainDer, crtChain, chainLength)); + + free(msg.data - 3); +} + +//test checking CA certificate generated by OpenSSL +TEST(OpenSSLCompatibility, testOpenSSLCertificate) +{ + ByteArray crtDer = BYTE_ARRAY_INITIALIZER; + FILE *fileCert = fopen("cacert.der", "rb"); + ASSERT_TRUE(fileCert != NULL); + + //get the length + fseek(fileCert, 0, SEEK_END); + crtDer.len = ftell(fileCert); + fseek(fileCert, 0, SEEK_SET); + //allocate memory + crtDer.data = (uint8_t*)malloc(crtDer.len+1); + //read the content + EXPECT_EQ(READ_WRITE_BLOCK_N, fread(crtDer.data, crtDer.len, READ_WRITE_BLOCK_N, fileCert)); + + fclose(fileCert); + #ifdef X509_DEBUG + printf("Length of cert: %lu\n", crtDer.len); + #endif + EXPECT_EQ(PKI_SUCCESS, DecodeCertificate(crtDer, &PKITest::g_certificate)); + free(crtDer.data); +} + +//test signatures checking of certificate chain generated by OpenSSL +TEST(OpenSSLCompatibility, ParseAndCheckCertificateChain) +{ + ByteArray crtChainDer[MAX_CHAIN_LEN] = {{0,0},}; + CertificateX509 crtChain[MAX_CHAIN_LEN] = {{{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},}; + ByteArray msg = BYTE_ARRAY_INITIALIZER; + uint8_t chainLength; + + const char* chainPath = {"chain.der"}; + FILE *fileChain = fopen(chainPath, "rb"); + ASSERT_TRUE(fileChain != NULL); + + //get the length + fseek(fileChain, 0, SEEK_END); + msg.len = ftell(fileChain); + fseek(fileChain, 0, SEEK_SET); + //allocate memory + msg.data = (uint8_t*)malloc(msg.len+1); + //read the content + EXPECT_EQ(READ_WRITE_BLOCK_N, fread(msg.data, msg.len, READ_WRITE_BLOCK_N, fileChain)); + + fclose (fileChain); + + INC_BYTE_ARRAY(msg, 3); + EXPECT_EQ(PKI_SUCCESS, LoadCertificateChain(msg, crtChainDer, &chainLength)); + EXPECT_EQ(3, chainLength); + #ifdef X509_DEBUG + printf("Length of the chain: %d\n", chainLength); + #endif + + EXPECT_EQ(PKI_SUCCESS, ParseCertificateChain(crtChainDer, crtChain, chainLength)); + + ByteArray caPubKey = BYTE_ARRAY_INITIALIZER; + + const char* caPubKeyPath = {"capub.der"}; + FILE *fileCaPubKey = fopen(caPubKeyPath, "rb"); + ASSERT_TRUE(fileCaPubKey != NULL); + + fseek(fileCaPubKey, 0, SEEK_END); + caPubKey.len = ftell(fileCaPubKey); + fseek(fileCaPubKey, 0, SEEK_SET); + if(caPubKey.len > PUBLIC_KEY_SIZE){ + fseek(fileCaPubKey, (caPubKey.len - PUBLIC_KEY_SIZE), SEEK_SET); + caPubKey.len = PUBLIC_KEY_SIZE; + } + caPubKey.data = (uint8_t*)malloc(caPubKey.len+1); + //read the content + EXPECT_EQ(READ_WRITE_BLOCK_N, fread(caPubKey.data, caPubKey.len, READ_WRITE_BLOCK_N, fileCaPubKey)); + fclose(fileCaPubKey); + + EXPECT_EQ(PKI_SUCCESS, CheckCertificateChain(crtChain, chainLength, caPubKey)); + + free(msg.data - 3); + free(caPubKey.data); +} + +//testing correctness of decoding certificate length from ASN.1 structure +TEST(CRL, testDecodeLength) +{ + ByteArray cert = BYTE_ARRAY_INITIALIZER; + size_t length(0); + EXPECT_EQ(PKI_NULL_PASSED, DecodeLength(&cert, &length)); + + //a simple DER + size_t derLength = (size_t)rand() % LEN_LONG; + cert.len = derLength + 2; + uint8_t *certData = (uint8_t*)malloc(cert.len); + cert.data = certData; + cert.data[0] = (uint8_t)0x30; //mixed types + cert.data[1] = (uint8_t)(derLength & 0xff); + EXPECT_EQ(PKI_SUCCESS, DecodeLength(&cert, &length)); + EXPECT_EQ(derLength, length); + free(certData); +} + +//testing serial number storage +TEST(CRL, StoreSerialNumber) +{ + uint8_t data[10] = {0x01, 0x82, 0x01, 0xd1, 0x30, 0x82, 0x01, 0x77, 0xa0, 0x03}; + const ByteArray sn = { data, sizeof(data) / sizeof(uint8_t)}; + int i; + for (i = 0; i < 400; i++) + { + sn.data[0] = i % 20; + ASSERT_EQ(PKI_SUCCESS, StoreSerialNumber(sn)); + } + ASSERT_EQ(PKI_CERT_REVOKED, CheckSerialNumber(sn)); + + sn.data[1] = 0x01; + ASSERT_EQ(PKI_SUCCESS, CheckSerialNumber(sn)); + + FreeSNStore(); +} +#ifdef ARDUINO_MEMORY_DEBUG +//testing memory allocation fault handling at Arduino +TEST(SNStore, MemoryOverflow) +{ + uint8_t data[10] = {0x01, 0x82, 0x01, 0xd1, 0x30, 0x82, 0x01, 0x77, 0xa0, 0x03}; + const ByteArray sn = { data, sizeof(data) / sizeof(uint8_t)}; + int i; + PKIError res; + do + { + res = StoreSerialNumber(sn); + } + while (res == PKI_SUCCESS); + ASSERT_EQ(PKI_MEMORY_ALLOC_FAILED, res); + + FreeSNStore(); +} +#endif /* ARDUINO_MEMORY_DEBUG */ + +//testing next certificate serial number handling by "CKM info" unit +TEST_F(PKITest, CAInitAndSerialNum) +{ + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + long serialNum = rand() % (MAX_LEN - 1) + 1; + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + //all the serials should start from + ASSERT_EQ(PKI_SUCCESS, SetSerialNumber(serialNum)); + long nextSerial; + ASSERT_EQ(PKI_SUCCESS, GetNextSerialNumber(&nextSerial)); + ASSERT_EQ(nextSerial, serialNum); + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//testing CA name handling by "CKM info" unit +TEST_F(PKITest, testCAName) +{ + ByteArray caName = BYTE_ARRAY_INITIALIZER; + caName.len = ((size_t)rand() % (ISSUER_MAX_NAME_SIZE - 1) + 1); + caName.data = (uint8_t*)malloc(caName.len); + size_t i; + for(i = 0; i < caName.len; i++){ + caName.data[i] = (uint8_t)(rand() % 128); + } + EXPECT_EQ(PKI_SUCCESS, InitCKMInfo()); + EXPECT_EQ(PKI_SUCCESS, SetRootName(caName)); + ByteArray getName = BYTE_ARRAY_INITIALIZER; + uint8_t uint8CAName[ISSUER_MAX_NAME_SIZE] = {0}; + getName.data = uint8CAName; + getName.len = ISSUER_MAX_NAME_SIZE; + EXPECT_EQ(PKI_SUCCESS, GetCAName(&getName)); + EXPECT_EQ(0, memcmp(caName.data, getName.data, caName.len)); + free(caName.data); + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//testing key pair generation and storing by "CKM info" unit +TEST_F(PKITest, testKeyPair) +{ + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + rootName.data = (uint8_t *)"ROOT"; + rootName.len = strlen((char *)rootName.data); + SetRootName(rootName); + + //first test the GenerateCAKeyPair - this writes to the CA storage + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + privKeyIss.len = PRIVATE_KEY_SIZE; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + privKeyIss.data = caPrivKey; + + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + pubKeyIss.len = PUBLIC_KEY_SIZE; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + pubKeyIss.data = caPubKey; + + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKeyIss, &pubKeyIss)); + + ByteArray keyCheck = BYTE_ARRAY_INITIALIZER; + keyCheck.len = PUBLIC_KEY_SIZE; + uint8_t keyCheckData[PUBLIC_KEY_SIZE] = {0}; + keyCheck.data = keyCheckData; + ASSERT_EQ(PKI_SUCCESS, GetCAPrivateKey(&keyCheck)); + ASSERT_EQ(0, memcmp(keyCheck.data, privKeyIss.data, PRIVATE_KEY_SIZE)); + + ASSERT_EQ(PKI_SUCCESS, GetCAPublicKey(&keyCheck)); + ASSERT_EQ(0, memcmp(keyCheck.data, pubKeyIss.data, PUBLIC_KEY_SIZE)); + + //now test the GenerateKeyPair - does not write to the CA storage + ASSERT_EQ(PKI_SUCCESS, GenerateKeyPair(&privKeyIss, &pubKeyIss)); + + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + ASSERT_EQ(PKI_SUCCESS, GetCAPrivateKey(&keyCheck)); + ASSERT_NE(0, memcmp(keyCheck.data, privKeyIss.data, PRIVATE_KEY_SIZE)); + + ASSERT_EQ(PKI_SUCCESS, GetCAPublicKey(&keyCheck)); + ASSERT_NE(0, memcmp(keyCheck.data, pubKeyIss.data, PUBLIC_KEY_SIZE)); + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//testing CRL encoding +TEST_F(PKITest, testEncodeCRL) +{ + CertificateList crl; + + uint8_t *uint8ThisUpdateTime = (uint8_t *)"130101000000Z"; + uint32_t numberOfRevoked = 0; + uint32_t revokedNumbers[2]; + const uint8_t *revocationDates[2]; + + ByteArray code = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + + pubKeyIss.data = caPubKey; + pubKeyIss.len = PUBLIC_KEY_SIZE; + privKeyIss.data = caPrivKey; + privKeyIss.len = PRIVATE_KEY_SIZE; + + numberOfRevoked = 2; + + revokedNumbers[0] = 100; // serial number of first revoked certificate + revokedNumbers[1] = 200; // serial number of second revoked certificate + revocationDates[0] = (const uint8_t *)"130101000001Z"; + revocationDates[1] = (const uint8_t *)"130101000002Z"; + + rootName.data = (uint8_t *)"ROOT2"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKeyIss, &pubKeyIss)); + + code.data = (uint8_t *)calloc(1, + (CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4))); + code.len = (CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4)); + + EXPECT_EQ(PKI_SUCCESS,CKMIssueCRL(uint8ThisUpdateTime, numberOfRevoked, revokedNumbers, + revocationDates,&code)); + EXPECT_EQ(PKI_SUCCESS, DecodeCertificateList (code, &crl, pubKeyIss)); +#ifdef X509_DEBUG + PrintSNStore(); + PrintCRL(&crl); +#endif + + FreeSNStore(); + free(code.data); + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//check correctness of certificate revocation by CKMIssueCRL() and CKMRevocateCertificate() +TEST_F(PKITest, testRevocateCertificate) +{ + CertificateList crl; + + uint8_t *uint8ThisUpdateTime = (uint8_t *)"130101000000Z"; + uint32_t numberOfRevoked = 0; + uint32_t revokedNumbers[2]; + const uint8_t *revocationDates[2]; + + ByteArray code = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + + pubKeyIss.data = caPubKey; + pubKeyIss.len = sizeof(caPubKey); + privKeyIss.data = caPrivKey; + privKeyIss.len = sizeof(caPrivKey); + + numberOfRevoked = 2; + + revokedNumbers[0] = 100; // serial number of first revoked certificate + revokedNumbers[1] = 200; // serial number of second revoked certificate + revocationDates[0] = (const uint8_t *)"130101000001Z"; + revocationDates[1] = (const uint8_t *)"130101000002Z"; + + rootName.data = (uint8_t *)"ROOT2"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKeyIss, &pubKeyIss)); + + code.len = CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4); + code.data = (uint8_t *)calloc(1, code.len); + + EXPECT_EQ(PKI_SUCCESS, CKMIssueCRL (uint8ThisUpdateTime, numberOfRevoked, revokedNumbers, + revocationDates, &code)); + EXPECT_EQ(PKI_SUCCESS, DecodeCertificateList (code, &crl, pubKeyIss)); + free(code.data); + numberOfRevoked++; + code.len = CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4); + code.data = (uint8_t *)calloc(1, code.len); + EXPECT_EQ(PKI_SUCCESS, CKMRevocateCertificate (uint8ThisUpdateTime, 50, &code)); + EXPECT_EQ(PKI_SUCCESS, DecodeCertificateList (code, &crl, pubKeyIss)); +#ifdef X509_DEBUG + PrintSNStore(); + PrintCRL(&crl); +#endif + + FreeSNStore(); + free(code.data); + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//checck correctness of saving root certificate to binary file +TEST_F(PKITest, StoreCKMInfo) +{ + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + uint8_t derData[ISSUER_MAX_CERT_SIZE] = {0}; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + const long serNum = 48598490; + CertificateList crl; + uint8_t *uint8ThisUpdateTime = (uint8_t *)"130101000000Z"; + uint32_t numberOfRevoked = 0; + uint32_t revokedNumbers[2]; + const uint8_t *revocationDates[2]; + + ByteArray certDer = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + ByteArray code = BYTE_ARRAY_INITIALIZER; + + certDer.data = derData; + certDer.len = ISSUER_MAX_CERT_SIZE; + pubKeyIss.data = caPubKey; + pubKeyIss.len = PUBLIC_KEY_SIZE; + privKeyIss.data = caPrivKey; + privKeyIss.len = PRIVATE_KEY_SIZE; + rootName.data = (uint8_t *)"ROOT"; + rootName.len = strlen((char *)rootName.data); + + //generate CA Certificate + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKeyIss, &pubKeyIss)); + ASSERT_EQ(PKI_SUCCESS, SetSerialNumber(serNum)); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + ASSERT_EQ(PKI_SUCCESS, CKMIssueRootCertificate(0, 0, &certDer)); + + //generate CRL + numberOfRevoked = NUMBER_OF_REVOKED; + + revokedNumbers[0] = 100; // serial number of first revoked certificate + revokedNumbers[1] = 200; // serial number of second revoked certificate + revocationDates[0] = (const uint8_t *)"130101000001Z"; + revocationDates[1] = (const uint8_t *)"130101000002Z"; + + code.data = (uint8_t *)calloc(1, + (CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4))); + code.len = (CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4)); + + ASSERT_EQ(PKI_SUCCESS, CKMIssueCRL (uint8ThisUpdateTime, numberOfRevoked, revokedNumbers, + revocationDates, &code)); + + // Check Certificate file + CertificateX509 certificate; + ByteArray crtDer = BYTE_ARRAY_INITIALIZER; + FILE *filePtr = fopen(CA_STORAGE_CRT_FILE , "rb"); + ASSERT_TRUE(filePtr != NULL); + + //get the length + fseek(filePtr, 0, SEEK_END); + crtDer.len = ftell(filePtr); + fseek(filePtr, 0, SEEK_SET); + //allocate memory + crtDer.data = (uint8_t*)malloc(crtDer.len+1); + //read the content + EXPECT_EQ(READ_WRITE_BLOCK_N, fread(crtDer.data, crtDer.len, READ_WRITE_BLOCK_N, filePtr)); + fclose(filePtr); + ByteArray crtCheck; + crtCheck.data = crtDer.data + 3; //now file contains length of certificate + crtCheck.len = crtDer.len - 3; + EXPECT_EQ(PKI_SUCCESS, DecodeCertificate(crtCheck, &certificate)); +#ifdef X509_DEBUG + PrintCertificate(&certificate); +#endif + + //check CRL + ByteArray crlDer = BYTE_ARRAY_INITIALIZER; + crlDer.len = (CRL_MIN_SIZE + numberOfRevoked * (sizeof(CertificateRevocationInfo_t) + 4)); + crlDer.data = (uint8_t *)malloc(crlDer.len); + + EXPECT_EQ(PKI_SUCCESS, GetCertificateRevocationList(&crlDer)); + + EXPECT_EQ(PKI_SUCCESS, DecodeCertificateList (crlDer, &crl, pubKeyIss)); +#ifdef X509_DEBUG + PrintCRL(&crl); +#endif + EXPECT_EQ(PKI_SUCCESS, CloseCKMInfo()); + free(crlDer.data); + free(code.data); + free(crtDer.data); +} + +//check correctness of root certificate generation +TEST_F(PKITest, GenerateRootCertificate) +{ + uint8_t derData[ISSUER_MAX_CERT_SIZE] = {0}; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + + ByteArray certDer = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + certDer.data = derData; + certDer.len = sizeof(derData); + + pubKeyIss.data = caPubKey; + pubKeyIss.len = sizeof(caPubKey); + privKeyIss.data = caPrivKey; + privKeyIss.len = sizeof(caPrivKey); + rootName.data = (uint8_t *)"ROOT"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + + for (int i = 1; i <= RUNS; i++) + { + ASSERT_EQ(PKI_SUCCESS, GenerateCAKeyPair(&privKeyIss, &pubKeyIss)); + ASSERT_EQ(PKI_SUCCESS, SetSerialNumber(i)); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + ASSERT_EQ(PKI_SUCCESS, CKMIssueRootCertificate(0, 0, &certDer)); + + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + certDer.data[0]++; + ASSERT_NE(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + certDer.data[0]--; + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + } + ASSERT_EQ(PKI_SUCCESS, CloseCKMInfo()); +} + +//check correctness of ordinal device certificate generation +TEST_F(PKITest, GenerateDeviceCertificate) +{ + uint8_t derData[ISSUER_MAX_CERT_SIZE] = {0}; + uint8_t subjPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t subjPrivKey[PRIVATE_KEY_SIZE] = {0}; + uint8_t caPubKey[PUBLIC_KEY_SIZE] = {0}; + uint8_t caPrivKey[PRIVATE_KEY_SIZE] = {0}; + uint8_t *subjName = (uint8_t *)"Subject Name"; + + ByteArray certDer = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray privKeyIss = BYTE_ARRAY_INITIALIZER; + ByteArray pubKeySubj = BYTE_ARRAY_INITIALIZER; + ByteArray privKeySubj = BYTE_ARRAY_INITIALIZER; + ByteArray rootName = BYTE_ARRAY_INITIALIZER; + + certDer.data = derData; + certDer.len = ISSUER_MAX_CERT_SIZE; + + pubKeyIss.data = caPubKey; + pubKeyIss.len = sizeof(caPubKey); + privKeyIss.data = caPrivKey; + privKeyIss.len = sizeof(caPrivKey); + pubKeySubj.data = subjPubKey; + pubKeySubj.len = sizeof(subjPubKey); + privKeySubj.data = subjPrivKey; + privKeySubj.len = sizeof(subjPrivKey); + rootName.data = (uint8_t *)"ROOT2"; + rootName.len = strlen((char *)rootName.data); + ASSERT_EQ(PKI_SUCCESS, InitCKMInfo()); + + ASSERT_EQ(GenerateCAKeyPair(&privKeyIss, &pubKeyIss), PKI_SUCCESS); + for (int i = 1; i <= RUNS; i++) + { + ASSERT_EQ(PKI_SUCCESS, GenerateKeyPair(&privKeySubj, &pubKeySubj)); + ASSERT_EQ(PKI_SUCCESS, SetSerialNumber(i)); + ASSERT_EQ(PKI_SUCCESS, SetRootName(rootName)); + ASSERT_EQ(PKI_SUCCESS, CKMIssueDeviceCertificate(subjName, 0, 0, subjPubKey, &certDer)); + + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + certDer.data[0]++; + ASSERT_NE(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + certDer.data[0]--; + ASSERT_EQ(PKI_SUCCESS, CheckCertificate(certDer, pubKeyIss)); + } + ASSERT_EQ(CloseCKMInfo(), PKI_SUCCESS); +} + +//check correctness of saving CRL to storage and loading CRL from storage +TEST_F(PKITest, CRLSetGet) +{ + OicSecCrl_t *defaultCrl = NULL; + defaultCrl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t)); + defaultCrl->CrlId = CRL_DEFAULT_CRL_ID; + defaultCrl->CrlData.data = (uint8_t *)CRL_DEFAULT_CRL_DATA; + defaultCrl->CrlData.len = strlen(CRL_DEFAULT_CRL_DATA); + defaultCrl->ThisUpdate.data = (uint8_t *)CRL_DEFAULT_THIS_UPDATE; + defaultCrl->ThisUpdate.len = strlen(CRL_DEFAULT_THIS_UPDATE); + EXPECT_EQ(OC_STACK_OK, UpdateCRLResource(defaultCrl)); + + EXPECT_NE((void *)NULL, GetBase64CRL()); + OICFree(defaultCrl); + + +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/test_data/01.der b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/01.der new file mode 100644 index 0000000..9f4e0d9 Binary files /dev/null and b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/01.der differ diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/test_data/CKMInfo.json b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/CKMInfo.json new file mode 100644 index 0000000..d036473 --- /dev/null +++ b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/CKMInfo.json @@ -0,0 +1,48 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad" + ], + "perms": 2, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlE"] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/cred" + ], + "perms": 7, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlE"] + } + ], + "crl": { + "CRLId": 1, + "ThisUpdate": "MTUwMTAxMDAwMDAwWg==", + "CRLData": "LQ==" + }, + "pstat": { + "isop": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlE", + "ch": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlE", + "ownr": "YWRtaW5EZXZpY2VVVUlE" + } +} diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/test_data/cacert.der b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/cacert.der new file mode 100644 index 0000000..e8d0a67 Binary files /dev/null and b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/cacert.der differ diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/test_data/capub.der b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/capub.der new file mode 100644 index 0000000..55252f0 Binary files /dev/null and b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/capub.der differ diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/test_data/cert_chain.dat b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/cert_chain.dat new file mode 100755 index 0000000..e400aa8 Binary files /dev/null and b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/cert_chain.dat differ diff --git a/resource/csdk/security/provisioning/ck_manager/unittest/test_data/chain.der b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/chain.der new file mode 100644 index 0000000..37f3dd8 Binary files /dev/null and b/resource/csdk/security/provisioning/ck_manager/unittest/test_data/chain.der differ