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