Merge branch 'master' into resource-container
[platform/upstream/iotivity.git] / resource / csdk / security / src / amsmgr.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
21 #include "oic_malloc.h"
22 #include "amsmgr.h"
23 #include "resourcemanager.h"
24 #include "securevirtualresourcetypes.h"
25 #include "srmresourcestrings.h"
26 #include "logger.h"
27 #include "ocrandom.h"
28 #include "aclresource.h"
29 #include "amaclresource.h"
30 #include "srmutility.h"
31 #include "base64.h"
32 #include "secureresourcemanager.h"
33 #include "doxmresource.h"
34 #include "policyengine.h"
35 #include "oic_string.h"
36 #include "caremotehandler.h"
37 #include <string.h>
38
39 #define TAG "SRM-AMSMGR"
40
41
42  //Callback for AMS service multicast discovery request.
43 static OCStackApplicationResult AmsMgrDiscoveryCallback(void *ctx, OCDoHandle handle,
44                          OCClientResponse * clientResponse);
45
46 //Callback for unicast secured port discovery request.
47 static OCStackApplicationResult SecurePortDiscoveryCallback(void *ctx, OCDoHandle handle,
48                          OCClientResponse * clientResponse);
49
50 //Callback for unicast ACL request
51 static OCStackApplicationResult AmsMgrAclReqCallback(void *ctx, OCDoHandle handle,
52     OCClientResponse * clientResponse);
53
54
55 OCStackResult DiscoverAmsService(PEContext_t *context)
56 {
57     OC_LOG(INFO, TAG, "IN DiscoverAmsService");
58
59     OCStackResult ret = OC_STACK_ERROR;
60     const char DOXM_DEVICEID_QUERY_FMT[] = "%s?%s=%s";
61     char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {};
62     OCCallbackData cbData = {.context=NULL};
63     char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
64     uint32_t outLen = 0;
65     B64Result b64Ret;
66
67     VERIFY_NON_NULL(TAG, context, ERROR);
68     b64Ret = b64Encode(context->amsMgrContext->amsDeviceId.id,
69           sizeof(context->amsMgrContext->amsDeviceId.id), base64Buff, sizeof(base64Buff), &outLen);
70     VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR);
71     snprintf(uri, sizeof(uri), DOXM_DEVICEID_QUERY_FMT, OIC_RSRC_DOXM_URI,
72                                        OIC_JSON_DEVICE_ID_NAME, base64Buff);
73
74     cbData.cb = &AmsMgrDiscoveryCallback;
75     cbData.context = (void*)context;
76
77     /* TODO
78      * If no good response was received for this discovery request,
79      * PE would be blocked forever waiting for AMS service to respond with the ACE.
80      * Need logic to reset the PE state and send ACCESS_DENIED response,
81      * when discovery response from AMS service is not received within certain time.
82      */
83     OC_LOG_V(INFO, TAG,"AMS Manager Sending Multicast Discovery with URI = %s", uri);
84     ret = OCDoResource(NULL, OC_REST_DISCOVER, uri, NULL, NULL,
85                        CT_DEFAULT, OC_LOW_QOS, &cbData, NULL, 0);
86
87 exit:
88     OC_LOG(INFO, TAG, "Leaving DiscoverAmsService");
89     return ret;
90 }
91
92
93 static OCStackApplicationResult AmsMgrDiscoveryCallback(void *ctx, OCDoHandle handle,
94                          OCClientResponse * clientResponse)
95 {
96     OC_LOG_V(INFO, TAG, "%s Begin", __func__ );
97
98     if (!ctx ||
99         !clientResponse ||
100         !clientResponse->payload||
101         (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type)||
102         (OC_STACK_OK != clientResponse->result))
103     {
104         OC_LOG_V(ERROR, TAG, "%s Invalid Response ", __func__);
105         return OC_STACK_KEEP_TRANSACTION;
106     }
107
108     (void)handle;
109     PEContext_t *context = (PEContext_t *) ctx;
110     if (context->state != AWAITING_AMS_RESPONSE)
111     {
112         OC_LOG_V(ERROR, TAG, "%s Invalid PE State ", __func__);
113         return OC_STACK_DELETE_TRANSACTION;
114     }
115
116     OicSecDoxm_t *doxm = NULL;
117     OC_LOG_V(INFO, TAG, "Doxm DeviceId Discovery response = %s\n",
118           ((OCSecurityPayload*)clientResponse->payload)->securityData);
119     doxm = JSONToDoxmBin(((OCSecurityPayload*)clientResponse->payload)->securityData);
120
121     //As doxm is NULL amsmgr can't test if response from trusted AMS service
122     //so keep the transaction.
123     if(NULL == doxm)
124     {
125         OC_LOG_V(ERROR, TAG, "%s : Unable to convert JSON to Binary",__func__);
126         return OC_STACK_KEEP_TRANSACTION;
127     }
128
129     OicUuid_t deviceId = {.id={}};
130     memcpy(&deviceId, &doxm->deviceID, sizeof(deviceId));
131     OICFree(doxm);
132
133     /* TODO : By assuming that the first response received is the actual
134      * AMS service, a 'bad device' can cause DoS attack.
135      */
136     if (memcmp(&context->amsMgrContext->amsDeviceId, &deviceId,
137             sizeof(context->amsMgrContext->amsDeviceId)) == 0)
138     {
139         OC_LOG(INFO, TAG, "AMS Manager Sending unicast discovery to get secured port info");
140         //Sending Unicast discovery to get secure port information
141         if(OC_STACK_OK == SendUnicastSecurePortDiscovery(context, &clientResponse->devAddr,
142                 clientResponse->connType))
143         {
144             context->retVal = ACCESS_WAITING_FOR_AMS;
145             return OC_STACK_DELETE_TRANSACTION;
146         }
147     }
148     context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
149     SRMSendResponse(context->retVal);
150     return OC_STACK_DELETE_TRANSACTION;
151 }
152
153
154 OCStackResult SendUnicastSecurePortDiscovery(PEContext_t *context,OCDevAddr *devAddr,
155                                       OCConnectivityType connType)
156 {
157     OC_LOG(INFO, TAG, "IN SendUnicastSecurePortDiscovery");
158
159     const char RES_DOXM_QUERY_FMT[] = "%s?%s=%s";
160     OCCallbackData cbData = {.context=NULL};
161     char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {};
162     snprintf(uri, sizeof(uri), RES_DOXM_QUERY_FMT, OC_RSRVD_WELL_KNOWN_URI,
163             OC_RSRVD_RESOURCE_TYPE, OIC_RSRC_TYPE_SEC_DOXM);
164
165     cbData.cb = &SecurePortDiscoveryCallback;
166     cbData.context = context;
167
168     OC_LOG_V(INFO, TAG, "AMS Manager Sending Unicast Discovery with URI = %s", uri);
169
170     return  OCDoResource(NULL, OC_REST_DISCOVER, uri, devAddr, NULL,
171                          connType, OC_LOW_QOS, &cbData, NULL, 0);
172 }
173
174 static OCStackApplicationResult SecurePortDiscoveryCallback(void *ctx, OCDoHandle handle,
175                          OCClientResponse * clientResponse)
176 {
177     OC_LOG(INFO, TAG, "In SecurePortDiscoveryCallback");
178
179     if (!ctx ||
180         !clientResponse ||
181         !clientResponse->payload||
182         (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type)||
183         (OC_STACK_OK != clientResponse->result))
184     {
185         OC_LOG_V(ERROR, TAG, "%s Invalid Response ", __func__);
186         SRMSendResponse(ACCESS_DENIED_AMS_SERVICE_ERROR);
187         return OC_STACK_DELETE_TRANSACTION;
188     }
189
190     PEContext_t *context = (PEContext_t *) ctx;
191
192     (void)handle;
193     if (context->state != AWAITING_AMS_RESPONSE)
194     {
195         OC_LOG_V(ERROR, TAG, "%s Invalid PE State ", __func__);
196         context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
197         SRMSendResponse(context->retVal);
198         return OC_STACK_DELETE_TRANSACTION;
199     }
200
201     OCResourcePayload* resPayload = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
202
203     //Verifying if the ID of the sender is an AMS service that this device trusts.
204     if(resPayload &&
205        memcmp(context->amsMgrContext->amsDeviceId.id, resPayload->sid,
206                     sizeof(context->amsMgrContext->amsDeviceId.id)) != 0)
207     {
208         OC_LOG_V(ERROR, TAG, "%s Invalid AMS device", __func__);
209         context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
210         SRMSendResponse(context->retVal);
211         return OC_STACK_DELETE_TRANSACTION;
212     }
213
214     if (resPayload && resPayload->secure)
215     {
216         if(OC_STACK_OK == SendAclReq(context, &clientResponse->devAddr, clientResponse->connType,
217                 resPayload->port))
218         {
219             return OC_STACK_DELETE_TRANSACTION;
220         }
221     }
222     OC_LOG(INFO, TAG, "Can not find secure port information");
223
224     context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
225     SRMSendResponse(context->retVal);
226     return OC_STACK_DELETE_TRANSACTION;
227 }
228
229
230 OCStackResult SendAclReq(PEContext_t *context, OCDevAddr *devAddr, OCConnectivityType connType,
231         uint16_t securedPort)
232 {
233     OCStackResult ret = OC_STACK_ERROR;
234     const char GET_ACE_QUERY_FMT[] = "%s?%s=%s;%s=%s";
235     char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
236     uint32_t outLen = 0;
237     char uri[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {};
238     OCCallbackData cbData = {.context=NULL};
239     OCDevAddr destAddr = {.adapter = OC_ADAPTER_IP};
240     B64Result b64Ret;
241
242     VERIFY_NON_NULL(TAG, context, ERROR);
243     VERIFY_NON_NULL(TAG, devAddr, ERROR);
244
245     b64Ret = b64Encode(context->subject.id, sizeof(context->subject.id),
246                        base64Buff, sizeof(base64Buff), &outLen);
247     VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR);
248
249     snprintf(uri, sizeof(uri), GET_ACE_QUERY_FMT, OIC_RSRC_ACL_URI,
250                                     OIC_JSON_SUBJECT_NAME, base64Buff,
251                                     OIC_JSON_RESOURCES_NAME, context->resource);
252
253     cbData.cb = &AmsMgrAclReqCallback;
254     cbData.context = context;
255
256     destAddr = *devAddr;
257     //update port info
258     destAddr.flags = (OCTransportFlags)(destAddr.flags | OC_FLAG_SECURE);
259     destAddr.port = securedPort;
260
261     OC_LOG_V(INFO, TAG, "AMS Manager Sending Unicast ACL request with URI = %s", uri);
262     ret = OCDoResource(NULL, OC_REST_GET, uri, &destAddr, NULL,
263             connType, OC_LOW_QOS, &cbData, NULL, 0);
264
265 exit:
266     OC_LOG_V(INFO, TAG, "%s returns %d ", __func__, ret);
267     return ret;
268 }
269
270
271 static OCStackApplicationResult AmsMgrAclReqCallback(void *ctx, OCDoHandle handle,
272     OCClientResponse * clientResponse)
273 {
274     OC_LOG_V(INFO, TAG, "%s Begin", __func__ );
275
276     (void)handle;
277     PEContext_t *context = (PEContext_t *) ctx;
278     SRMAccessResponse_t rsps;
279
280     if (!ctx ||
281         !clientResponse ||
282         !clientResponse->payload||
283         (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type) ||
284         (clientResponse->result != OC_STACK_OK))
285     {
286         OC_LOG_V(ERROR, TAG, "%s Invalid Response ", __func__);
287         SRMSendResponse(ACCESS_DENIED_AMS_SERVICE_ERROR);
288         return OC_STACK_DELETE_TRANSACTION;
289     }
290
291     if (context->state != AWAITING_AMS_RESPONSE)
292     {
293         OC_LOG_V(ERROR, TAG, "%s Invalid State ", __func__);
294         context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
295         SRMSendResponse(context->retVal);
296         return OC_STACK_DELETE_TRANSACTION;
297     }
298
299     // Verify before installing ACL if the ID of the sender of this ACL is an AMS
300     //service that this device trusts.
301     rsps = ACCESS_DENIED;
302     if((UUID_LENGTH == clientResponse->identity.id_length) &&
303         memcmp(context->amsMgrContext->amsDeviceId.id, clientResponse->identity.id,
304                        sizeof(context->amsMgrContext->amsDeviceId.id)) == 0)
305     {
306         OCStackResult ret =
307                 InstallNewACL(((OCSecurityPayload*)clientResponse->payload)->securityData);
308         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
309
310         OC_LOG_V(INFO, TAG, "%s : Calling checkPermission", __func__);
311         rsps = CheckPermission(context, &context->subject, context->resource, context->permission);
312         VERIFY_SUCCESS(TAG, (true == IsAccessGranted(rsps)), ERROR);
313
314         OC_LOG_V(INFO, TAG, "%sAccess granted, Calling SRMCallCARequestHandler", __func__);
315         context->retVal = ACCESS_GRANTED;
316         SRMSendResponse(context->retVal);
317         return OC_STACK_DELETE_TRANSACTION;
318     }
319
320 exit:
321     context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
322     SRMSendResponse(context->retVal);
323     return OC_STACK_DELETE_TRANSACTION;
324 }
325
326
327 OCStackResult UpdateAmsMgrContext(PEContext_t *context, const CAEndpoint_t *endpoint,
328                         const CARequestInfo_t *requestInfo)
329 {
330     OCStackResult ret = OC_STACK_ERROR;
331
332     //The AmsMgr context endpoint and requestInfo will be free from ,
333     //AmsMgrAclReqCallback function
334     if(context->amsMgrContext->endpoint)
335     {
336         OICFree(context->amsMgrContext->endpoint);
337         context->amsMgrContext->endpoint = NULL;
338     }
339     context->amsMgrContext->endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof(CAEndpoint_t ));
340     VERIFY_NON_NULL(TAG, context->amsMgrContext->endpoint, ERROR);
341     *context->amsMgrContext->endpoint = *endpoint;
342
343     if(context->amsMgrContext->requestInfo)
344     {
345         FreeCARequestInfo(context->amsMgrContext->requestInfo);
346         context->amsMgrContext->requestInfo = NULL;
347     }
348     context->amsMgrContext->requestInfo = CACloneRequestInfo(requestInfo);
349     VERIFY_NON_NULL(TAG, context->amsMgrContext->requestInfo, ERROR);
350     ret = OC_STACK_OK;
351 exit:
352     return ret;
353 }
354
355 void FreeCARequestInfo(CARequestInfo_t *requestInfo)
356 {
357     if(NULL == requestInfo)
358     {
359         OC_LOG_V(ERROR, TAG, "%s: Can't free memory. Received NULL requestInfo", __func__);
360         return;
361     }
362     OICFree(requestInfo->info.token);
363     OICFree(requestInfo->info.options);
364     OICFree(requestInfo->info.payload);
365     OICFree(requestInfo->info.resourceUri);
366     OICFree(requestInfo);
367 }
368
369
370 //This method checks for Amacl resource. If Amacl is found then it fills up
371 //context->amsMgrContext->amsDeviceId with amsID of the Amacl else leaves it empty.
372 bool FoundAmaclForRequest(PEContext_t *context)
373 {
374     OC_LOG_V(INFO, TAG, "%s:no ACL found. Searching for AMACL",__func__);
375
376     bool ret = false;
377     VERIFY_NON_NULL(TAG, context, ERROR);
378     memset(&context->amsMgrContext->amsDeviceId, 0, sizeof(context->amsMgrContext->amsDeviceId));
379
380     //Call amacl resource function to get the AMS service deviceID for the resource
381     if(OC_STACK_OK == AmaclGetAmsDeviceId(context->resource, &context->amsMgrContext->amsDeviceId))
382     {
383         OC_LOG_V(INFO, TAG, "%s:AMACL found for the requested resource %s",
384                 __func__, context->resource);
385         ret = true;
386     }
387     else
388     {
389         OC_LOG_V(INFO, TAG, "%s:AMACL found for the requested resource %s",
390                 __func__, context->resource);
391         ret = false;
392     }
393
394  exit:
395      return ret;
396 }
397
398
399 void ProcessAMSRequest(PEContext_t *context)
400 {
401     OicUuid_t  emptyUuid = {.id={}};
402     OC_LOG_V(INFO, TAG, "Entering %s", __func__);
403     if(NULL != context)
404     {
405         if((false == context->matchingAclFound) && (false == context->amsProcessing))
406         {
407             context->amsProcessing = true;
408
409             //Checking if context AMS deviceId is empty
410             if(memcmp(&context->amsMgrContext->amsDeviceId, &emptyUuid, sizeof(OicUuid_t)) != 0 )
411             {
412                 if(OC_STACK_OK == DiscoverAmsService(context))
413                 {
414                     context->retVal = ACCESS_WAITING_FOR_AMS;
415                     context->state = AWAITING_AMS_RESPONSE;
416                 }
417                 else
418                 {
419                     context->retVal = ACCESS_DENIED_AMS_SERVICE_ERROR;
420                 }
421             }
422         }
423     }
424     else
425     {
426         OC_LOG_V(INFO, TAG, "Leaving %s(context is NULL)", __func__);
427     }
428
429     if(ACCESS_WAITING_FOR_AMS == context->retVal )
430     {
431         OC_LOG_V(INFO, TAG, "Leaving %s(WAITING_FOR_AMS)", __func__);
432     }
433 }