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