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