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