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