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