Fix Werror=implicit-function-declaration
[platform/upstream/iotivity.git] / resource / csdk / security / src / srmutility.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH 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 #define _POSIX_C_SOURCE 200112L
21 #include <string.h>
22
23 #include "srmutility.h"
24 #include "srmresourcestrings.h"
25 #include "logger.h"
26 #include "oic_malloc.h"
27 #include "oic_string.h"
28 #include "base64.h"
29 #include "psinterface.h"
30 #include "doxmresource.h"
31 #include "credresource.h"
32 #include "pstatresource.h"
33 #include "cacommon.h"
34 #include "casecurityinterface.h"
35 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
36 #include "pkix_interface.h"
37 #endif
38
39 #define TAG  "OIC_SRM_UTILITY"
40
41 void ParseQueryIterInit(const unsigned char * query, OicParseQueryIter_t * parseIter)
42 {
43     OIC_LOG(INFO, TAG, "Initializing coap iterator");
44     if ((NULL == query) || (NULL == parseIter))
45     {
46         return;
47     }
48
49     parseIter->attrPos = NULL;
50     parseIter->attrLen = 0;
51     parseIter->valPos = NULL;
52     parseIter->valLen = 0;
53     coap_parse_iterator_init((unsigned char *)query, strlen((char *)query),
54                              (unsigned char *)OIC_SEC_REST_QUERY_SEPARATOR,
55                              (unsigned char *) "", 0, &parseIter->pi);
56 }
57
58 OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter)
59 {
60     OIC_LOG(INFO, TAG, "Getting Next Query");
61     if (NULL == parseIter)
62     {
63         return NULL;
64     }
65
66     unsigned char * qrySeg = NULL;
67     char * delimPos;
68
69     // Get the next query. Querys are separated by OIC_SEC_REST_QUERY_SEPARATOR.
70     qrySeg = coap_parse_next(&parseIter->pi);
71
72     if (qrySeg)
73     {
74         delimPos = strchr((char *)qrySeg, OIC_SEC_REST_QUERY_DELIMETER);
75         if (delimPos)
76         {
77             parseIter->attrPos = parseIter->pi.pos;
78             parseIter->attrLen = (unsigned char *)delimPos - parseIter->pi.pos;
79             parseIter->valPos  = (unsigned char *)delimPos + 1;
80             parseIter->valLen  = &qrySeg[parseIter->pi.segment_length] - parseIter->valPos;
81             return parseIter;
82         }
83     }
84     return NULL;
85 }
86
87 // TODO This functionality is replicated in all SVR's and therefore we need
88 // to encapsulate it in a common method. However, this may not be the right
89 // file for this method.
90 OCStackResult AddUuidArray(const cJSON* jsonRoot, const char* arrayItem,
91                            size_t *numUuids, OicUuid_t** uuids)
92 {
93     size_t idxx = 0;
94     cJSON* jsonObj = cJSON_GetObjectItem((cJSON *)jsonRoot, arrayItem);
95     VERIFY_NON_NULL(TAG, jsonObj, ERROR);
96     VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR);
97
98     *numUuids = (size_t)cJSON_GetArraySize(jsonObj);
99     VERIFY_SUCCESS(TAG, *numUuids > 0, ERROR);
100     *uuids = (OicUuid_t*)OICCalloc(*numUuids, sizeof(OicUuid_t));
101     VERIFY_NON_NULL(TAG, *uuids, ERROR);
102
103     do
104     {
105         unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {0};
106         uint32_t outLen = 0;
107         B64Result b64Ret = B64_OK;
108
109         cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx);
110         VERIFY_NON_NULL(TAG, jsonOwnr, ERROR);
111         VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR);
112
113         outLen = 0;
114         b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff,
115                sizeof(base64Buff), &outLen);
116
117         VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof((*uuids)[idxx].id)),
118                ERROR);
119         memcpy((*uuids)[idxx].id, base64Buff, outLen);
120     } while ( ++idxx < *numUuids);
121
122     return OC_STACK_OK;
123
124 exit:
125     return OC_STACK_ERROR;
126
127 }
128
129 /**
130  * Function to getting string of ownership transfer method
131  *
132  * @prarm oxmType ownership transfer method
133  *
134  * @return string value of ownership transfer method
135  */
136 const char* GetOxmString(OicSecOxm_t oxmType)
137 {
138     switch(oxmType)
139     {
140         case OIC_JUST_WORKS:
141             return OXM_JUST_WORKS;
142         case OIC_RANDOM_DEVICE_PIN:
143             return OXM_RANDOM_DEVICE_PIN;
144         case OIC_MANUFACTURER_CERTIFICATE:
145             return OXM_MANUFACTURER_CERTIFICATE;
146         case OIC_RAW_PUB_KEY:
147             return OXM_RAW_PUBLIC_KEY;
148 #ifdef MULTIPLE_OWNER
149         case OIC_PRECONFIG_PIN:
150             return OXM_PRECONF_PIN;
151 #endif //MULTIPLE_OWNER
152         case OIC_MV_JUST_WORKS:
153             return OXM_MV_JUST_WORKS;
154         case OIC_CON_MFG_CERT:
155             return OXM_CON_MFG_CERT;
156         default:
157             return NULL;
158     }
159 }
160
161 OCStackResult ConvertUuidToStr(const OicUuid_t* uuid, char** strUuid)
162 {
163     if(NULL == uuid || NULL == strUuid || NULL != *strUuid)
164     {
165         OIC_LOG(ERROR, TAG, "ConvertUuidToStr : Invalid param");
166         return OC_STACK_INVALID_PARAM;
167     }
168
169     size_t uuidIdx = 0;
170     size_t urnIdx = 0;
171     const size_t urnBufSize = (UUID_LENGTH * 2) + 4 + 1;
172     char* convertedUrn = (char*)OICCalloc(urnBufSize, sizeof(char));
173     VERIFY_NON_NULL(TAG, convertedUrn, ERROR);
174
175     for(uuidIdx=0, urnIdx=0;  uuidIdx < UUID_LENGTH && urnIdx < urnBufSize; uuidIdx++, urnIdx+=2)
176     {
177         // canonical format for UUID has '8-4-4-4-12'
178         if(uuidIdx==4 || uuidIdx==6 || uuidIdx==8 || uuidIdx==10)
179         {
180             snprintf(convertedUrn + urnIdx, 2, "%c", '-');
181             urnIdx++;
182         }
183         snprintf(convertedUrn + urnIdx, 3, "%02x", (uint8_t)(uuid->id[uuidIdx]));
184     }
185     convertedUrn[urnBufSize - 1] = '\0';
186
187     *strUuid = convertedUrn;
188     return OC_STACK_OK;
189
190 exit:
191     return OC_STACK_NO_MEMORY;
192 }
193
194 OCStackResult ConvertStrToUuid(const char* strUuid, OicUuid_t* uuid)
195 {
196     if(NULL == strUuid || NULL == uuid)
197     {
198         OIC_LOG(ERROR, TAG, "ConvertStrToUuid : Invalid param");
199         return OC_STACK_INVALID_PARAM;
200     }
201
202     size_t urnIdx = 0;
203     size_t uuidIdx = 0;
204     size_t strUuidLen = 0;
205     char convertedUuid[UUID_LENGTH * 2] = {0};
206
207     strUuidLen = strlen(strUuid);
208     if(0 == strUuidLen)
209     {
210         OIC_LOG(INFO, TAG, "The empty string detected, The UUID will be converted to "\
211                            "\"00000000-0000-0000-0000-000000000000\"");
212     }
213     else if(UUID_LENGTH * 2 + 4 == strUuidLen)
214     {
215         for(uuidIdx=0, urnIdx=0; uuidIdx < UUID_LENGTH ; uuidIdx++, urnIdx+=2)
216         {
217             if(*(strUuid + urnIdx) == '-')
218             {
219                 urnIdx++;
220             }
221             sscanf(strUuid + urnIdx, "%2hhx", &convertedUuid[uuidIdx]);
222         }
223     }
224     else
225     {
226         OIC_LOG(ERROR, TAG, "Invalid string uuid format, Please set the uuid as correct format");
227         OIC_LOG(ERROR, TAG, "e.g) \"72616E64-5069-6E44-6576-557569643030\" (4-2-2-2-6)");
228         OIC_LOG(ERROR, TAG, "e.g) \"\"");
229
230         return OC_STACK_INVALID_PARAM;
231     }
232
233     memcpy(uuid->id, convertedUuid, UUID_LENGTH);
234
235     return OC_STACK_OK;
236 }
237
238 const OicUuid_t THE_NIL_UUID = {.id={0000000000000000}};
239
240 /**
241  * Compares two OicUuid_t structs.
242  *
243  * @return true if the two OicUuid_t structs are equal, else false.
244  */
245 bool UuidCmp(const OicUuid_t *firstId, const OicUuid_t *secondId)
246 {
247     bool ret = false;
248     VERIFY_NON_NULL(TAG, firstId, ERROR);
249     VERIFY_NON_NULL(TAG, secondId, ERROR);
250
251     if (0 == memcmp(firstId, secondId, sizeof(OicUuid_t)))
252     {
253         ret = true;
254     }
255
256 exit:
257     OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
258     return ret;
259 }
260
261 /**
262  * Compares OicUuid_t to Nil UUID {.id={0000000000000000}}
263  *
264  * @return true if the OicUuid_t is the Nil UUID.
265  */
266 bool IsNilUuid(const OicUuid_t *uuid)
267 {
268 #if !defined(NDEBUG)
269     char *strUuid = NULL;
270     ConvertUuidToStr(uuid, &strUuid);
271     if (strUuid)
272     {
273         OIC_LOG_V(DEBUG, TAG, "%s: uuid: %s.", __func__, strUuid);
274         OICFree(strUuid);
275     }
276 #endif
277     return UuidCmp(uuid, &THE_NIL_UUID);
278 }
279
280 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
281 OCStackResult SetDeviceIdSeed(const uint8_t* seed, size_t seedSize)
282 {
283     return SetDoxmDeviceIDSeed(seed, seedSize);
284 }
285
286 static OicSecOtmEventHandler_t gOtmEventHandler = NULL;
287 static char ptAddr[256] = {0};
288 static uint16_t ptPort = 0;
289
290 void SetOtmEventHandler(OicSecOtmEventHandler_t otmEventHandler)
291 {
292     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
293
294     memset(ptAddr, 0x00, sizeof(ptAddr));
295     ptPort = 0;
296     gOtmEventHandler = otmEventHandler;
297     OIC_LOG_V(DEBUG, TAG, "Out%s", __func__);
298 }
299
300 /**
301  * Function to handle the handshake result in OTM.
302  * This function will be invoked after DTLS handshake
303  * @param   endPoint  [IN] The remote endpoint.
304  * @param   errorInfo [IN] Error information from the endpoint.
305  * @return  NONE
306  */
307 static void DTLSHandshakeServerCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
308 {
309     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
310     if(NULL != endpoint && NULL != info)
311     {
312         OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
313                  endpoint->addr, endpoint->port, info->result);
314
315         //We can't know about PT's secure port, so compare only adress to identify the PT.
316         if (strncmp(endpoint->addr, ptAddr, strlen(ptAddr)) == 0)
317         {
318             OIC_LOG_V(INFO, TAG, "Normal port is [%s:%d]", ptAddr, ptPort);
319
320             //If DTLS handshake error occurred, revert secure resource and notify error event to application.
321             if (CA_STATUS_OK != info->result)
322             {
323                 OIC_LOG(ERROR, TAG, "Failed to establish a secure session with owner device.");
324                 ResetSecureResourceInPS();
325                 OIC_LOG(INFO, TAG, "Secure Resources reverted.");
326                 InvokeOtmEventHandler(endpoint->addr, endpoint->port, NULL, OIC_OTM_ERROR);
327             }
328         }
329         else
330         {
331             OIC_LOG_V(WARNING, TAG, "[%s:%d] is not a owner device", endpoint->addr, endpoint->port);
332         }
333     }
334     else
335     {
336         OIC_LOG(WARNING, TAG, "Invalid param.");
337     }
338     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
339 }
340
341
342 void InvokeOtmEventHandler(const char* addr, uint16_t port,
343                            const OicUuid_t* uuid, OicSecOtmEvent_t event)
344 {
345     char* strUuid = NULL;
346     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
347
348     //addr can be NULL for init state
349     //port can be '0' for BLE and init state
350     //uuid can be NULL for init state & coap
351
352     switch(event)
353     {
354         case OIC_OTM_READY:
355         case OIC_OTM_STARTED:
356             if (addr)
357             {
358                 OICStrcpy(ptAddr, sizeof(ptAddr), addr);
359                 ptPort = port;
360             }
361             else
362             {
363                 memset(ptAddr, 0x00, sizeof(ptAddr));
364                 ptPort = 0;
365             }
366             //Register TLS event handler to catch the tls event while handshake
367             if(CA_STATUS_OK != CAregisterSslHandshakeCallback(DTLSHandshakeServerCB))
368             {
369                 OIC_LOG(WARNING, TAG, "Failed to register (D)TLS handshake callback.");
370             }
371             break;
372         case OIC_OTM_DONE:
373         case OIC_OTM_ERROR:
374             memset(ptAddr, 0x00, sizeof(ptAddr));
375             ptPort = 0;
376             //Register TLS event handler to catch the tls event while handshake
377             if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL))
378             {
379                 OIC_LOG(WARNING, TAG, "Failed to register (D)TLS handshake callback.");
380             }
381             //Restore Pkix handler to initial state
382             CAregisterPkixInfoHandler(GetPkixInfo);
383             CAregisterGetCredentialTypesHandler(InitCipherSuiteList);
384             CAregisterPskCredentialsHandler(GetDtlsPskCredentials);
385             break;
386         default:
387             OIC_LOG_V(ERROR, TAG, "Unknow OTM event : %d", event);
388             goto exit;
389     }
390
391     if (uuid)
392     {
393         if(OC_STACK_OK != ConvertUuidToStr(uuid, &strUuid))
394         {
395             OIC_LOG(ERROR, TAG, "Failed to convert UUID to String.");
396             goto exit;
397         }
398     }
399
400     OIC_LOG(DEBUG, TAG, "=================================");
401     OIC_LOG(DEBUG, TAG, "[OTM Event]");
402     OIC_LOG_V(DEBUG, TAG, "PT UUID : %s", (strUuid ? strUuid : "NULL"));
403     OIC_LOG_V(DEBUG, TAG, "PT Addr=%s:%d", (addr ? addr : "NULL"), port);
404     OIC_LOG_V(DEBUG, TAG, "Event Code=%d", event);
405     OIC_LOG(DEBUG, TAG, "=================================");
406
407     if (NULL == gOtmEventHandler)
408     {
409         OIC_LOG(WARNING, TAG, "OTM event handler is not registered.");
410         goto exit;
411     }
412
413     OIC_LOG(DEBUG, TAG, "Invoking callback to notify OTM state..");
414     gOtmEventHandler(addr, port, strUuid, (int)event);
415
416 exit:
417     if (strUuid)
418     {
419         OICFree(strUuid);
420     }
421     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
422 }
423
424 #endif