Merge branch 'master' into notification-service
[platform/upstream/iotivity.git] / resource / csdk / security / src / directpairing.c
1 /* *****************************************************************\r
2  *\r
3  * Copyright 2016 Samsung Electronics All Rights Reserved.\r
4  *\r
5  *\r
6  *\r
7  * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * you may not use this file except in compliance with the License.\r
9  * You may obtain a copy of the License at\r
10  *\r
11  *     http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * Unless required by applicable law or agreed to in writing, software\r
14  * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * See the License for the specific language governing permissions and\r
17  * limitations under the License.\r
18  *\r
19  * *****************************************************************/\r
20 #ifndef _POSIX_C_SOURCE\r
21 #define _POSIX_C_SOURCE 200112L\r
22 #endif\r
23 #ifndef WITH_ARDUINO\r
24 #include <unistd.h>\r
25 #include <time.h>\r
26 #include <sys/time.h>\r
27 #endif\r
28 #include <string.h>\r
29 \r
30 #include "ocstack.h"\r
31 #include "oic_malloc.h"\r
32 #include "oic_string.h"\r
33 #include "logger.h"\r
34 #include "cJSON.h"\r
35 #include "utlist.h"\r
36 #include "ocpayload.h"\r
37 #include "payload_logging.h"\r
38 #include "cainterface.h"\r
39 \r
40 #include "directpairing.h"\r
41 #include "srmresourcestrings.h" //@note: SRM's internal header\r
42 #include "doxmresource.h"       //@note: SRM's internal header\r
43 #include "pconfresource.h"       //@note: SRM's internal header\r
44 #include "dpairingresource.h"       //@note: SRM's internal header\r
45 #include "credresource.h"\r
46 \r
47 #include "pmtypes.h"\r
48 #include "pmutility.h"\r
49 \r
50 #include "srmutility.h"\r
51 \r
52 #ifdef __WITH_DTLS__\r
53 #include "global.h"\r
54 #endif\r
55 \r
56 \r
57 #define TAG ("DP")\r
58 static const uint16_t CBOR_SIZE = 1024;\r
59 \r
60 /**\r
61  * Structure to carry direct-pairing API data to callback.\r
62  */\r
63 typedef struct DPairData\r
64 {\r
65     OCDirectPairingDev_t        *peer;                         /**< Pointer to pairing target info.**/\r
66     char                                  pin[DP_PIN_LENGTH];  /**< PIN **/\r
67     OCDirectPairingResultCB    resultCallback;           /**< Pointer to result callback.**/\r
68     void *userCtx;                                      /** < user context to pass in callback **/\r
69 } DPairData_t;\r
70 \r
71 static OCDirectPairingDev_t *g_dp_paired = NULL;\r
72 static OCDirectPairingDev_t *g_dp_discover = NULL;\r
73 static DPairData_t *g_dp_proceed_ctx = NULL;\r
74 \r
75 \r
76 /**\r
77  * Function to search node in linked list that matches given IP and port.\r
78  *\r
79  * @param[in] pList         List of OCProvisionDev_t.\r
80  * @param[in] addr          address of target device.\r
81  * @param[in] port          port of remote server.\r
82  *\r
83  * @return pointer of OCProvisionDev_t if exist, otherwise NULL\r
84  */\r
85 OCDirectPairingDev_t* getDev(OCDirectPairingDev_t **ppList, const char* addr, const uint16_t port)\r
86 {\r
87     if(NULL == addr)\r
88     {\r
89         OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);\r
90         return NULL;\r
91     }\r
92 \r
93     OCDirectPairingDev_t *ptr = NULL;\r
94     LL_FOREACH(*ppList, ptr)\r
95     {\r
96         if( strcmp(ptr->endpoint.addr, addr) == 0 && port == ptr->endpoint.port)\r
97         {\r
98             return ptr;\r
99         }\r
100     }\r
101 \r
102     return NULL;\r
103 }\r
104 \r
105 \r
106 \r
107 /**\r
108  * Add device information to list.\r
109  *\r
110  * @param[in] pList         List of OCProvisionDev_t.\r
111  * @param[in] addr          address of target device.\r
112  * @param[in] port          port of remote server.\r
113  * @param[in] adapter       adapter type of endpoint.\r
114  * @param[in] doxm          pointer to doxm instance.\r
115  * @param[in] connType  connectivity type of endpoint\r
116  *\r
117  * @return OC_STACK_OK for success and errorcode otherwise.\r
118  */\r
119 OCStackResult addDev(OCDirectPairingDev_t **ppList, OCDevAddr *endpoint,\r
120                                       OCConnectivityType conn, OicSecPconf_t *pconf)\r
121 {\r
122     if(NULL == endpoint || NULL == pconf)\r
123     {\r
124         OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);\r
125         return OC_STACK_INVALID_PARAM;\r
126     }\r
127 \r
128     OCDirectPairingDev_t *ptr = getDev(ppList, endpoint->addr, endpoint->port);\r
129     if(!ptr)\r
130     {\r
131         ptr = (OCDirectPairingDev_t *)OICCalloc(1, sizeof (OCDirectPairingDev_t));\r
132         if (NULL == ptr)\r
133         {\r
134             OIC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");\r
135             return OC_STACK_NO_MEMORY;\r
136         }\r
137 \r
138         memcpy(&ptr->endpoint, endpoint, sizeof(OCDevAddr));\r
139         ptr->connType = conn;\r
140         ptr->securePort = DEFAULT_SECURE_PORT;\r
141         ptr->edp = pconf->edp;\r
142         ptr->prm = pconf->prm;\r
143         pconf->prm = NULL;  // to prevent free\r
144         ptr->prmLen = pconf->prmLen;\r
145         memcpy(&ptr->deviceID, &pconf->deviceID, sizeof(OicUuid_t));\r
146         memcpy(&ptr->rowner, &pconf->rownerID, sizeof(OicUuid_t));\r
147         ptr->next = NULL;\r
148 \r
149         LL_PREPEND(*ppList, ptr);\r
150         OIC_LOG(INFO, TAG, "device added !");\r
151     }\r
152 \r
153     return OC_STACK_OK;\r
154 }\r
155 \r
156 \r
157 /**\r
158  * Add device information to list.\r
159  *\r
160  * @param[in] ppList         List of OCProvisionDev_t.\r
161  * @param[in] pDev          target device.\r
162  *\r
163  * @return OC_STACK_OK for success and errorcode otherwise.\r
164  */\r
165 OCStackResult addDev2(OCDirectPairingDev_t **ppList, OCDirectPairingDev_t *pDev)\r
166 {\r
167     if(NULL == pDev)\r
168     {\r
169         OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);\r
170         return OC_STACK_INVALID_PARAM;\r
171     }\r
172 \r
173     OCDirectPairingDev_t *ptr = getDev(ppList, pDev->endpoint.addr, pDev->endpoint.port);\r
174     if(!ptr)\r
175     {\r
176         ptr = (OCDirectPairingDev_t *)OICCalloc(1, sizeof (OCDirectPairingDev_t));\r
177         if (NULL == ptr)\r
178         {\r
179             OIC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");\r
180             return OC_STACK_NO_MEMORY;\r
181         }\r
182 \r
183         memcpy(&ptr->endpoint, &pDev->endpoint, sizeof(OCDevAddr));\r
184         ptr->connType = pDev->connType;\r
185         ptr->securePort = pDev->securePort;\r
186         ptr->edp = pDev->edp;\r
187         ptr->prmLen = pDev->prmLen;\r
188         ptr->prm = (OicSecPrm_t*)OICCalloc(ptr->prmLen, sizeof (OicSecPrm_t));\r
189         if (NULL == ptr->prm)\r
190         {\r
191             OIC_LOG(ERROR, TAG, "Error while allocating memory for prm !!");\r
192             return OC_STACK_NO_MEMORY;\r
193         }\r
194         memcpy(ptr->prm, pDev->prm, sizeof(OicSecPrm_t)*ptr->prmLen);\r
195         memcpy(&ptr->deviceID, &pDev->deviceID, sizeof(OicUuid_t));\r
196         memcpy(&ptr->rowner, &pDev->rowner, sizeof(OicUuid_t));\r
197         ptr->next = NULL;\r
198 \r
199         LL_PREPEND(*ppList, ptr);\r
200         OIC_LOG(INFO, TAG, "device added !");\r
201     }\r
202 \r
203     return OC_STACK_OK;\r
204 }\r
205 \r
206 \r
207 \r
208 /**\r
209  * This function deletes list of provision target devices\r
210  *\r
211  * @param[in] pDevicesList         List of OCProvisionDev_t.\r
212  */\r
213 void delList(OCDirectPairingDev_t *pList)\r
214 {\r
215     if(pList)\r
216     {\r
217         OCDirectPairingDev_t *del = NULL, *tmp = NULL;\r
218         LL_FOREACH_SAFE(pList, del, tmp)\r
219         {\r
220             LL_DELETE(pList, del);\r
221             if (del && del->prm)\r
222             {\r
223                 OICFree(del->prm);\r
224             }\r
225         }\r
226     }\r
227 }\r
228 \r
229 bool DPGenerateQuery(bool isSecure,\r
230                      const char* address, const uint16_t port,\r
231                      const OCConnectivityType connType,\r
232                      char* buffer, size_t bufferSize, const char* uri)\r
233 {\r
234     if(!address || !buffer || !uri)\r
235     {\r
236         OIC_LOG(ERROR, TAG, "DPGenerateQuery : Invalid parameters.");\r
237         return false;\r
238     }\r
239 \r
240     static char QPREFIX_COAP[] =  "coap://";\r
241     static char QPREFIX_COAPS[] = "coaps://";\r
242 \r
243     int snRet = 0;\r
244     char* prefix = (isSecure == true) ? QPREFIX_COAPS : QPREFIX_COAP;\r
245 \r
246     switch(connType & CT_MASK_ADAPTER)\r
247     {\r
248         case CT_ADAPTER_IP:\r
249             switch(connType & CT_MASK_FLAGS & ~CT_FLAG_SECURE)\r
250             {\r
251                 case CT_IP_USE_V4:\r
252                         snRet = snprintf(buffer, bufferSize, "%s%s:%d%s",\r
253                                          prefix, address, port, uri);\r
254                     break;\r
255                 case CT_IP_USE_V6:\r
256                         snRet = snprintf(buffer, bufferSize, "%s[%s]:%d%s",\r
257                                          prefix, address, port, uri);\r
258                     break;\r
259                 default:\r
260                     OIC_LOG(ERROR, TAG, "Unknown address format.");\r
261                     return false;\r
262             }\r
263             // snprintf return value check\r
264             if (snRet < 0)\r
265             {\r
266                 OIC_LOG_V(ERROR, TAG, "DPGenerateQuery : Error (snprintf) %d\n", snRet);\r
267                 return false;\r
268             }\r
269             else if ((size_t)snRet >= bufferSize)\r
270             {\r
271                 OIC_LOG_V(ERROR, TAG, "DPGenerateQuery : Truncated (snprintf) %d\n", snRet);\r
272                 return false;\r
273             }\r
274 \r
275             break;\r
276 #ifndef WITH_ARDUINO\r
277         // TODO: We need to verify tinyDTLS in below cases\r
278         case CT_ADAPTER_GATT_BTLE:\r
279         case CT_ADAPTER_RFCOMM_BTEDR:\r
280             OIC_LOG(ERROR, TAG, "Not supported connectivity adapter.");\r
281             return false;\r
282             break;\r
283 #endif\r
284         default:\r
285             OIC_LOG(ERROR, TAG, "Unknown connectivity adapter.");\r
286             return false;\r
287     }\r
288 \r
289     return true;\r
290 }\r
291 \r
292 const OCDirectPairingDev_t* DPGetDiscoveredDevices()\r
293 {\r
294     return g_dp_discover;\r
295 }\r
296 \r
297 const OCDirectPairingDev_t* DPGetPairedDevices()\r
298 {\r
299     return g_dp_paired;\r
300 }\r
301 \r
302 void DPDeleteLists()\r
303 {\r
304     delList(g_dp_discover);\r
305     delList(g_dp_paired);\r
306 }\r
307 \r
308 /**\r
309  * Callback handler of FinalizeDirectPairing.\r
310  *\r
311  * @param[in] ctx             ctx value passed to callback from calling function.\r
312  * @param[in] UNUSED          handle to an invocation\r
313  * @param[in] clientResponse  Response from queries to remote servers.\r
314  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction\r
315  *          and  OC_STACK_KEEP_TRANSACTION to keep it.\r
316  */\r
317 static OCStackApplicationResult DirectPairingFinalizeHandler(void *ctx, OCDoHandle UNUSED,\r
318                                                   OCClientResponse *clientResponse)\r
319 {\r
320     OIC_LOG_V(INFO, TAG, "IN DirectPairingFinalizeHandler()");\r
321     (void)UNUSED;\r
322     if(NULL == ctx)\r
323     {\r
324         OIC_LOG(ERROR, TAG, "Context is Null");\r
325         return OC_STACK_DELETE_TRANSACTION;\r
326     }\r
327 \r
328     OCStackResult res;\r
329     DPairData_t *dpairData = (DPairData_t*)ctx;\r
330     OCDirectPairingDev_t *peer = dpairData->peer;\r
331     OCDirectPairingResultCB resultCallback = dpairData->resultCallback;\r
332 \r
333     if (clientResponse)\r
334     {\r
335         if(OC_STACK_OK == clientResponse->result)\r
336         {\r
337             // result\r
338             OIC_LOG(INFO, TAG, "DirectPairingFinalizeHandler : success PUT"\r
339                     " request to /oic/sec/dpairing");\r
340 \r
341             CAEndpoint_t endpoint;\r
342             memset(&endpoint, 0x00, sizeof(CAEndpoint_t));\r
343             OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, peer->endpoint.addr);\r
344             endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';\r
345             endpoint.port = peer->securePort;\r
346 \r
347             OicUuid_t ptDeviceID = {.id={0}};\r
348             if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID))\r
349             {\r
350                 OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");\r
351                 resultCallback(dpairData->userCtx, peer, OC_STACK_ERROR);\r
352                 return OC_STACK_DELETE_TRANSACTION;\r
353             }\r
354 \r
355 #ifdef __WITH_DTLS__\r
356             res = SavePairingPSK((OCDevAddr*)&endpoint, &peer->deviceID, &ptDeviceID, false);\r
357             if(OC_STACK_OK != res)\r
358             {\r
359                 OIC_LOG(ERROR, TAG, "Failed to PairingPSK generation");\r
360                 resultCallback(dpairData->userCtx, peer, res);\r
361                 return OC_STACK_DELETE_TRANSACTION;\r
362             }\r
363 \r
364             //  close temporary sesion\r
365             CAResult_t caResult = CACloseDtlsSession((const CAEndpoint_t*)&endpoint);\r
366             if(CA_STATUS_OK != caResult)\r
367             {\r
368                 OIC_LOG(INFO, TAG, "Fail to close temporary dtls session");\r
369             }\r
370 \r
371             caResult = CASelectCipherSuite(TLS_NULL_WITH_NULL_NULL);\r
372             if(CA_STATUS_OK != caResult)\r
373             {\r
374                 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");\r
375             }\r
376 #endif // __WITH_DTLS__\r
377 \r
378             OIC_LOG(INFO, TAG, "Direct-Papring was successfully completed.");\r
379 \r
380             // update paired list\r
381             OCDirectPairingDev_t *dev = getDev(&g_dp_discover, peer->endpoint.addr,\r
382                     peer->endpoint.port);\r
383             res = addDev2(&g_dp_paired, dev);\r
384             if (OC_STACK_OK != res)\r
385             {\r
386                 OIC_LOG(ERROR, TAG, "Error while adding a device to paired list.");\r
387             }\r
388 \r
389             resultCallback(dpairData->userCtx, peer, OC_STACK_OK);\r
390 \r
391             return OC_STACK_DELETE_TRANSACTION;\r
392         }\r
393         else\r
394         {\r
395             OIC_LOG(INFO, TAG, "Direct-Papring received error response.");\r
396         }\r
397     }\r
398     else\r
399     {\r
400         OIC_LOG(ERROR, TAG, "DirectPairingFinalizeHandler received Null clientResponse");\r
401     }\r
402 \r
403     resultCallback(dpairData->userCtx, peer, OC_STACK_ERROR);\r
404     OICFree(dpairData);\r
405     return OC_STACK_DELETE_TRANSACTION;\r
406 }\r
407 \r
408 /**\r
409  * Finalize direct-pairing .\r
410  *\r
411  * @param[in] peer  target device to establish direct-pairing.\r
412  * @param[in] resultCallback  result event callback.\r
413  *\r
414  * @return OC_STACK_OK on success otherwise error.\r
415  */\r
416 OCStackResult FinalizeDirectPairing(void *ctx, OCDirectPairingDev_t* peer,\r
417                                                      OCDirectPairingResultCB resultCallback)\r
418 {\r
419     if(NULL == peer)\r
420     {\r
421         return OC_STACK_INVALID_PARAM;\r
422     }\r
423 \r
424     OicUuid_t deviceID =   {.id={0}};\r
425     if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))\r
426     {\r
427         OIC_LOG(ERROR, TAG, "Error while retrieving device ID");\r
428         return OC_STACK_ERROR;\r
429     }\r
430 \r
431     OicSecDpairing_t dpair;\r
432     memset(&dpair, 0, sizeof(OicSecDpairing_t));\r
433     dpair.spm = (OicSecPrm_t)PRM_NOT_ALLOWED;\r
434     memcpy(&dpair.pdeviceID, &deviceID, sizeof(OicUuid_t));\r
435 \r
436     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));\r
437     if(!secPayload)\r
438     {\r
439         OIC_LOG(ERROR, TAG, "Failed to memory allocation");\r
440         return OC_STACK_NO_MEMORY;\r
441     }\r
442     secPayload->base.type = PAYLOAD_TYPE_SECURITY;\r
443 \r
444     OCStackResult ret = DpairingToCBORPayload(&dpair, &(secPayload->securityData),\r
445             &(secPayload->payloadSize));\r
446 \r
447     if(OC_STACK_OK != ret)\r
448     {\r
449         OICFree(secPayload);\r
450         OIC_LOG(ERROR, TAG, "Failed to DpairingToCBORPayload");\r
451         return OC_STACK_NO_MEMORY;\r
452     }\r
453     OIC_LOG(INFO, TAG, "DPARING CBOR data:");\r
454     OIC_LOG_BUFFER(INFO, TAG, secPayload->securityData, secPayload->payloadSize);\r
455 \r
456     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};\r
457     if(!DPGenerateQuery(true,\r
458                         peer->endpoint.addr,\r
459                         peer->securePort,\r
460                         peer->connType,\r
461                         query, sizeof(query), OIC_RSRC_DPAIRING_URI))\r
462     {\r
463         OIC_LOG(ERROR, TAG, "DPDirectPairing : Failed to generate query");\r
464         return OC_STACK_ERROR;\r
465     }\r
466     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);\r
467 \r
468     DPairData_t *dpairData = (DPairData_t *) OICCalloc(1, sizeof(DPairData_t));\r
469     if (dpairData == NULL)\r
470     {\r
471         OICFree(secPayload->securityData);\r
472         OICFree(secPayload);\r
473         OIC_LOG(ERROR, TAG, "Unable to allocate memory");\r
474         return OC_STACK_NO_MEMORY;\r
475     }\r
476     dpairData->peer = peer;\r
477     dpairData->resultCallback = resultCallback;\r
478     dpairData->userCtx = ctx;\r
479 \r
480     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};\r
481     cbData.cb = DirectPairingFinalizeHandler;\r
482     cbData.context = (void*)dpairData;\r
483     cbData.cd = NULL;\r
484 \r
485     OCMethod method = OC_REST_PUT;\r
486     OCDoHandle handle = NULL;\r
487     OIC_LOG(DEBUG, TAG, "Sending DPAIRNG setting to resource server");\r
488     ret = OCDoResource(&handle, method, query,\r
489             &peer->endpoint, (OCPayload*)secPayload,\r
490             peer->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
491     if(OC_STACK_OK != ret)\r
492     {\r
493         OIC_LOG(ERROR, TAG, "error in OCDoResource");\r
494         return OC_STACK_ERROR;\r
495     }\r
496 \r
497     return OC_STACK_OK;\r
498  }\r
499 \r
500 /**\r
501  * Function to handle the handshake result in Direct-Pairing.\r
502  * This function will be invoked after DTLS handshake\r
503  * @param   endPoint  [IN] The remote endpoint.\r
504  * @param   errorInfo [IN] Error information from the endpoint.\r
505  * @return  NONE\r
506  */\r
507 void DirectPairingDTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)\r
508 {\r
509     OIC_LOG_V(INFO, TAG, "IN DirectPairingDTLSHandshakeCB");\r
510 \r
511 \r
512     if(g_dp_proceed_ctx && g_dp_proceed_ctx->peer && endpoint && info)\r
513     {\r
514         OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",\r
515                  endpoint->addr, endpoint->port, info->result);\r
516 \r
517         OCDirectPairingDev_t *peer = g_dp_proceed_ctx->peer;\r
518         OCDirectPairingResultCB resultCallback = g_dp_proceed_ctx->resultCallback;\r
519         OCStackResult res;\r
520 \r
521         //Make sure the address matches.\r
522         if(strncmp(peer->endpoint.addr, endpoint->addr, sizeof(endpoint->addr)) == 0 &&\r
523                          peer->securePort == endpoint->port)\r
524         {\r
525             //In case of success, send next coaps request.\r
526             if(CA_STATUS_OK == info->result)\r
527             {\r
528                 OIC_LOG(INFO, TAG, "Now, finalize Direct-Pairing procedure.");\r
529 \r
530                 res = FinalizeDirectPairing(g_dp_proceed_ctx->userCtx, peer, resultCallback);\r
531                 if(OC_STACK_OK != res)\r
532                 {\r
533                     OIC_LOG(ERROR, TAG, "Failed to finalize direct-pairing");\r
534                     resultCallback(g_dp_proceed_ctx->userCtx, peer, res);\r
535                 }\r
536             }\r
537             else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)\r
538             {\r
539                 OIC_LOG(INFO, TAG, "DirectPairingDTLSHandshakeCB - Authentication failed");\r
540                 resultCallback(g_dp_proceed_ctx->userCtx, peer, OC_STACK_AUTHENTICATION_FAILURE);\r
541             }\r
542 \r
543 #ifdef __WITH_DTLS__\r
544             CARegisterDTLSHandshakeCallback(NULL);\r
545 #endif // __WITH_DTLS__\r
546             res = RemoveCredential(&peer->deviceID);\r
547             if(OC_STACK_RESOURCE_DELETED != res)\r
548             {\r
549                 OIC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);\r
550             }\r
551 \r
552             OICFree(g_dp_proceed_ctx);\r
553             g_dp_proceed_ctx = NULL;\r
554         }\r
555         else\r
556         {\r
557             OIC_LOG_V(INFO, TAG, "DirectPairingDTLSHandshakeCB - Not matched to peer address");\r
558         }\r
559     }\r
560 \r
561     OIC_LOG_V(INFO, TAG, "OUT DirectPairingDTLSHandshakeCB");\r
562 }\r
563 \r
564 /**\r
565  * Callback handler of DPDirectPairing.\r
566  *\r
567  * @param[in] ctx             ctx value passed to callback from calling function.\r
568  * @param[in] UNUSED          handle to an invocation\r
569  * @param[in] clientResponse  Response from queries to remote servers.\r
570  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction\r
571  *          and  OC_STACK_KEEP_TRANSACTION to keep it.\r
572  */\r
573 static OCStackApplicationResult DirectPairingHandler(void *ctx, OCDoHandle UNUSED,\r
574                                                   OCClientResponse *clientResponse)\r
575 {\r
576     OIC_LOG_V(INFO, TAG, "IN DirectPairingHandler.");\r
577     (void)UNUSED;\r
578     if(NULL == ctx)\r
579     {\r
580         OIC_LOG(ERROR, TAG, "Context is Null");\r
581         return OC_STACK_DELETE_TRANSACTION;\r
582     }\r
583 \r
584     OCStackResult res = OC_STACK_ERROR;\r
585     DPairData_t *dpairData = (DPairData_t*)ctx;\r
586     OCDirectPairingResultCB resultCallback = (OCDirectPairingResultCB)dpairData->resultCallback;\r
587     OicUuid_t subjectId = {.id={0}};\r
588 \r
589     if (clientResponse)\r
590     {\r
591         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)\r
592         {\r
593             // result\r
594             OIC_LOG(INFO, TAG, "DirectPairingHandler : success POST request to /oic/sec/dpairing");\r
595 \r
596 #ifdef __WITH_DTLS__\r
597             // Add temporary psk\r
598             res = AddTmpPskWithPIN(&dpairData->peer->deviceID,\r
599                            SYMMETRIC_PAIR_WISE_KEY,\r
600                            (char*)dpairData->pin, DP_PIN_LENGTH,\r
601                            &dpairData->peer->rowner, &subjectId);\r
602             VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);\r
603 \r
604 \r
605             // Start to establish a secure channel with Pin-based PSK cipher suite\r
606             CAResult_t caresult;\r
607 \r
608             caresult = CAEnableAnonECDHCipherSuite(false);\r
609             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
610 \r
611             caresult = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);\r
612             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
613 \r
614             //Register proceeding peer info. & DTLS event handler to catch the dtls event while handshake\r
615             g_dp_proceed_ctx = dpairData;\r
616             res = CARegisterDTLSHandshakeCallback(DirectPairingDTLSHandshakeCB);\r
617             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
618 \r
619             // initiate dtls\r
620             CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t));\r
621             VERIFY_NON_NULL(TAG, endpoint, FATAL);\r
622             memcpy(endpoint,&dpairData->peer->endpoint,sizeof(CAEndpoint_t));\r
623             endpoint->port = dpairData->peer->securePort;\r
624             OIC_LOG_V(INFO, TAG, "Initiate DTLS handshake to %s(%d)", endpoint->addr,\r
625                     endpoint->port);\r
626 \r
627             caresult = CAInitiateHandshake(endpoint);\r
628             OICFree(endpoint);\r
629             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
630 #endif // __WITH_DTLS__\r
631 \r
632             res = OC_STACK_OK;\r
633         }\r
634         else\r
635         {\r
636             // result\r
637             OIC_LOG(INFO, TAG, "DirectPairingHandler : fail POST request to /oic/sec/dpairing");\r
638         }\r
639     }\r
640     else\r
641     {\r
642         OIC_LOG(ERROR, TAG, "DirectPairingHandler received Null clientResponse");\r
643     }\r
644 \r
645 #ifdef __WITH_DTLS__\r
646 exit:\r
647 #endif // __WITH_DTLS__\r
648 \r
649     if (OC_STACK_OK != res)\r
650     {\r
651         if (0 < strlen((const char*)subjectId.id))\r
652         {\r
653             RemoveCredential(&dpairData->peer->deviceID);\r
654             OICFree(dpairData);\r
655             g_dp_proceed_ctx = NULL;\r
656         }\r
657 \r
658         resultCallback(dpairData->userCtx, dpairData->peer, res);\r
659     }\r
660     OIC_LOG_V(INFO, TAG, "OUT DirectPairingHandler.");\r
661     return OC_STACK_DELETE_TRANSACTION;\r
662 }\r
663 \r
664 /**\r
665  * Start direct-pairing .\r
666  *\r
667  * @param[in] peer  target device to establish direct-pairing.\r
668  * @param[in] pmSel  selected pairing method.\r
669  * @param[in] pinNumber  secret value for dtls connection.\r
670  *\r
671  * @return OC_STACK_OK on success otherwise error.\r
672  */\r
673 OCStackResult DPDirectPairing(void *ctx, OCDirectPairingDev_t* peer, OicSecPrm_t pmSel,\r
674                                 char *pinNumber, OCDirectPairingResultCB resultCallback)\r
675 {\r
676     if(NULL == peer || NULL == pinNumber)\r
677     {\r
678         return OC_STACK_INVALID_PARAM;\r
679     }\r
680 \r
681     OicUuid_t deviceID =   {.id={0}};\r
682     if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))\r
683     {\r
684         OIC_LOG(ERROR, TAG, "Error while retrieving device ID");\r
685         return OC_STACK_ERROR;\r
686     }\r
687 \r
688     OicSecDpairing_t dpair;\r
689     memset(&dpair, 0, sizeof(OicSecDpairing_t));\r
690     dpair.spm = pmSel;\r
691     memcpy(&dpair.pdeviceID, &deviceID, sizeof(OicUuid_t));\r
692 \r
693     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));\r
694     if(!secPayload)\r
695     {\r
696         OIC_LOG(ERROR, TAG, "Failed to memory allocation");\r
697         return OC_STACK_NO_MEMORY;\r
698     }\r
699     secPayload->base.type = PAYLOAD_TYPE_SECURITY;\r
700 \r
701     OCStackResult ret = DpairingToCBORPayload(&dpair, &(secPayload->securityData),\r
702             &(secPayload->payloadSize));\r
703 \r
704     if(OC_STACK_OK != ret)\r
705     {\r
706         OICFree(secPayload);\r
707         OIC_LOG(ERROR, TAG, "Failed to DpairingToCBORPayload");\r
708         return OC_STACK_NO_MEMORY;\r
709     }\r
710     OIC_LOG(INFO, TAG, "DPARING CBOR data:");\r
711     OIC_LOG_BUFFER(INFO, TAG, secPayload->securityData, secPayload->payloadSize);\r
712 \r
713     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};\r
714     if(!DPGenerateQuery(false,\r
715                         peer->endpoint.addr,\r
716                         peer->endpoint.port,\r
717                         //peer->securePort,\r
718                         peer->connType,\r
719                         query, sizeof(query), OIC_RSRC_DPAIRING_URI))\r
720     {\r
721         OIC_LOG(ERROR, TAG, "DPDirectPairing : Failed to generate query");\r
722         return OC_STACK_ERROR;\r
723     }\r
724     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);\r
725 \r
726     DPairData_t *dpairData = (DPairData_t *) OICCalloc(1, sizeof(DPairData_t));\r
727     if (dpairData == NULL)\r
728     {\r
729         OICFree(secPayload->securityData);\r
730         OICFree(secPayload);\r
731         OIC_LOG(ERROR, TAG, "Unable to allocate memory");\r
732         return OC_STACK_NO_MEMORY;\r
733     }\r
734     dpairData->peer = peer;\r
735     memcpy(dpairData->pin, pinNumber, DP_PIN_LENGTH);\r
736     dpairData->resultCallback = resultCallback;\r
737     dpairData->userCtx = ctx;\r
738 \r
739     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};\r
740     cbData.cb = DirectPairingHandler;\r
741     cbData.context = (void*)dpairData;\r
742     cbData.cd = NULL;\r
743 \r
744     OCMethod method = OC_REST_POST;\r
745     OCDoHandle handle = NULL;\r
746     OIC_LOG(DEBUG, TAG, "Sending DPAIRNG setting to resource server");\r
747     ret = OCDoResource(&handle, method, query,\r
748             &peer->endpoint, (OCPayload*)secPayload,\r
749             peer->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
750     if(OC_STACK_OK != ret)\r
751     {\r
752         OIC_LOG(ERROR, TAG, "error in OCDoResource");\r
753         return OC_STACK_ERROR;\r
754     }\r
755 \r
756     return OC_STACK_OK;\r
757 \r
758  }\r
759 \r
760 /**\r
761  * Callback handler for getting secure port information using /oic/res discovery.\r
762  *\r
763  * @param[in] ctx             user context\r
764  * @param[in] handle          Handle for response\r
765  * @param[in] clientResponse  Response information(It will contain payload)\r
766  *\r
767  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and\r
768  *         OC_STACK_DELETE_TRANSACTION to delete it.\r
769  */\r
770 static OCStackApplicationResult DirectPairingPortDiscoveryHandler(void *ctx, OCDoHandle UNUSED,\r
771                                  OCClientResponse *clientResponse)\r
772 {\r
773     OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing Secure Port DISCOVER "\r
774             "query recvd successfully");\r
775 \r
776     (void)ctx;\r
777     (void)UNUSED;\r
778     if (clientResponse)\r
779     {\r
780         if  (NULL == clientResponse->payload)\r
781         {\r
782             OIC_LOG(INFO, TAG, "Skiping Null payload");\r
783         }\r
784         else\r
785         {\r
786             if (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type)\r
787             {\r
788                 OIC_LOG(INFO, TAG, "Wrong payload type");\r
789                 return OC_STACK_DELETE_TRANSACTION;\r
790             }\r
791 \r
792             uint16_t securePort = 0;\r
793             OCResourcePayload* resPayload = ((OCDiscoveryPayload*)clientResponse->payload)->resources;\r
794             OIC_LOG_PAYLOAD(INFO, clientResponse->payload);\r
795 \r
796             if (resPayload && resPayload->secure)\r
797             {\r
798                 securePort = resPayload->port;\r
799             }\r
800             else\r
801             {\r
802                 OIC_LOG(INFO, TAG, "Can not find secure port information.");\r
803                 return OC_STACK_DELETE_TRANSACTION;\r
804             }\r
805 \r
806             OCDirectPairingDev_t *ptr = getDev(&g_dp_discover,\r
807                     clientResponse->devAddr.addr, clientResponse->devAddr.port);\r
808             if(!ptr)\r
809             {\r
810                 OIC_LOG(ERROR, TAG, "Can not find device information in the discovery device list");\r
811                 return OC_STACK_DELETE_TRANSACTION;\r
812             }\r
813             ptr->securePort = securePort;\r
814 \r
815             OIC_LOG(INFO, TAG, "Exiting DirectPairingPortDiscoveryHandler.");\r
816         }\r
817 \r
818         return  OC_STACK_DELETE_TRANSACTION;\r
819     }\r
820     else\r
821     {\r
822         OIC_LOG(INFO, TAG, "Skiping Null response");\r
823     }\r
824     return  OC_STACK_DELETE_TRANSACTION;\r
825 }\r
826 \r
827 /**\r
828  * Callback handler for DPDeviceDiscovery API.\r
829  *\r
830  * @param[in] ctx             User context\r
831  * @param[in] handle          Handler for response\r
832  * @param[in] clientResponse  Response information (It will contain payload)\r
833  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and\r
834  *         OC_STACK_DELETE_TRANSACTION to delete it.\r
835  */\r
836 static OCStackApplicationResult DirectPairingDiscoveryHandler(void* ctx, OCDoHandle UNUSED,\r
837         OCClientResponse * clientResponse)\r
838 {\r
839     OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing DISCOVER query recvd successfully");\r
840 \r
841     (void)ctx;\r
842     (void)UNUSED;\r
843     if (clientResponse)\r
844     {\r
845         OIC_LOG_V(INFO, TAG, "StackResult: %d", clientResponse->result);\r
846         OIC_LOG_V(INFO, TAG,\r
847                 "Device =============> Discovered @ %s:%d",\r
848                 clientResponse->devAddr.addr,\r
849                 clientResponse->devAddr.port);\r
850 \r
851         if  (NULL == clientResponse->payload)\r
852         {\r
853             OIC_LOG(INFO, TAG, "Skiping Null payload");\r
854             return OC_STACK_KEEP_TRANSACTION;\r
855         }\r
856         if (OC_STACK_OK != clientResponse->result)\r
857         {\r
858             OIC_LOG(INFO, TAG, "Error in response");\r
859             return OC_STACK_KEEP_TRANSACTION;\r
860         }\r
861 \r
862         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);\r
863         OicSecPconf_t *pconf = NULL;\r
864 \r
865         OCStackResult res = CBORPayloadToPconf(\r
866                 ((OCSecurityPayload*)clientResponse->payload)->securityData,\r
867                 CBOR_SIZE,&pconf);\r
868         if (OC_STACK_OK != res )\r
869         {\r
870             OIC_LOG(INFO, TAG, "Ignoring malformed CBOR");\r
871             return OC_STACK_KEEP_TRANSACTION;\r
872         }\r
873         else\r
874         {\r
875             if(pconf->edp)\r
876             {\r
877                 OCDevAddr endpoint;\r
878                 memcpy(&endpoint, &clientResponse->devAddr, sizeof(OCDevAddr));\r
879 \r
880                 OCStackResult res = addDev(&g_dp_discover, &endpoint,\r
881                             clientResponse->connType, pconf);\r
882                 DeletePconfBinData(pconf);\r
883                 if (OC_STACK_OK != res)\r
884                 {\r
885                     OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");\r
886                     return OC_STACK_KEEP_TRANSACTION;\r
887                 }\r
888 \r
889 \r
890                 char rsrc_uri[MAX_URI_LENGTH+1] = {0};\r
891                 int wr_len = snprintf(rsrc_uri, sizeof(rsrc_uri), "%s?%s=%s",\r
892                           OC_RSRVD_WELL_KNOWN_URI, OC_RSRVD_RESOURCE_TYPE, OIC_RSRC_TYPE_SEC_DPAIRING);\r
893                 if(wr_len <= 0 || (size_t)wr_len >= sizeof(rsrc_uri))\r
894                 {\r
895                     OIC_LOG(ERROR, TAG, "rsrc_uri_string_print failed");\r
896                     return OC_STACK_KEEP_TRANSACTION;\r
897                 }\r
898 \r
899                 //Try to the unicast discovery to getting secure port\r
900                 char query[MAX_URI_LENGTH+MAX_QUERY_LENGTH+1] = {0};\r
901                 if(!DPGenerateQuery(false,\r
902                                     clientResponse->devAddr.addr, clientResponse->devAddr.port,\r
903                                     clientResponse->connType,\r
904                                     query, sizeof(query), rsrc_uri))\r
905                 {\r
906                     OIC_LOG(ERROR, TAG, "DirectPairingDiscoveryHandler : Failed to generate query");\r
907                     return OC_STACK_KEEP_TRANSACTION;\r
908                 }\r
909                 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);\r
910 \r
911                 OCCallbackData cbData;\r
912                 cbData.cb = &DirectPairingPortDiscoveryHandler;\r
913                 cbData.context = NULL;\r
914                 cbData.cd = NULL;\r
915                 OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, query, 0, 0,\r
916                         clientResponse->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
917                 if(OC_STACK_OK != ret)\r
918                 {\r
919                     OIC_LOG(ERROR, TAG, "Failed to Secure Port Discovery");\r
920                     return OC_STACK_KEEP_TRANSACTION;\r
921                 }\r
922                 else\r
923                 {\r
924                     OIC_LOG_V(INFO, TAG, "OCDoResource with [%s] Success", query);\r
925                 }\r
926             }\r
927             return  OC_STACK_KEEP_TRANSACTION;\r
928         }\r
929     }\r
930     else\r
931     {\r
932         OIC_LOG(INFO, TAG, "Skiping Null response");\r
933     }\r
934 \r
935     return OC_STACK_DELETE_TRANSACTION;\r
936 }\r
937 #ifndef WITH_ARDUINO\r
938 /**\r
939  * Discover direct-pairing devices in the same IP subnet. .\r
940  *\r
941  * @param[in] waittime  Timeout in seconds.\r
942  *\r
943  * @return OC_STACK_OK on success otherwise error.\r
944  */\r
945 OCStackResult DPDeviceDiscovery(unsigned short waittime)\r
946 {\r
947     OIC_LOG(DEBUG, TAG, "IN DPDeviceDiscovery");\r
948 \r
949     if (g_dp_discover)\r
950     {\r
951         delList(g_dp_discover);\r
952         g_dp_discover = NULL;\r
953     }\r
954 \r
955     OCStackResult ret;\r
956     struct timespec startTime = {.tv_sec=0, .tv_nsec=0};\r
957     struct timespec currTime  = {.tv_sec=0, .tv_nsec=0};\r
958     struct timespec timeout;\r
959 \r
960     const char DP_DISCOVERY_QUERY[] = "/oic/sec/pconf";\r
961 \r
962     OCCallbackData cbData;\r
963     cbData.cb = DirectPairingDiscoveryHandler;\r
964     cbData.context = NULL;\r
965     cbData.cd = NULL;\r
966 \r
967     /* Start a DP discovery query*/\r
968     OIC_LOG_V(INFO, TAG, "Initiating Direct-Pairing Discovery : %s\n", DP_DISCOVERY_QUERY);\r
969     OCDoHandle handle = NULL;\r
970     ret = OCDoResource(&handle, OC_REST_DISCOVER, DP_DISCOVERY_QUERY, 0, 0, CT_DEFAULT,\r
971                        OC_LOW_QOS, &cbData, NULL, 0);\r
972     if (ret != OC_STACK_OK)\r
973     {\r
974         OIC_LOG(ERROR, TAG, "OCStack resource error");\r
975         return ret;\r
976     }\r
977 \r
978     // wait..\r
979     timeout.tv_sec  = 0;\r
980     timeout.tv_nsec = 100000000L;\r
981 \r
982     int clock_res = -1;\r
983 #if defined(__ANDROID__) || _POSIX_TIMERS > 0\r
984     clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);\r
985 #endif\r
986     if (0 != clock_res)\r
987     {\r
988         OIC_LOG(ERROR, TAG, "clock error");\r
989         if(OC_STACK_OK !=  OCCancel(handle, OC_LOW_QOS, NULL, 0))\r
990         {\r
991             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");\r
992         }\r
993         return OC_STACK_ERROR;\r
994     }\r
995 \r
996     while (1)\r
997     {\r
998 #if defined(__ANDROID__) || _POSIX_TIMERS > 0\r
999         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);\r
1000 #endif\r
1001         if (0 != clock_res)\r
1002         {\r
1003             OIC_LOG(ERROR, TAG, "clock error");\r
1004             ret = OC_STACK_ERROR;\r
1005             break;\r
1006         }\r
1007         long elapsed = (currTime.tv_sec - startTime.tv_sec);\r
1008         if (elapsed > waittime)\r
1009         {\r
1010             break;\r
1011         }\r
1012         else\r
1013         {\r
1014             OCProcess();\r
1015             nanosleep(&timeout, NULL);\r
1016         }\r
1017     }\r
1018 \r
1019     //Waiting for each response.\r
1020     ret = OCCancel(handle, OC_LOW_QOS, NULL, 0);\r
1021     if (OC_STACK_OK != ret)\r
1022     {\r
1023         OIC_LOG(ERROR, TAG, "Failed to remove registered callback");\r
1024     }\r
1025     OIC_LOG(DEBUG, TAG, "OUT DPDeviceDiscovery");\r
1026     return ret;\r
1027 }\r
1028 #endif\r