1 /* *****************************************************************
3 * Copyright 2016 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * *****************************************************************/
25 #include "oic_malloc.h"
26 #include "oic_string.h"
29 #include "resourcemanager.h"
30 #include "dpairingresource.h"
31 #include "psinterface.h"
33 #include "srmresourcestrings.h"
34 #include "cainterface.h"
35 #include "doxmresource.h"
36 #include "pconfresource.h"
37 #include "credresource.h"
38 #include "aclresource.h"
39 #include "srmutility.h"
40 #include "ocserverrequest.h"
41 #include "ocpayloadcbor.h"
42 #include "ocpayload.h"
43 #include "payload_logging.h"
55 #define TAG "SRM-DPAIRING"
57 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
58 * The value of payload size is increased until reaching belox max cbor size. */
59 static const uint8_t CBOR_SIZE = 255;
61 /** Max cbor size payload. */
62 static const uint16_t CBOR_MAX_SIZE = 4400;
64 /** DOXM Map size - Number of mandatory items. */
65 static const uint8_t DPAIR_MAP_SIZE = 3;
67 static OicSecDpairing_t *gDpair = NULL;
68 static OCResourceHandle gDpairHandle = NULL;
69 static OicSecDpairing_t gDefaultDpair =
71 PRM_NOT_ALLOWED, /* OicSecPrm_t spm */
72 {.id = {0}}, /* OicUuid_t pdeviceID */
73 {.id = {0}}, /* OicUuid_t rowner */
76 void DeleteDpairingBinData(OicSecDpairing_t* dpair)
80 //Clean dpairing itself
86 * Get the default value.
87 * @retval the gDefaultDpair pointer;
89 static OicSecDpairing_t* GetDpairingDefault()
91 OIC_LOG (DEBUG, TAG, "GetDpairingDefault");
93 return &gDefaultDpair;
97 * This method is used by SRM to retrieve Dpairing resource data..
99 void SetDpairingResourceOwner(OicUuid_t *rowner)
101 OIC_LOG (DEBUG, TAG, "SetDpairingResourceOwner");
104 memcpy(&gDpair->rowner, rowner, sizeof(OicUuid_t));
110 * Function to save PairingPSK.
112 * @param[in] endpoint current endpoint.
113 * @param[in] peerDevID peer device indentitiy.
114 * @param[in] isPairingServer indicate if it generates PairingPSK for server or client.
116 * @return OC_STACK_OK on success
118 OCStackResult SavePairingPSK(OCDevAddr *endpoint,
119 OicUuid_t *peerDevID, OicUuid_t *owner, bool isPairingServer)
121 OIC_LOG(DEBUG, TAG, "IN SavePairingPSK");
123 if(NULL == endpoint || NULL == peerDevID || NULL == owner)
125 OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);
126 return OC_STACK_INVALID_PARAM;
129 OCStackResult res = OC_STACK_ERROR;
131 OicUuid_t ptDeviceID = {.id={0}};
132 if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID))
134 OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
138 uint8_t pairingPSK[OWNER_PSK_LENGTH_128] = {0};
139 OicSecKey_t pairingKey = {pairingPSK, OWNER_PSK_LENGTH_128};
141 //Generating PairingPSK using OwnerPSK scheme
142 CAResult_t pskRet = CAGenerateOwnerPSK((const CAEndpoint_t *)endpoint,
143 (uint8_t *)OIC_RSRC_TYPE_SEC_DPAIRING,
144 strlen(OIC_RSRC_TYPE_SEC_DPAIRING),
145 (isPairingServer ? ptDeviceID.id : peerDevID->id), sizeof(OicUuid_t), // server
146 (isPairingServer ? peerDevID->id : ptDeviceID.id), sizeof(OicUuid_t), // client
147 pairingPSK, OWNER_PSK_LENGTH_128);
149 if (CA_STATUS_OK == pskRet)
151 OIC_LOG(INFO, TAG, "pairingPSK dump:\n");
152 OIC_LOG_BUFFER(INFO, TAG, pairingPSK, OWNER_PSK_LENGTH_128);
153 //Generating new credential for direct-pairing client
156 OicSecCred_t *cred = GenerateCredential(peerDevID,
157 SYMMETRIC_PAIR_WISE_KEY, NULL,
158 &pairingKey, ownLen, owner);
159 VERIFY_NON_NULL(TAG, cred, ERROR);
161 res = AddCredential(cred);
162 if(res != OC_STACK_OK)
164 DeleteCredList(cred);
170 OIC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
173 OIC_LOG(DEBUG, TAG, "OUT SavePairingPSK");
177 #endif // __WITH_DTLS__
179 OCStackResult DpairingToCBORPayload(const OicSecDpairing_t *dpair, uint8_t **payload, size_t *size)
181 if (NULL == dpair || NULL == payload || NULL != *payload || NULL == size)
183 return OC_STACK_INVALID_PARAM;
186 size_t cborLen = *size;
195 OCStackResult ret = OC_STACK_ERROR;
197 CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
198 CborEncoder dpairMap = { {.ptr = NULL }, .end = 0 };
200 int64_t cborEncoderResult = CborNoError;
201 uint8_t mapSize = DPAIR_MAP_SIZE;
203 uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
204 VERIFY_NON_NULL(TAG, outPayload, ERROR);
205 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
207 cborEncoderResult |= cbor_encoder_create_map(&encoder, &dpairMap, mapSize);
208 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Creating DPAIRING Map");
211 cborEncoderResult |= cbor_encode_text_string(&dpairMap, OIC_JSON_SPM_NAME,
212 strlen(OIC_JSON_SPM_NAME));
213 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SPM name tag");
214 cborEncoderResult |= cbor_encode_int(&dpairMap, dpair->spm);
215 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SPM value");
217 //PDEVICEID -- Mandatory
218 cborEncoderResult |= cbor_encode_text_string(&dpairMap, OIC_JSON_PDEVICE_ID_NAME,
219 strlen(OIC_JSON_PDEVICE_ID_NAME));
220 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PDeviceID tag");
221 cborEncoderResult |= cbor_encode_byte_string(&dpairMap, dpair->pdeviceID.id,
222 sizeof(dpair->pdeviceID.id));
223 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PDeviceID value");
225 //ROWNER -- Mandatory
226 cborEncoderResult |= cbor_encode_text_string(&dpairMap, OIC_JSON_ROWNER_NAME,
227 strlen(OIC_JSON_ROWNER_NAME));
228 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROWNER tag");
229 cborEncoderResult |= cbor_encode_byte_string(&dpairMap, dpair->rowner.id,
230 sizeof(dpair->rowner.id));
231 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Rowner ID value");
233 cborEncoderResult |= cbor_encoder_close_container(&encoder, &dpairMap);
234 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to close dpairMap");
236 if (CborNoError == cborEncoderResult)
238 *size = encoder.ptr - outPayload;
239 *payload = outPayload;
244 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
246 // reallocate and try again!
248 // Since the allocated initial memory failed, double the memory.
249 cborLen += encoder.ptr - encoder.end;
250 cborEncoderResult = CborNoError;
251 ret = DpairingToCBORPayload(dpair, payload, &cborLen);
255 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
261 ret = OC_STACK_ERROR;
267 OCStackResult CBORPayloadToDpair(const uint8_t *cborPayload, size_t size,
268 OicSecDpairing_t **secDpair)
270 if (NULL == cborPayload || NULL == secDpair || NULL != *secDpair || 0 == size)
272 return OC_STACK_INVALID_PARAM;
275 OCStackResult ret = OC_STACK_ERROR;
278 CborValue dpairCbor = { .parser = NULL };
279 CborParser parser = { .end = NULL };
280 CborError cborFindResult = CborNoError;
283 cbor_parser_init(cborPayload, cborLen, 0, &parser, &dpairCbor);
284 CborValue dpairMap = { .parser = NULL };
285 OicSecDpairing_t *dpair = NULL;
286 cborFindResult = cbor_value_enter_container(&dpairCbor, &dpairMap);
287 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering DPairing Map");
289 dpair = (OicSecDpairing_t *)OICCalloc(1, sizeof(*dpair));
290 VERIFY_NON_NULL(TAG, dpair, ERROR);
292 while (cbor_value_is_valid(&dpairMap))
296 cborFindResult = cbor_value_dup_text_string(&dpairMap, &name, &len, NULL);
297 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding tag name");
298 cborFindResult = cbor_value_advance(&dpairMap);
299 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing a value in DPair map");
301 CborType type = cbor_value_get_type(&dpairMap);
303 if (0 == strcmp(OIC_JSON_SPM_NAME, name))
305 cborFindResult = cbor_value_get_int(&dpairMap, (int *) &dpair->spm);
306 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SPM Value");
309 if (0 == strcmp(OIC_JSON_PDEVICE_ID_NAME, name))
312 cborFindResult = cbor_value_dup_byte_string(&dpairMap, &id, &len, NULL);
313 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PDeviceID value");
314 memcpy(dpair->pdeviceID.id, id, len);
318 if (0 == strcmp(OIC_JSON_ROWNER_NAME, name))
321 cborFindResult = cbor_value_dup_byte_string(&dpairMap, &id, &len, NULL);
322 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding RownerID value");
323 memcpy(dpair->rowner.id, id, len);
327 if (CborMapType != type && cbor_value_is_valid(&dpairMap))
329 cborFindResult = cbor_value_advance(&dpairMap);
330 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing the Dpair Map");
339 if (CborNoError != cborFindResult)
341 OIC_LOG (ERROR, TAG, "CBORPayloadToDoxm failed");
342 DeleteDpairingBinData(dpair);
344 ret = OC_STACK_ERROR;
349 * Function to handle the handshake result in Direct-Pairing.
350 * This function will be invoked after DTLS handshake
351 * @param endPoint [IN] The remote endpoint.
352 * @param errorInfo [IN] Error information from the endpoint.
355 void DPairingDTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
357 OIC_LOG_V(INFO, TAG, "IN DPairingDTLSHandshakeCB");
359 if(gDpair && endpoint && info)
361 OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
362 endpoint->addr, endpoint->port, info->result);
364 if(CA_STATUS_OK == info->result)
366 OIC_LOG(INFO, TAG, "DPairingDTLSHandshakeCB - Connection success.");
368 else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)
370 OIC_LOG(INFO, TAG, "DPairingDTLSHandshakeCB - Authentication failed");
375 CARegisterDTLSHandshakeCallback(NULL);
376 #endif // __WITH_DTLS__
378 // delete temporary key
379 RemoveCredential(&gDpair->pdeviceID);
382 OIC_LOG_V(INFO, TAG, "OUT DPairingDTLSHandshakeCB");
385 static OCEntityHandlerResult HandleDpairingPostRequest (const OCEntityHandlerRequest * ehRequest)
387 OIC_LOG (DEBUG, TAG, "Dpairing EntityHandle processing POST request");
388 OCEntityHandlerResult ehRet = OC_EH_ERROR;
389 OicSecDpairing_t* newDpair = NULL;
390 OCStackResult res = OC_STACK_OK;
392 const OicSecPconf_t *pconf = GetPconfResourceData();
393 if (true == pconf->edp)
395 uint8_t *payload = ((OCSecurityPayload*)ehRequest->payload)->securityData1;
396 size_t size = ((OCSecurityPayload*)ehRequest->payload)->payloadSize;
399 res = CBORPayloadToDpair(payload, size, &newDpair);
404 OIC_LOG (DEBUG, TAG, "EDP == false : Direct-Pairing Disabled");
408 if (OC_STACK_OK == res && newDpair && false == IsPairedDevice(&newDpair->pdeviceID))
410 // Check if valid Post request
411 bool prmMached = false;
412 for (size_t i=0; i<pconf->prmLen; i++)
414 if (newDpair->spm == pconf->prm[i])
420 OIC_LOG_V(DEBUG, TAG, "Parsed spm is %s", prmMached ? "valid" :
421 "invalid, send error response");
423 // Update local Dpairing with new Dpairing & prepare dtls session
424 if (prmMached && '\0' != (char)newDpair->pdeviceID.id[0])
428 gDpair = GetDpairingDefault();
430 gDpair->spm = newDpair->spm;
431 memcpy(&gDpair->pdeviceID, &newDpair->pdeviceID, sizeof(OicUuid_t));
432 memcpy(&gDpair->rowner, &pconf->rowner, sizeof(OicUuid_t));
437 OicUuid_t subjectId = {.id={0}};
438 res = AddTmpPskWithPIN(&gDpair->pdeviceID,
439 SYMMETRIC_PAIR_WISE_KEY,
440 (char*)pconf->pin.val, DP_PIN_LENGTH,
441 1, &gDpair->rowner, &subjectId);
442 if(res != OC_STACK_OK ||
443 memcmp(&gDpair->pdeviceID, &subjectId, sizeof(OicUuid_t)))
445 OIC_LOG_V(ERROR, TAG, "Failed to save the temporal PSK : %d", res);
449 // Prepare to establish a secure channel with Pin-based PSK cipher suite
450 if (CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false) ||
451 CA_STATUS_OK != CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256))
453 OIC_LOG_V(ERROR, TAG, "Failed to select TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256");
457 if(CA_STATUS_OK != CARegisterDTLSHandshakeCallback(DPairingDTLSHandshakeCB))
459 OIC_LOG(WARNING, TAG, "DirectPairingHandler : Failed to register"
460 " DTLS handshake callback.");
463 #endif // __WITH_DTLS__
465 // should be lock /oic/sec/dpairing resource if Direct-Pairing starts normally ?
466 OIC_LOG (DEBUG, TAG, "/oic/sec/dpairing resource created");
468 ehRet = OC_EH_RESOURCE_CREATED;
472 OIC_LOG(ERROR, TAG, "Error in request check");
479 #endif // __WITH_DTLS__
481 if (OC_EH_ERROR == ehRet && gDpair)
483 RemoveCredential(&gDpair->pdeviceID);
487 // Send payload to request originator
488 if(OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, NULL, 0))
490 OIC_LOG (ERROR, TAG, "SendSRMCBORResponse failed in HandleDpairingPostRequest");
493 DeleteDpairingBinData(newDpair);
494 OIC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
498 static OCEntityHandlerResult HandleDpairingPutRequest (const OCEntityHandlerRequest * ehRequest)
500 OIC_LOG (DEBUG, TAG, "Dpairing EntityHandle processing PUT request (Comfirmation)");
502 OCEntityHandlerResult ehRet = OC_EH_ERROR;
503 OicSecDpairing_t* newDpair = NULL;
504 OCStackResult res = OC_STACK_OK;
506 const OicSecPconf_t *pconf = GetPconfResourceData();
507 if (true == pconf->edp)
509 uint8_t *payload = ((OCSecurityPayload*)ehRequest->payload)->securityData1;
510 size_t size = ((OCSecurityPayload*)ehRequest->payload)->payloadSize;
513 res = CBORPayloadToDpair(payload, size, &newDpair);
519 OIC_LOG (DEBUG, TAG, "EDP == false : Direct-Pairing Disabled");
524 if ((OC_STACK_OK == res) && gDpair && newDpair)
526 OIC_LOG(DEBUG, TAG, "Received direct-pairing finalization request");
528 // Check if valid Put request
529 VERIFY_SUCCESS(TAG, PRM_NOT_ALLOWED == newDpair->spm, ERROR);
531 const OicSecPconf_t *pconf = GetPconfResourceData();
532 VERIFY_NON_NULL(TAG, pconf, ERROR);
535 OCServerRequest * request = (OCServerRequest *)ehRequest->requestHandle;
536 VERIFY_SUCCESS(TAG, (request->devAddr.flags | OC_FLAG_SECURE), ERROR);
538 //Generate new credential
539 OIC_LOG_V(INFO, TAG, "SavePairingPSK for %s(%d)", request->devAddr.addr,
540 request->devAddr.port);
541 OCStackResult res = SavePairingPSK(&request->devAddr, &newDpair->pdeviceID,
542 (OicUuid_t *)&pconf->rowner, true);
543 VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
544 #endif //__WITH_DTLS__
547 OicSecPdAcl_t *pdAcl;
548 LL_FOREACH(pconf->pdacls, pdAcl)
551 memset(&acl, 0, sizeof(OicSecAcl_t));
552 memcpy(&acl.subject, &gDpair->pdeviceID, sizeof(OicUuid_t));
553 acl.resources = pdAcl->resources;
554 acl.resourcesLen = pdAcl->resourcesLen;
555 acl.owners = (OicUuid_t*)&pconf->rowner;
557 acl.permission = pdAcl->permission;
558 acl.periods = pdAcl->periods;
559 acl.recurrences = pdAcl->recurrences;
560 acl.prdRecrLen = pdAcl->prdRecrLen;
563 uint8_t *payload = NULL;
564 if (OC_STACK_OK == AclToCBORPayload(&acl, &payload, &size))
566 InstallNewACL(payload, size);
571 //update pconf device list
572 AddPairedDevice(&newDpair->pdeviceID);
574 //Initialize dpairing resource
577 OIC_LOG (DEBUG, TAG, "/oic/sec/dpairing resource updated,"
578 "direct-pairing finalization success");
584 //Send payload to request originator
585 if(OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, NULL, 0))
587 OIC_LOG (ERROR, TAG, "SendSRMCBORResponse failed in HandleDpairingPutRequest");
590 DeleteDpairingBinData(newDpair);
591 OIC_LOG_V (DEBUG, TAG, "%s RetVal %d", __func__ , ehRet);
595 * This internal method is the entity handler for Dpairing resources and
596 * will handle REST request (GET/POST) for them.
598 OCEntityHandlerResult DpairingEntityHandler (OCEntityHandlerFlag flag,
599 OCEntityHandlerRequest * ehRequest,
600 void* callbackParameter)
602 OIC_LOG(DEBUG, TAG, "Received request DpairingEntityHandler");
603 (void)callbackParameter;
604 OCEntityHandlerResult ehRet = OC_EH_ERROR;
611 if (flag & OC_REQUEST_FLAG)
613 OIC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
614 switch (ehRequest->method)
620 ehRet = HandleDpairingPostRequest(ehRequest);
624 ehRet = HandleDpairingPutRequest(ehRequest);
632 SendSRMCBORResponse(ehRequest, ehRet, NULL, 0);
640 * This internal method is used to create '/oic/sec/dpairing' resource.
642 OCStackResult CreateDpairingResource()
646 ret = OCCreateResource(&gDpairHandle,
647 OIC_RSRC_TYPE_SEC_DPAIRING,
649 OIC_RSRC_DPAIRING_URI,
650 DpairingEntityHandler,
652 OC_SECURE | OC_EXPLICIT_DISCOVERABLE);
654 if (OC_STACK_OK != ret)
656 OIC_LOG (ERROR, TAG, "Unable to instantiate Dpairing resource");
657 DeInitDpairingResource();
663 * Initialize Dpairing resource by loading data from persistent storage.
665 * @retval OC_STACK_OK for Success, otherwise some error value
667 OCStackResult InitDpairingResource()
669 OCStackResult ret = OC_STACK_ERROR;
671 // Instantiate 'oic.sec.dpairing'
672 ret = CreateDpairingResource();
673 if (OC_STACK_OK != ret)
675 DeInitDpairingResource();
681 * Perform cleanup for Dpairing resources.
684 * OC_STACK_OK - no error
685 * OC_STACK_ERROR - stack process error
688 OCStackResult DeInitDpairingResource()
690 OCStackResult ret = OCDeleteResource(gDpairHandle);
693 if(OC_STACK_OK == ret)
699 return OC_STACK_ERROR;