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