Merge remote-tracking branch 'origin/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     static char QPREFIX_COAP_TCP[] =  "coap+tcp://";\r
249     static char QPREFIX_COAPS_TCP[] = "coaps+tcp://";\r
250 \r
251     int snRet = 0;\r
252     char* prefix = (isSecure == true) ? QPREFIX_COAPS : QPREFIX_COAP;\r
253 \r
254     switch(connType & CT_MASK_ADAPTER)\r
255     {\r
256 // @todo: Remove this ifdef. On Arduino, CT_ADAPTER_TCP resolves to the same value\r
257 // as CT_ADAPTER_IP, resulting in a compiler error.\r
258 #ifdef WITH_TCP\r
259 #ifndef WITH_ARDUINO\r
260         case CT_ADAPTER_TCP:\r
261             prefix = (isSecure == true) ? QPREFIX_COAPS_TCP : QPREFIX_COAP_TCP;\r
262 #endif\r
263 #endif\r
264         case CT_ADAPTER_IP:\r
265             switch(connType & CT_MASK_FLAGS & ~CT_FLAG_SECURE)\r
266             {\r
267                 case CT_IP_USE_V4:\r
268                         snRet = snprintf(buffer, bufferSize, "%s%s:%d%s",\r
269                                          prefix, address, port, uri);\r
270                     break;\r
271                 case CT_IP_USE_V6:\r
272                         snRet = snprintf(buffer, bufferSize, "%s[%s]:%d%s",\r
273                                          prefix, address, port, uri);\r
274                     break;\r
275                 default:\r
276                     OIC_LOG(ERROR, TAG, "Unknown address format.");\r
277                     return false;\r
278             }\r
279             // snprintf return value check\r
280             if (snRet < 0)\r
281             {\r
282                 OIC_LOG_V(ERROR, TAG, "DPGenerateQuery : Error (snprintf) %d\n", snRet);\r
283                 return false;\r
284             }\r
285             else if ((size_t)snRet >= bufferSize)\r
286             {\r
287                 OIC_LOG_V(ERROR, TAG, "DPGenerateQuery : Truncated (snprintf) %d\n", snRet);\r
288                 return false;\r
289             }\r
290 \r
291             break;\r
292 #ifndef WITH_ARDUINO\r
293         // TODO: We need to verify tinyDTLS in below cases\r
294         case CT_ADAPTER_GATT_BTLE:\r
295         case CT_ADAPTER_RFCOMM_BTEDR:\r
296             OIC_LOG(ERROR, TAG, "Not supported connectivity adapter.");\r
297             return false;\r
298             break;\r
299 #endif\r
300         default:\r
301             OIC_LOG(ERROR, TAG, "Unknown connectivity adapter.");\r
302             return false;\r
303     }\r
304 \r
305     return true;\r
306 }\r
307 \r
308 const OCDirectPairingDev_t* DPGetDiscoveredDevices()\r
309 {\r
310     return g_dp_discover;\r
311 }\r
312 \r
313 const OCDirectPairingDev_t* DPGetPairedDevices()\r
314 {\r
315     return g_dp_paired;\r
316 }\r
317 \r
318 void DPDeleteLists()\r
319 {\r
320     delList(g_dp_discover);\r
321     delList(g_dp_paired);\r
322 }\r
323 \r
324 /**\r
325  * Callback handler of FinalizeDirectPairing.\r
326  *\r
327  * @param[in] ctx             ctx value passed to callback from calling function.\r
328  * @param[in] UNUSED          handle to an invocation\r
329  * @param[in] clientResponse  Response from queries to remote servers.\r
330  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction\r
331  *          and  OC_STACK_KEEP_TRANSACTION to keep it.\r
332  */\r
333 static OCStackApplicationResult DirectPairingFinalizeHandler(void *ctx, OCDoHandle UNUSED,\r
334                                                   OCClientResponse *clientResponse)\r
335 {\r
336     OIC_LOG_V(INFO, TAG, "IN DirectPairingFinalizeHandler()");\r
337     (void)UNUSED;\r
338     if(NULL == ctx)\r
339     {\r
340         OIC_LOG(ERROR, TAG, "Context is Null");\r
341         return OC_STACK_DELETE_TRANSACTION;\r
342     }\r
343 \r
344     OCStackResult res;\r
345     DPairData_t *dpairData = (DPairData_t*)ctx;\r
346     OCDirectPairingDev_t *peer = dpairData->peer;\r
347     OCDirectPairingResultCB resultCallback = dpairData->resultCallback;\r
348 \r
349     if (clientResponse)\r
350     {\r
351         if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)\r
352         {\r
353             // result\r
354             OIC_LOG(INFO, TAG, "DirectPairingFinalizeHandler : success PUT"\r
355                     " request to /oic/sec/dpairing");\r
356 \r
357             CAEndpoint_t endpoint;\r
358             memset(&endpoint, 0x00, sizeof(CAEndpoint_t));\r
359             OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, peer->endpoint.addr);\r
360             endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';\r
361             endpoint.port = peer->securePort;\r
362 \r
363             OicUuid_t ptDeviceID = {.id={0}};\r
364             if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID))\r
365             {\r
366                 OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");\r
367                 resultCallback(dpairData->userCtx, peer, OC_STACK_ERROR);\r
368                 return OC_STACK_DELETE_TRANSACTION;\r
369             }\r
370 \r
371 #ifdef __WITH_DTLS__\r
372             res = SavePairingPSK((OCDevAddr*)&endpoint, &peer->deviceID, &ptDeviceID, false);\r
373             if(OC_STACK_OK != res)\r
374             {\r
375                 OIC_LOG(ERROR, TAG, "Failed to PairingPSK generation");\r
376                 resultCallback(dpairData->userCtx, peer, res);\r
377                 return OC_STACK_DELETE_TRANSACTION;\r
378             }\r
379 \r
380             //  close temporary sesion\r
381             CAResult_t caResult = CACloseDtlsSession((const CAEndpoint_t*)&endpoint);\r
382             if(CA_STATUS_OK != caResult)\r
383             {\r
384                 OIC_LOG(INFO, TAG, "Fail to close temporary dtls session");\r
385             }\r
386 \r
387             caResult = CASelectCipherSuite(TLS_NULL_WITH_NULL_NULL, CA_ADAPTER_IP);\r
388             if(CA_STATUS_OK != caResult)\r
389             {\r
390                 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");\r
391             }\r
392 #endif // __WITH_DTLS__\r
393 \r
394             OIC_LOG(INFO, TAG, "Direct-Papring was successfully completed.");\r
395 \r
396             // update paired list\r
397             OCDirectPairingDev_t *dev = getDev(&g_dp_discover, peer->endpoint.addr,\r
398                     peer->endpoint.port);\r
399             res = addDev2(&g_dp_paired, dev);\r
400             if (OC_STACK_OK != res)\r
401             {\r
402                 OIC_LOG(ERROR, TAG, "Error while adding a device to paired list.");\r
403             }\r
404 \r
405             resultCallback(dpairData->userCtx, peer, OC_STACK_OK);\r
406 \r
407             return OC_STACK_DELETE_TRANSACTION;\r
408         }\r
409         else\r
410         {\r
411             OIC_LOG(INFO, TAG, "Direct-Papring received error response.");\r
412         }\r
413     }\r
414     else\r
415     {\r
416         OIC_LOG(ERROR, TAG, "DirectPairingFinalizeHandler received Null clientResponse");\r
417     }\r
418 \r
419     resultCallback(dpairData->userCtx, peer, OC_STACK_ERROR);\r
420     OICFree(dpairData);\r
421     return OC_STACK_DELETE_TRANSACTION;\r
422 }\r
423 \r
424 /**\r
425  * Finalize direct-pairing .\r
426  *\r
427  * @param[in] peer  target device to establish direct-pairing.\r
428  * @param[in] resultCallback  result event callback.\r
429  *\r
430  * @return OC_STACK_OK on success otherwise error.\r
431  */\r
432 OCStackResult FinalizeDirectPairing(void *ctx, OCDirectPairingDev_t* peer,\r
433                                                      OCDirectPairingResultCB resultCallback)\r
434 {\r
435     if(NULL == peer)\r
436     {\r
437         return OC_STACK_INVALID_PARAM;\r
438     }\r
439 \r
440     OicUuid_t deviceID =   {.id={0}};\r
441     if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))\r
442     {\r
443         OIC_LOG(ERROR, TAG, "Error while retrieving device ID");\r
444         return OC_STACK_ERROR;\r
445     }\r
446 \r
447     OicSecDpairing_t dpair;\r
448     memset(&dpair, 0, sizeof(OicSecDpairing_t));\r
449     dpair.spm = (OicSecPrm_t)PRM_NOT_ALLOWED;\r
450     memcpy(&dpair.pdeviceID, &deviceID, sizeof(OicUuid_t));\r
451 \r
452     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));\r
453     if(!secPayload)\r
454     {\r
455         OIC_LOG(ERROR, TAG, "Failed to memory allocation");\r
456         return OC_STACK_NO_MEMORY;\r
457     }\r
458     secPayload->base.type = PAYLOAD_TYPE_SECURITY;\r
459 \r
460     OCStackResult ret = DpairingToCBORPayload(&dpair, &(secPayload->securityData),\r
461             &(secPayload->payloadSize));\r
462 \r
463     if(OC_STACK_OK != ret)\r
464     {\r
465         OICFree(secPayload);\r
466         OIC_LOG(ERROR, TAG, "Failed to DpairingToCBORPayload");\r
467         return OC_STACK_NO_MEMORY;\r
468     }\r
469     OIC_LOG(INFO, TAG, "DPARING CBOR data:");\r
470     OIC_LOG_BUFFER(INFO, TAG, secPayload->securityData, secPayload->payloadSize);\r
471 \r
472     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};\r
473     if(!DPGenerateQuery(true,\r
474                         peer->endpoint.addr,\r
475                         peer->securePort,\r
476                         peer->connType,\r
477                         query, sizeof(query), OIC_RSRC_DPAIRING_URI))\r
478     {\r
479         OIC_LOG(ERROR, TAG, "DPDirectPairing : Failed to generate query");\r
480         return OC_STACK_ERROR;\r
481     }\r
482     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);\r
483 \r
484     DPairData_t *dpairData = (DPairData_t *) OICCalloc(1, sizeof(DPairData_t));\r
485     if (dpairData == NULL)\r
486     {\r
487         OICFree(secPayload->securityData);\r
488         OICFree(secPayload);\r
489         OIC_LOG(ERROR, TAG, "Unable to allocate memory");\r
490         return OC_STACK_NO_MEMORY;\r
491     }\r
492     dpairData->peer = peer;\r
493     dpairData->resultCallback = resultCallback;\r
494     dpairData->userCtx = ctx;\r
495 \r
496     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};\r
497     cbData.cb = DirectPairingFinalizeHandler;\r
498     cbData.context = (void*)dpairData;\r
499     cbData.cd = NULL;\r
500 \r
501     OCMethod method = OC_REST_PUT;\r
502     OCDoHandle handle = NULL;\r
503     OIC_LOG(DEBUG, TAG, "Sending DPAIRNG setting to resource server");\r
504     ret = OCDoResource(&handle, method, query,\r
505             &peer->endpoint, (OCPayload*)secPayload,\r
506             peer->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
507     if(OC_STACK_OK != ret)\r
508     {\r
509         OIC_LOG(ERROR, TAG, "error in OCDoResource");\r
510         return OC_STACK_ERROR;\r
511     }\r
512 \r
513     return OC_STACK_OK;\r
514  }\r
515 \r
516 /**\r
517  * Function to handle the handshake result in Direct-Pairing.\r
518  * This function will be invoked after DTLS handshake\r
519  * @param   endPoint  [IN] The remote endpoint.\r
520  * @param   errorInfo [IN] Error information from the endpoint.\r
521  * @return  NONE\r
522  */\r
523 void DirectPairingDTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)\r
524 {\r
525     OIC_LOG_V(INFO, TAG, "IN DirectPairingDTLSHandshakeCB");\r
526 \r
527 \r
528     if(g_dp_proceed_ctx && g_dp_proceed_ctx->peer && endpoint && info)\r
529     {\r
530         OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",\r
531                  endpoint->addr, endpoint->port, info->result);\r
532 \r
533         OCDirectPairingDev_t *peer = g_dp_proceed_ctx->peer;\r
534         OCDirectPairingResultCB resultCallback = g_dp_proceed_ctx->resultCallback;\r
535         OCStackResult res;\r
536 \r
537         //Make sure the address matches.\r
538         if(strncmp(peer->endpoint.addr, endpoint->addr, sizeof(endpoint->addr)) == 0 &&\r
539                          peer->securePort == endpoint->port)\r
540         {\r
541             //In case of success, send next coaps request.\r
542             if(CA_STATUS_OK == info->result)\r
543             {\r
544                 OIC_LOG(INFO, TAG, "Now, finalize Direct-Pairing procedure.");\r
545 \r
546                 res = FinalizeDirectPairing(g_dp_proceed_ctx->userCtx, peer, resultCallback);\r
547                 if(OC_STACK_OK != res)\r
548                 {\r
549                     OIC_LOG(ERROR, TAG, "Failed to finalize direct-pairing");\r
550                     resultCallback(g_dp_proceed_ctx->userCtx, peer, res);\r
551                 }\r
552             }\r
553             else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)\r
554             {\r
555                 OIC_LOG(INFO, TAG, "DirectPairingDTLSHandshakeCB - Authentication failed");\r
556                 resultCallback(g_dp_proceed_ctx->userCtx, peer, OC_STACK_AUTHENTICATION_FAILURE);\r
557             }\r
558 \r
559 #ifdef __WITH_DTLS__\r
560             CARegisterDTLSHandshakeCallback(NULL);\r
561 #endif // __WITH_DTLS__\r
562             res = RemoveCredential(&peer->deviceID);\r
563             if(OC_STACK_RESOURCE_DELETED != res)\r
564             {\r
565                 OIC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);\r
566             }\r
567 \r
568             OICFree(g_dp_proceed_ctx);\r
569             g_dp_proceed_ctx = NULL;\r
570         }\r
571         else\r
572         {\r
573             OIC_LOG_V(INFO, TAG, "DirectPairingDTLSHandshakeCB - Not matched to peer address");\r
574         }\r
575     }\r
576 \r
577     OIC_LOG_V(INFO, TAG, "OUT DirectPairingDTLSHandshakeCB");\r
578 }\r
579 \r
580 /**\r
581  * Callback handler of DPDirectPairing.\r
582  *\r
583  * @param[in] ctx             ctx value passed to callback from calling function.\r
584  * @param[in] UNUSED          handle to an invocation\r
585  * @param[in] clientResponse  Response from queries to remote servers.\r
586  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction\r
587  *          and  OC_STACK_KEEP_TRANSACTION to keep it.\r
588  */\r
589 static OCStackApplicationResult DirectPairingHandler(void *ctx, OCDoHandle UNUSED,\r
590                                                   OCClientResponse *clientResponse)\r
591 {\r
592     OIC_LOG_V(INFO, TAG, "IN DirectPairingHandler.");\r
593     (void)UNUSED;\r
594     if(NULL == ctx)\r
595     {\r
596         OIC_LOG(ERROR, TAG, "Context is Null");\r
597         return OC_STACK_DELETE_TRANSACTION;\r
598     }\r
599 \r
600     OCStackResult res = OC_STACK_ERROR;\r
601     DPairData_t *dpairData = (DPairData_t*)ctx;\r
602     OCDirectPairingResultCB resultCallback = (OCDirectPairingResultCB)dpairData->resultCallback;\r
603     OicUuid_t subjectId = {.id={0}};\r
604 \r
605     if (clientResponse)\r
606     {\r
607         if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)\r
608         {\r
609             // result\r
610             OIC_LOG(INFO, TAG, "DirectPairingHandler : success POST request to /oic/sec/dpairing");\r
611 \r
612 #ifdef __WITH_DTLS__\r
613             // Add temporary psk\r
614             res = AddTmpPskWithPIN(&dpairData->peer->deviceID,\r
615                            SYMMETRIC_PAIR_WISE_KEY,\r
616                            (char*)dpairData->pin, DP_PIN_LENGTH,\r
617                            &dpairData->peer->rowner, &subjectId);\r
618             VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);\r
619 \r
620 \r
621             // Start to establish a secure channel with Pin-based PSK cipher suite\r
622             CAResult_t caresult;\r
623 \r
624             caresult = CAEnableAnonECDHCipherSuite(false);\r
625             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
626 \r
627             caresult = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, CA_ADAPTER_IP);\r
628             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
629 \r
630             //Register proceeding peer info. & DTLS event handler to catch the dtls event while handshake\r
631             g_dp_proceed_ctx = dpairData;\r
632             res = CARegisterDTLSHandshakeCallback(DirectPairingDTLSHandshakeCB);\r
633             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
634 \r
635             // initiate dtls\r
636             CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t));\r
637             VERIFY_NON_NULL(TAG, endpoint, FATAL);\r
638             memcpy(endpoint,&dpairData->peer->endpoint,sizeof(CAEndpoint_t));\r
639             endpoint->port = dpairData->peer->securePort;\r
640             OIC_LOG_V(INFO, TAG, "Initiate DTLS handshake to %s(%d)", endpoint->addr,\r
641                     endpoint->port);\r
642 \r
643             caresult = CAInitiateHandshake(endpoint);\r
644             OICFree(endpoint);\r
645             VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);\r
646 #endif // __WITH_DTLS__\r
647 \r
648             res = OC_STACK_OK;\r
649         }\r
650         else\r
651         {\r
652             // result\r
653             OIC_LOG(INFO, TAG, "DirectPairingHandler : fail POST request to /oic/sec/dpairing");\r
654         }\r
655     }\r
656     else\r
657     {\r
658         OIC_LOG(ERROR, TAG, "DirectPairingHandler received Null clientResponse");\r
659     }\r
660 \r
661 #ifdef __WITH_DTLS__\r
662 exit:\r
663 #endif // __WITH_DTLS__\r
664 \r
665     if (OC_STACK_OK != res)\r
666     {\r
667         if (0 < strlen((const char*)subjectId.id))\r
668         {\r
669             RemoveCredential(&dpairData->peer->deviceID);\r
670             OICFree(dpairData);\r
671             g_dp_proceed_ctx = NULL;\r
672         }\r
673 \r
674         resultCallback(dpairData->userCtx, dpairData->peer, res);\r
675     }\r
676     OIC_LOG_V(INFO, TAG, "OUT DirectPairingHandler.");\r
677     return OC_STACK_DELETE_TRANSACTION;\r
678 }\r
679 \r
680 /**\r
681  * Start direct-pairing .\r
682  *\r
683  * @param[in] peer  target device to establish direct-pairing.\r
684  * @param[in] pmSel  selected pairing method.\r
685  * @param[in] pinNumber  secret value for dtls connection.\r
686  *\r
687  * @return OC_STACK_OK on success otherwise error.\r
688  */\r
689 OCStackResult DPDirectPairing(void *ctx, OCDirectPairingDev_t* peer, OicSecPrm_t pmSel,\r
690                                 char *pinNumber, OCDirectPairingResultCB resultCallback)\r
691 {\r
692     if(NULL == peer || NULL == pinNumber)\r
693     {\r
694         return OC_STACK_INVALID_PARAM;\r
695     }\r
696 \r
697     OicUuid_t deviceID =   {.id={0}};\r
698     if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))\r
699     {\r
700         OIC_LOG(ERROR, TAG, "Error while retrieving device ID");\r
701         return OC_STACK_ERROR;\r
702     }\r
703 \r
704     OicSecDpairing_t dpair;\r
705     memset(&dpair, 0, sizeof(OicSecDpairing_t));\r
706     dpair.spm = pmSel;\r
707     memcpy(&dpair.pdeviceID, &deviceID, sizeof(OicUuid_t));\r
708 \r
709     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));\r
710     if(!secPayload)\r
711     {\r
712         OIC_LOG(ERROR, TAG, "Failed to memory allocation");\r
713         return OC_STACK_NO_MEMORY;\r
714     }\r
715     secPayload->base.type = PAYLOAD_TYPE_SECURITY;\r
716 \r
717     OCStackResult ret = DpairingToCBORPayload(&dpair, &(secPayload->securityData),\r
718             &(secPayload->payloadSize));\r
719 \r
720     if(OC_STACK_OK != ret)\r
721     {\r
722         OICFree(secPayload);\r
723         OIC_LOG(ERROR, TAG, "Failed to DpairingToCBORPayload");\r
724         return OC_STACK_NO_MEMORY;\r
725     }\r
726     OIC_LOG(INFO, TAG, "DPARING CBOR data:");\r
727     OIC_LOG_BUFFER(INFO, TAG, secPayload->securityData, secPayload->payloadSize);\r
728 \r
729     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};\r
730     if(!DPGenerateQuery(false,\r
731                         peer->endpoint.addr,\r
732                         peer->endpoint.port,\r
733                         //peer->securePort,\r
734                         peer->connType,\r
735                         query, sizeof(query), OIC_RSRC_DPAIRING_URI))\r
736     {\r
737         OIC_LOG(ERROR, TAG, "DPDirectPairing : Failed to generate query");\r
738         return OC_STACK_ERROR;\r
739     }\r
740     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);\r
741 \r
742     DPairData_t *dpairData = (DPairData_t *) OICCalloc(1, sizeof(DPairData_t));\r
743     if (dpairData == NULL)\r
744     {\r
745         OICFree(secPayload->securityData);\r
746         OICFree(secPayload);\r
747         OIC_LOG(ERROR, TAG, "Unable to allocate memory");\r
748         return OC_STACK_NO_MEMORY;\r
749     }\r
750     dpairData->peer = peer;\r
751     memcpy(dpairData->pin, pinNumber, DP_PIN_LENGTH);\r
752     dpairData->resultCallback = resultCallback;\r
753     dpairData->userCtx = ctx;\r
754 \r
755     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};\r
756     cbData.cb = DirectPairingHandler;\r
757     cbData.context = (void*)dpairData;\r
758     cbData.cd = NULL;\r
759 \r
760     OCMethod method = OC_REST_POST;\r
761     OCDoHandle handle = NULL;\r
762     OIC_LOG(DEBUG, TAG, "Sending DPAIRNG setting to resource server");\r
763     ret = OCDoResource(&handle, method, query,\r
764             &peer->endpoint, (OCPayload*)secPayload,\r
765             peer->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
766     if(OC_STACK_OK != ret)\r
767     {\r
768         OIC_LOG(ERROR, TAG, "error in OCDoResource");\r
769         return OC_STACK_ERROR;\r
770     }\r
771 \r
772     return OC_STACK_OK;\r
773 \r
774  }\r
775 \r
776 /**\r
777  * Callback handler for getting secure port information using /oic/res discovery.\r
778  *\r
779  * @param[in] ctx             user context\r
780  * @param[in] handle          Handle for response\r
781  * @param[in] clientResponse  Response information(It will contain payload)\r
782  *\r
783  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and\r
784  *         OC_STACK_DELETE_TRANSACTION to delete it.\r
785  */\r
786 static OCStackApplicationResult DirectPairingPortDiscoveryHandler(void *ctx, OCDoHandle UNUSED,\r
787                                  OCClientResponse *clientResponse)\r
788 {\r
789     OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing Secure Port DISCOVER "\r
790             "query recvd successfully");\r
791 \r
792     (void)ctx;\r
793     (void)UNUSED;\r
794     if (clientResponse)\r
795     {\r
796         if  (NULL == clientResponse->payload)\r
797         {\r
798             OIC_LOG(INFO, TAG, "Skiping Null payload");\r
799         }\r
800         else\r
801         {\r
802             if (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type)\r
803             {\r
804                 OIC_LOG(INFO, TAG, "Wrong payload type");\r
805                 return OC_STACK_DELETE_TRANSACTION;\r
806             }\r
807 \r
808             uint16_t securePort = 0;\r
809             OCResourcePayload* resPayload = ((OCDiscoveryPayload*)clientResponse->payload)->resources;\r
810             OIC_LOG_PAYLOAD(INFO, clientResponse->payload);\r
811 \r
812             if (resPayload && resPayload->secure)\r
813             {\r
814                 securePort = resPayload->port;\r
815             }\r
816             else\r
817             {\r
818                 OIC_LOG(INFO, TAG, "Can not find secure port information.");\r
819                 return OC_STACK_DELETE_TRANSACTION;\r
820             }\r
821 \r
822             OCDirectPairingDev_t *ptr = getDev(&g_dp_discover,\r
823                     clientResponse->devAddr.addr, clientResponse->devAddr.port);\r
824             if(!ptr)\r
825             {\r
826                 OIC_LOG(ERROR, TAG, "Can not find device information in the discovery device list");\r
827                 return OC_STACK_DELETE_TRANSACTION;\r
828             }\r
829             ptr->securePort = securePort;\r
830 \r
831             OIC_LOG(INFO, TAG, "Exiting DirectPairingPortDiscoveryHandler.");\r
832         }\r
833 \r
834         return  OC_STACK_DELETE_TRANSACTION;\r
835     }\r
836     else\r
837     {\r
838         OIC_LOG(INFO, TAG, "Skiping Null response");\r
839     }\r
840     return  OC_STACK_DELETE_TRANSACTION;\r
841 }\r
842 \r
843 /**\r
844  * Callback handler for DPDeviceDiscovery API.\r
845  *\r
846  * @param[in] ctx             User context\r
847  * @param[in] handle          Handler for response\r
848  * @param[in] clientResponse  Response information (It will contain payload)\r
849  * @return OC_STACK_KEEP_TRANSACTION to keep transaction and\r
850  *         OC_STACK_DELETE_TRANSACTION to delete it.\r
851  */\r
852 static OCStackApplicationResult DirectPairingDiscoveryHandler(void* ctx, OCDoHandle UNUSED,\r
853         OCClientResponse * clientResponse)\r
854 {\r
855     OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing DISCOVER query recvd successfully");\r
856 \r
857     (void)ctx;\r
858     (void)UNUSED;\r
859     if (clientResponse)\r
860     {\r
861         OIC_LOG_V(INFO, TAG, "StackResult: %d", clientResponse->result);\r
862         OIC_LOG_V(INFO, TAG,\r
863                 "Device =============> Discovered @ %s:%d",\r
864                 clientResponse->devAddr.addr,\r
865                 clientResponse->devAddr.port);\r
866 \r
867         if  (NULL == clientResponse->payload)\r
868         {\r
869             OIC_LOG(INFO, TAG, "Skiping Null payload");\r
870             return OC_STACK_KEEP_TRANSACTION;\r
871         }\r
872         if (OC_STACK_OK != clientResponse->result)\r
873         {\r
874             OIC_LOG(INFO, TAG, "Error in response");\r
875             return OC_STACK_KEEP_TRANSACTION;\r
876         }\r
877 \r
878         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);\r
879         OicSecPconf_t *pconf = NULL;\r
880 \r
881         OCStackResult res = CBORPayloadToPconf(\r
882                 ((OCSecurityPayload*)clientResponse->payload)->securityData,\r
883                 CBOR_SIZE,&pconf);\r
884         if (OC_STACK_OK != res )\r
885         {\r
886             OIC_LOG(INFO, TAG, "Ignoring malformed CBOR");\r
887             return OC_STACK_KEEP_TRANSACTION;\r
888         }\r
889         else\r
890         {\r
891             if(pconf->edp)\r
892             {\r
893                 OCDevAddr endpoint;\r
894                 memcpy(&endpoint, &clientResponse->devAddr, sizeof(OCDevAddr));\r
895 \r
896                 OCStackResult res = addDev(&g_dp_discover, &endpoint,\r
897                             clientResponse->connType, pconf);\r
898                 DeletePconfBinData(pconf);\r
899                 if (OC_STACK_OK != res)\r
900                 {\r
901                     OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");\r
902                     return OC_STACK_KEEP_TRANSACTION;\r
903                 }\r
904 \r
905 \r
906                 char rsrc_uri[MAX_URI_LENGTH+1] = {0};\r
907                 int wr_len = snprintf(rsrc_uri, sizeof(rsrc_uri), "%s?%s=%s",\r
908                           OC_RSRVD_WELL_KNOWN_URI, OC_RSRVD_RESOURCE_TYPE, OIC_RSRC_TYPE_SEC_DPAIRING);\r
909                 if(wr_len <= 0 || (size_t)wr_len >= sizeof(rsrc_uri))\r
910                 {\r
911                     OIC_LOG(ERROR, TAG, "rsrc_uri_string_print failed");\r
912                     return OC_STACK_KEEP_TRANSACTION;\r
913                 }\r
914 \r
915                 //Try to the unicast discovery to getting secure port\r
916                 char query[MAX_URI_LENGTH+MAX_QUERY_LENGTH+1] = {0};\r
917                 if(!DPGenerateQuery(false,\r
918                                     clientResponse->devAddr.addr, clientResponse->devAddr.port,\r
919                                     clientResponse->connType,\r
920                                     query, sizeof(query), rsrc_uri))\r
921                 {\r
922                     OIC_LOG(ERROR, TAG, "DirectPairingDiscoveryHandler : Failed to generate query");\r
923                     return OC_STACK_KEEP_TRANSACTION;\r
924                 }\r
925                 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);\r
926 \r
927                 OCCallbackData cbData;\r
928                 cbData.cb = &DirectPairingPortDiscoveryHandler;\r
929                 cbData.context = NULL;\r
930                 cbData.cd = NULL;\r
931                 OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, query, 0, 0,\r
932                         clientResponse->connType, OC_LOW_QOS, &cbData, NULL, 0);\r
933                 if(OC_STACK_OK != ret)\r
934                 {\r
935                     OIC_LOG(ERROR, TAG, "Failed to Secure Port Discovery");\r
936                     return OC_STACK_KEEP_TRANSACTION;\r
937                 }\r
938                 else\r
939                 {\r
940                     OIC_LOG_V(INFO, TAG, "OCDoResource with [%s] Success", query);\r
941                 }\r
942             }\r
943             return  OC_STACK_KEEP_TRANSACTION;\r
944         }\r
945     }\r
946     else\r
947     {\r
948         OIC_LOG(INFO, TAG, "Skiping Null response");\r
949     }\r
950 \r
951     return OC_STACK_DELETE_TRANSACTION;\r
952 }\r
953 #ifndef WITH_ARDUINO\r
954 /**\r
955  * Discover direct-pairing devices in the same IP subnet. .\r
956  *\r
957  * @param[in] waittime  Timeout in seconds.\r
958  *\r
959  * @return OC_STACK_OK on success otherwise error.\r
960  */\r
961 OCStackResult DPDeviceDiscovery(unsigned short waittime)\r
962 {\r
963     OIC_LOG(DEBUG, TAG, "IN DPDeviceDiscovery");\r
964 \r
965     if (g_dp_discover)\r
966     {\r
967         delList(g_dp_discover);\r
968         g_dp_discover = NULL;\r
969     }\r
970 \r
971     OCStackResult ret;\r
972 \r
973     const char DP_DISCOVERY_QUERY[] = "/oic/sec/pconf";\r
974 \r
975     OCCallbackData cbData;\r
976     cbData.cb = DirectPairingDiscoveryHandler;\r
977     cbData.context = NULL;\r
978     cbData.cd = NULL;\r
979 \r
980     /* Start a DP discovery query*/\r
981     OIC_LOG_V(INFO, TAG, "Initiating Direct-Pairing Discovery : %s\n", DP_DISCOVERY_QUERY);\r
982     OCDoHandle handle = NULL;\r
983     ret = OCDoResource(&handle, OC_REST_DISCOVER, DP_DISCOVERY_QUERY, 0, 0, CT_DEFAULT,\r
984                        OC_LOW_QOS, &cbData, NULL, 0);\r
985     if (ret != OC_STACK_OK)\r
986     {\r
987         OIC_LOG(ERROR, TAG, "OCStack resource error");\r
988         return ret;\r
989     }\r
990 \r
991     // wait..\r
992 \r
993     int clock_res = -1;\r
994 #if defined(_MSC_VER)\r
995     time_t startTime = NULL;\r
996     clock_res = (time(&startTime) == -1);\r
997 #else\r
998     struct timespec startTime = {.tv_sec=0, .tv_nsec=0};\r
999 #if defined(__ANDROID__) || _POSIX_TIMERS > 0\r
1000     clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);\r
1001 #endif\r
1002 #endif\r
1003     if (0 != clock_res)\r
1004     {\r
1005         OIC_LOG(ERROR, TAG, "clock error");\r
1006         if(OC_STACK_OK !=  OCCancel(handle, OC_LOW_QOS, NULL, 0))\r
1007         {\r
1008             OIC_LOG(ERROR, TAG, "Failed to remove registered callback");\r
1009         }\r
1010         return OC_STACK_ERROR;\r
1011     }\r
1012 \r
1013     while (1)\r
1014     {\r
1015 #if defined(_MSC_VER)\r
1016         time_t currTime = NULL;\r
1017         clock_res = (time(&currTime) == -1);\r
1018 #else\r
1019         struct timespec currTime  = {.tv_sec=0, .tv_nsec=0};\r
1020 #if defined(__ANDROID__) || _POSIX_TIMERS > 0\r
1021         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);\r
1022 #endif\r
1023 #endif\r
1024         if (0 != clock_res)\r
1025         {\r
1026             OIC_LOG(ERROR, TAG, "clock error");\r
1027             ret = OC_STACK_ERROR;\r
1028             break;\r
1029         }\r
1030 #if defined(_MSC_VER)\r
1031         long elapsed = currTime - startTime;\r
1032 #else\r
1033         long elapsed = (currTime.tv_sec - startTime.tv_sec);\r
1034 #endif\r
1035         if (elapsed > waittime)\r
1036         {\r
1037             break;\r
1038         }\r
1039         else\r
1040         {\r
1041             struct timespec timeout = {.tv_sec=0, .tv_nsec=100000000L};\r
1042             OCProcess();\r
1043             nanosleep(&timeout, NULL);\r
1044         }\r
1045     }\r
1046 \r
1047     // Waiting for each response.\r
1048     ret = OCCancel(handle, OC_LOW_QOS, NULL, 0);\r
1049     if (OC_STACK_OK != ret)\r
1050     {\r
1051         OIC_LOG(ERROR, TAG, "Failed to remove registered callback");\r
1052     }\r
1053     OIC_LOG(DEBUG, TAG, "OUT DPDeviceDiscovery");\r
1054     return ret;\r
1055 }\r
1056 #endif\r