IOT-1583: Removing /W3 warning from resource/csdk/security.
[iotivity.git] / resource / csdk / security / src / secureresourcemanager.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 "ocstack.h"
23 #include "logger.h"
24 #include "cainterface.h"
25 #include "resourcemanager.h"
26 #include "credresource.h"
27 #include "policyengine.h"
28 #include "srmutility.h"
29 #include "amsmgr.h"
30 #include "oic_string.h"
31 #include "oic_malloc.h"
32 #include "securevirtualresourcetypes.h"
33 #include "secureresourcemanager.h"
34 #include "srmresourcestrings.h"
35 #include "ocresourcehandler.h"
36
37 #if defined( __WITH_TLS__) || defined(__WITH_DTLS__)
38 #include "pkix_interface.h"
39 #endif //__WITH_TLS__ or __WITH_DTLS__
40 #define TAG  "OIC_SRM"
41
42 //Request Callback handler
43 static CARequestCallback gRequestHandler = NULL;
44 //Response Callback handler
45 static CAResponseCallback gResponseHandler = NULL;
46 //Error Callback handler
47 static CAErrorCallback gErrorHandler = NULL;
48 //Provisioning response callback
49 static SPResponseCallback gSPResponseHandler = NULL;
50
51 /**
52  * A single global Policy Engine context will suffice as long
53  * as SRM is single-threaded.
54  */
55 PEContext_t g_policyEngineContext;
56
57
58 /**
59  * Function to retrieve the length of the resource URI address part.
60  *
61  * @param resourceUri   A null-terminated string representing the resource URI.
62  *
63  * @return  Length of the resource URI address or -1, if failed.
64  */
65 static int GetResourceUriAddressLength(CAURI_t resourceUri)
66 {
67     if (!resourceUri)
68     {
69         OIC_LOG(ERROR, TAG, "Missing resource URI");
70         return -1;
71     }
72
73     size_t resourceUriLength = strlen(resourceUri);
74     if (resourceUriLength > MAX_URI_LENGTH)
75     {
76         OIC_LOG(ERROR, TAG, "Invalid resource URI length");
77         return -1;
78     }
79
80     //Check the URI has the query and skip it before checking the permission
81     char *uri = strstr(resourceUri, "?");
82
83     return uri ? (int)(uri - resourceUri) : (int)resourceUriLength;
84 }
85
86 /**
87  * Function to register provisoning API's response callback.
88  * @param respHandler response handler callback.
89  */
90 void SRMRegisterProvisioningResponseHandler(SPResponseCallback respHandler)
91 {
92     gSPResponseHandler = respHandler;
93 }
94
95 void SetResourceRequestType(PEContext_t *context, const char *resourceUri)
96 {
97     context->resourceType = GetSvrTypeFromUri(resourceUri);
98 }
99
100 static void SRMSendUnAuthorizedAccessresponse(PEContext_t *context)
101 {
102     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
103
104     if (NULL == context ||
105        NULL == context->amsMgrContext->requestInfo)
106     {
107         OIC_LOG_V(ERROR, TAG, "%s : NULL Parameter(s)",__func__);
108         return;
109     }
110
111     memcpy(&responseInfo.info, &(context->amsMgrContext->requestInfo->info),
112             sizeof(responseInfo.info));
113     responseInfo.info.payload = NULL;
114     responseInfo.result = CA_UNAUTHORIZED_REQ;
115     responseInfo.info.dataType = CA_RESPONSE_DATA;
116
117     if (CA_STATUS_OK == CASendResponse(context->amsMgrContext->endpoint, &responseInfo))
118     {
119         OIC_LOG(DEBUG, TAG, "Succeed in sending response to a unauthorized request!");
120     }
121     else
122     {
123         OIC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
124     }
125 }
126
127 void SRMSendResponse(SRMAccessResponse_t responseVal)
128 {
129     OIC_LOG(DEBUG, TAG, "Sending response to remote device");
130
131     if (IsAccessGranted(responseVal) && gRequestHandler)
132     {
133         OIC_LOG_V(INFO, TAG, "%s : Access granted. Passing Request to RI layer", __func__);
134         if (!g_policyEngineContext.amsMgrContext->endpoint ||
135             !g_policyEngineContext.amsMgrContext->requestInfo)
136         {
137             OIC_LOG_V(ERROR, TAG, "%s : Invalid arguments", __func__);
138             SRMSendUnAuthorizedAccessresponse(&g_policyEngineContext);
139             goto exit;
140         }
141         gRequestHandler(g_policyEngineContext.amsMgrContext->endpoint,
142                 g_policyEngineContext.amsMgrContext->requestInfo);
143     }
144     else
145     {
146         OIC_LOG_V(INFO, TAG, "%s : ACCESS_DENIED.", __func__);
147         SRMSendUnAuthorizedAccessresponse(&g_policyEngineContext);
148     }
149
150 exit:
151     //Resetting PE state to AWAITING_REQUEST
152     SetPolicyEngineState(&g_policyEngineContext, AWAITING_REQUEST);
153 }
154
155 /**
156  * Handle the request from the SRM.
157  *
158  * @param endPoint object from which the response is received.
159  * @param requestInfo contains information for the request.
160  */
161 void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requestInfo)
162 {
163     OIC_LOG(DEBUG, TAG, "Received request from remote device");
164
165     bool isRequestOverSecureChannel = false;
166     if (!endPoint || !requestInfo)
167     {
168         OIC_LOG(ERROR, TAG, "Invalid arguments");
169         return;
170     }
171
172     // Copy the subjectID
173     OicUuid_t subjectId = {.id = {0}};
174     memcpy(subjectId.id, requestInfo->info.identity.id, sizeof(subjectId.id));
175     if (endPoint->flags & CA_SECURE)
176     {
177         OIC_LOG(INFO, TAG, "request over secure channel");
178         isRequestOverSecureChannel = true;
179     }
180
181     CAURI_t resourceUri = requestInfo->info.resourceUri;
182     int resourceUriAddressLength = GetResourceUriAddressLength(resourceUri);
183
184     if (resourceUriAddressLength < 0)
185     {
186         return;
187     }
188
189     SRMAccessResponse_t response = ACCESS_DENIED;
190     char newUri[MAX_URI_LENGTH + 1];
191     OICStrcpyPartial(newUri, MAX_URI_LENGTH + 1, resourceUri, resourceUriAddressLength);
192
193     SetResourceRequestType(&g_policyEngineContext, newUri);
194
195      // Form a 'Error', 'slow response' or 'access deny' response and send to peer
196     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
197     memcpy(&responseInfo.info, &(requestInfo->info), sizeof(responseInfo.info));
198     responseInfo.info.payload = NULL;
199     responseInfo.info.dataType = CA_RESPONSE_DATA;
200
201     OCResource *resPtr = FindResourceByUri(newUri);
202     if (NULL != resPtr)
203     {
204         // All vertical secure resources and SVR resources other than DOXM & PSTAT should reject request
205         // over coap.
206         if ((((resPtr->resourceProperties) & OC_SECURE)
207                             && (g_policyEngineContext.resourceType == NOT_A_SVR_RESOURCE))
208                             || ((g_policyEngineContext.resourceType < OIC_SEC_SVR_TYPE_COUNT)
209                             &&  (g_policyEngineContext.resourceType != OIC_R_DOXM_TYPE)
210                             &&  (g_policyEngineContext.resourceType != OIC_R_PSTAT_TYPE)))
211         {
212            // if resource is secure and request is over insecure channel
213             if (!isRequestOverSecureChannel)
214             {
215                 // Reject all the requests over coap for secure resource.
216                 responseInfo.result = CA_FORBIDDEN_REQ;
217                 if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo))
218                 {
219                     OIC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
220                 }
221                 return;
222             }
223         }
224     }
225 #ifdef MULTIPLE_OWNER
226     /*
227      * In case of ACL and CRED, The payload required to verify the payload.
228      * Payload information will be used for subowner's permission verification.
229      */
230     g_policyEngineContext.payload = (uint8_t*)requestInfo->info.payload;
231     g_policyEngineContext.payloadSize = requestInfo->info.payloadSize;
232 #endif //MULTIPLE_OWNER
233
234     //New request are only processed if the policy engine state is AWAITING_REQUEST.
235     if (AWAITING_REQUEST == g_policyEngineContext.state)
236     {
237         OIC_LOG_V(DEBUG, TAG, "Processing request with uri, %s for method, %d",
238                 resourceUri, requestInfo->method);
239         response = CheckPermission(&g_policyEngineContext, &subjectId, newUri,
240                 GetPermissionFromCAMethod_t(requestInfo->method));
241     }
242     else
243     {
244         OIC_LOG_V(INFO, TAG, "PE state %d. Ignoring request with uri, %s for method, %d",
245                 g_policyEngineContext.state, resourceUri, requestInfo->method);
246     }
247
248     if (IsAccessGranted(response) && gRequestHandler)
249     {
250         gRequestHandler(endPoint, requestInfo);
251         return;
252     }
253
254     VERIFY_NOT_NULL(TAG, gRequestHandler, ERROR);
255
256     if (ACCESS_WAITING_FOR_AMS == response)
257     {
258         OIC_LOG(INFO, TAG, "Sending slow response");
259
260         UpdateAmsMgrContext(&g_policyEngineContext, endPoint, requestInfo);
261         responseInfo.result = CA_EMPTY;
262         responseInfo.info.type = CA_MSG_ACKNOWLEDGE;
263     }
264     else
265     {
266         /*
267          * TODO Enhance this logic more to decide between
268          * CA_UNAUTHORIZED_REQ or CA_FORBIDDEN_REQ depending
269          * upon SRMAccessResponseReasonCode_t
270          */
271         OIC_LOG(INFO, TAG, "Sending for regular response");
272         responseInfo.result = CA_UNAUTHORIZED_REQ;
273     }
274
275     if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo))
276     {
277         OIC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
278     }
279     return;
280 exit:
281     responseInfo.result = CA_INTERNAL_SERVER_ERROR;
282     if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo))
283     {
284         OIC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
285     }
286 }
287
288 /**
289  * Handle the response from the SRM.
290  *
291  * @param endPoint points to the remote endpoint.
292  * @param responseInfo contains response information from the endpoint.
293  */
294 void SRMResponseHandler(const CAEndpoint_t *endPoint, const CAResponseInfo_t *responseInfo)
295 {
296     OIC_LOG(DEBUG, TAG, "Received response from remote device");
297
298     // isProvResponse flag is to check whether response is catered by provisioning APIs or not.
299     // When token sent by CA response matches with token generated by provisioning request,
300     // gSPResponseHandler returns true and response is not sent to RI layer. In case
301     // gSPResponseHandler is null and isProvResponse is false response then the response is for
302     // RI layer.
303     bool isProvResponse = false;
304
305     if (gSPResponseHandler)
306     {
307         isProvResponse = gSPResponseHandler(endPoint, responseInfo);
308     }
309     if (!isProvResponse && gResponseHandler)
310     {
311         gResponseHandler(endPoint, responseInfo);
312     }
313 }
314
315 /**
316  * Handle the error from the SRM.
317  *
318  * @param endPoint is the remote endpoint.
319  * @param errorInfo contains error information from the endpoint.
320  */
321 void SRMErrorHandler(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo)
322 {
323     OIC_LOG_V(INFO, TAG, "Received error from remote device with result, %d for request uri, %s",
324             errorInfo->result, errorInfo->info.resourceUri);
325     if (gErrorHandler)
326     {
327         gErrorHandler(endPoint, errorInfo);
328     }
329 }
330
331 OCStackResult SRMRegisterHandler(CARequestCallback reqHandler,
332                                  CAResponseCallback respHandler,
333                                  CAErrorCallback errHandler)
334 {
335     OIC_LOG(DEBUG, TAG, "SRMRegisterHandler !!");
336     if( !reqHandler || !respHandler || !errHandler)
337     {
338         OIC_LOG(ERROR, TAG, "Callback handlers are invalid");
339         return OC_STACK_INVALID_PARAM;
340     }
341     gRequestHandler = reqHandler;
342     gResponseHandler = respHandler;
343     gErrorHandler = errHandler;
344
345
346 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
347     CARegisterHandler(SRMRequestHandler, SRMResponseHandler, SRMErrorHandler);
348 #else
349     CARegisterHandler(reqHandler, respHandler, errHandler);
350 #endif /* __WITH_DTLS__ */
351     return OC_STACK_OK;
352 }
353
354 OCStackResult SRMRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler)
355 {
356     OIC_LOG(DEBUG, TAG, "SRMRegisterPersistentStorageHandler !!");
357     return OCRegisterPersistentStorageHandler(persistentStorageHandler);
358 }
359
360 OCPersistentStorage* SRMGetPersistentStorageHandler()
361 {
362     return OCGetPersistentStorageHandler();
363 }
364
365 OCStackResult SRMInitSecureResources()
366 {
367     // TODO: temporarily returning OC_STACK_OK every time until default
368     // behavior (for when SVR DB is missing) is settled.
369     InitSecureResources();
370     OCStackResult ret = OC_STACK_OK;
371 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
372     if (CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
373     {
374         OIC_LOG(ERROR, TAG, "Failed to revert TLS credential handler.");
375         ret = OC_STACK_ERROR;
376     }
377     CAregisterPkixInfoHandler(GetPkixInfo);
378     CAregisterGetCredentialTypesHandler(InitCipherSuiteList);
379 #endif // __WITH_DTLS__ or __WITH_TLS__
380     return ret;
381 }
382
383 void SRMDeInitSecureResources()
384 {
385     DestroySecureResources();
386 }
387
388 OCStackResult SRMInitPolicyEngine()
389 {
390     return InitPolicyEngine(&g_policyEngineContext);
391 }
392
393 void SRMDeInitPolicyEngine()
394 {
395     DeInitPolicyEngine(&g_policyEngineContext);
396 }
397
398 bool SRMIsSecurityResourceURI(const char* uri)
399 {
400     if (!uri)
401     {
402         return false;
403     }
404
405     const char *rsrcs[] = {
406         OIC_RSRC_SVC_URI,
407         OIC_RSRC_AMACL_URI,
408         OIC_RSRC_CRL_URI,
409         OIC_RSRC_CRED_URI,
410         OIC_RSRC_ACL_URI,
411         OIC_RSRC_DOXM_URI,
412         OIC_RSRC_PSTAT_URI,
413         OIC_RSRC_PCONF_URI,
414         OIC_RSRC_DPAIRING_URI,
415         OIC_RSRC_VER_URI,
416         OC_RSRVD_PROV_CRL_URL
417     };
418
419     // Remove query from Uri for resource string comparison
420     size_t uriLen = strlen(uri);
421     char *query = strchr (uri, '?');
422     if (query)
423     {
424         uriLen = query - uri;
425     }
426
427     for (size_t i = 0; i < sizeof(rsrcs)/sizeof(rsrcs[0]); i++)
428     {
429         size_t svrLen = strlen(rsrcs[i]);
430
431         if ((uriLen == svrLen) &&
432             (strncmp(uri, rsrcs[i], svrLen) == 0))
433         {
434             return true;
435         }
436     }
437
438     return false;
439 }
440
441 /**
442  * Get the Secure Virtual Resource (SVR) type from the URI.
443  * @param   uri [IN] Pointer to URI in question.
444  * @return  The OicSecSvrType_t of the URI passed (note: if not a Secure Virtual
445             Resource, e.g. /a/light, will return "NOT_A_SVR_TYPE" enum value)
446  */
447 static const char URI_QUERY_CHAR = '?';
448 OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
449 {
450     if (!uri)
451     {
452         return NOT_A_SVR_RESOURCE;
453     }
454
455     // Remove query from Uri for resource string comparison
456     size_t uriLen = strlen(uri);
457     char *query = strchr (uri, URI_QUERY_CHAR);
458     if (query)
459     {
460         uriLen = query - uri;
461     }
462
463     size_t svrLen = 0;
464
465     svrLen = strlen(OIC_RSRC_ACL_URI);
466     if(uriLen == svrLen)
467     {
468         if(0 == strncmp(uri, OIC_RSRC_ACL_URI, svrLen))
469         {
470             return OIC_R_ACL_TYPE;
471         }
472     }
473
474     svrLen = strlen(OIC_RSRC_AMACL_URI);
475     if(uriLen == svrLen)
476     {
477         if(0 == strncmp(uri, OIC_RSRC_AMACL_URI, svrLen))
478         {
479             return OIC_R_AMACL_TYPE;
480         }
481     }
482
483     svrLen = strlen(OIC_RSRC_CRED_URI);
484     if(uriLen == svrLen)
485     {
486         if(0 == strncmp(uri, OIC_RSRC_CRED_URI, svrLen))
487         {
488             return OIC_R_CRED_TYPE;
489         }
490     }
491
492     svrLen = strlen(OIC_RSRC_CRL_URI);
493     if(uriLen == svrLen)
494     {
495         if(0 == strncmp(uri, OIC_RSRC_CRL_URI, svrLen))
496         {
497             return OIC_R_CRL_TYPE;
498         }
499     }
500
501     svrLen = strlen(OIC_RSRC_DOXM_URI);
502     if(uriLen == svrLen)
503     {
504         if(0 == strncmp(uri, OIC_RSRC_DOXM_URI, svrLen))
505         {
506             return OIC_R_DOXM_TYPE;
507         }
508     }
509
510     svrLen = strlen(OIC_RSRC_DPAIRING_URI);
511     if(uriLen == svrLen)
512     {
513         if(0 == strncmp(uri, OIC_RSRC_DPAIRING_URI, svrLen))
514         {
515             return OIC_R_DPAIRING_TYPE;
516         }
517     }
518
519     svrLen = strlen(OIC_RSRC_PCONF_URI);
520     if(uriLen == svrLen)
521     {
522         if(0 == strncmp(uri, OIC_RSRC_PCONF_URI, svrLen))
523         {
524             return OIC_R_PCONF_TYPE;
525         }
526     }
527
528     svrLen = strlen(OIC_RSRC_PSTAT_URI);
529     if(uriLen == svrLen)
530     {
531         if(0 == strncmp(uri, OIC_RSRC_PSTAT_URI, svrLen))
532         {
533             return OIC_R_PSTAT_TYPE;
534         }
535     }
536
537     svrLen = strlen(OIC_RSRC_SVC_URI);
538     if(uriLen == svrLen)
539     {
540         if(0 == strncmp(uri, OIC_RSRC_SVC_URI, svrLen))
541         {
542             return OIC_R_SVC_TYPE;
543         }
544     }
545
546     svrLen = strlen(OIC_RSRC_SACL_URI);
547     if(uriLen == svrLen)
548     {
549         if(0 == strncmp(uri, OIC_RSRC_SACL_URI, svrLen))
550         {
551             return OIC_R_SACL_TYPE;
552         }
553     }
554
555     return NOT_A_SVR_RESOURCE;
556 }