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