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