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