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