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