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