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