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