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