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