[IOT-1849] fixed null subject ID comparison logic
[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 "oic_string.h"
30 #include "oic_malloc.h"
31 #include "securevirtualresourcetypes.h"
32 #include "secureresourcemanager.h"
33 #include "srmresourcestrings.h"
34 #include "ocresourcehandler.h"
35 #include "ocrandom.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 Request context will suffice as long
53  * as SRM is single-threaded.
54  */
55 SRMRequestContext_t g_requestContext;
56
57 /**
58  * Function to register provisoning API's response callback.
59  * @param respHandler response handler callback.
60  */
61 void SRMRegisterProvisioningResponseHandler(SPResponseCallback respHandler)
62 {
63     gSPResponseHandler = respHandler;
64 }
65
66 void SetRequestedResourceType(SRMRequestContext_t *context)
67 {
68     context->resourceType = GetSvrTypeFromUri(context->resourceUri);
69 }
70
71 // Send the response (context->responseInfo) to the requester
72 // (context->endPoint).
73 static void SRMSendResponse(SRMRequestContext_t *context)
74 {
75     if (NULL != context
76         && NULL != context->requestInfo
77         && NULL != context->endPoint)
78     {
79
80         if (CA_STATUS_OK == CASendResponse(context->endPoint,
81             &(context->responseInfo)))
82         {
83             OIC_LOG(DEBUG, TAG, "SRM response sent.");
84             context->responseSent = true;
85         }
86         else
87         {
88             OIC_LOG(ERROR, TAG, "SRM response failed.");
89         }
90     }
91     else
92     {
93         OIC_LOG_V(ERROR, TAG, "%s : NULL Parameter(s)",__func__);
94     }
95
96     return;
97 }
98
99 // Based on the context->responseVal, either call the entity handler for the
100 // request (which must send the response), or send an ACCESS_DENIED response.
101 void SRMGenerateResponse(SRMRequestContext_t *context)
102 {
103     OIC_LOG_V(INFO, TAG, "%s : entering function.", __func__);
104
105     // If Access Granted, validate parameters and then pass request
106     // on to resource endpoint.
107     if (IsAccessGranted(context->responseVal))
108     {
109         if (NULL != gRequestHandler
110             && NULL != context->endPoint
111             && NULL != context->requestInfo)
112         {
113             OIC_LOG_V(INFO, TAG, "%s : Access granted, passing req to endpoint.",
114              __func__);
115             gRequestHandler(context->endPoint, context->requestInfo);
116             context->responseSent = true; // SRM counts on the endpoint to send
117                                           // a response.
118         }
119         else // error condition; log relevant msg then send DENIED response
120         {
121             OIC_LOG_V(ERROR, TAG, "%s : Null values in context.", __func__);
122             context->responseVal = ACCESS_DENIED_POLICY_ENGINE_ERROR;
123             context->responseInfo.result = CA_INTERNAL_SERVER_ERROR;
124             SRMSendResponse(context);
125         }
126     }
127     else // Access Denied
128     {
129         OIC_LOG_V(INFO, TAG, "%s : Access Denied; sending CA_UNAUTHORIZED_REQ.",
130          __func__);
131         // TODO: in future version, differentiate between types of DENIED.
132         // See JIRA issue 1796 (https://jira.iotivity.org/browse/IOT-1796)
133         context->responseInfo.result = CA_UNAUTHORIZED_REQ;
134         SRMSendResponse(context);
135     }
136     return;
137 }
138
139 // Set the value of context->resourceUri, based on the context->requestInfo.
140 void SetResourceUriAndType(SRMRequestContext_t *context)
141 {
142     char *uri = strstr(context->requestInfo->info.resourceUri, "?");
143     size_t position = 0;
144
145     if (uri)
146     {
147         //Skip query and pass the resource uri
148         position = uri - context->requestInfo->info.resourceUri;
149     }
150     else
151     {
152         position = strlen(context->requestInfo->info.resourceUri);
153     }
154     if (MAX_URI_LENGTH < position  || 0 > position)
155     {
156         OIC_LOG(ERROR, TAG, "Incorrect URI length.");
157         return;
158     }
159     OICStrcpyPartial(context->resourceUri, MAX_URI_LENGTH + 1,
160         context->requestInfo->info.resourceUri, position);
161
162     // Set the resource type.
163     context->resourceType = GetSvrTypeFromUri(context->resourceUri);
164
165     return;
166 }
167
168 // Check if this request is asking to access a "sec" = true resource
169 // over an unsecure channel.  This type of request is forbidden with
170 // the exception of a few SVRs (see Security Specification).
171 void CheckRequestForSecResourceOverUnsecureChannel(SRMRequestContext_t *context)
172 {
173     OIC_LOG_V(DEBUG, TAG, "%s: secureChannel = %u, resourceType = %d, URI = %s",
174         __func__, (uint32_t)context->secureChannel,
175         context->resourceType, context->resourceUri);
176
177     // if request is over unsecure channel, check resource type
178     if (false == context->secureChannel)
179     {
180         OCResource *resPtr = FindResourceByUri(context->resourceUri);
181
182         // TODO: IOT-1843:
183         // Should a NULL return value from FindResourceByUri result in CA_FORBIDDEN_REQ?
184         if (NULL != resPtr)
185         {
186             OIC_LOG_V(DEBUG, TAG, "%s: OC_SECURE = %s",
187                 __func__, ((resPtr->resourceProperties) & OC_SECURE) ? "true" : "false");
188
189             // All vertical secure resources and SVR resources other than
190             // DOXM & PSTAT should reject requests over unsecure channel.
191             if ((((resPtr->resourceProperties) & OC_SECURE)
192                 && (context->resourceType == NOT_A_SVR_RESOURCE))
193                 || ((context->resourceType < OIC_SEC_SVR_TYPE_COUNT)
194                     && (context->resourceType != OIC_R_DOXM_TYPE)
195                     && (context->resourceType != OIC_R_PSTAT_TYPE)))
196             {
197                 // Reject all the requests over coap for secure resource.
198                 context->responseVal = ACCESS_DENIED_SEC_RESOURCE_OVER_UNSECURE_CHANNEL;
199                 context->responseInfo.result = CA_FORBIDDEN_REQ;
200                 SRMSendResponse(context);
201             }
202             else
203             {
204                 OIC_LOG_V(DEBUG, TAG, "%s: Allowing unsecured access", __func__);
205             }
206         }
207     }
208
209     return;
210 }
211
212 void ClearRequestContext(SRMRequestContext_t *context)
213 {
214     if (NULL == context)
215     {
216
217         OIC_LOG(ERROR, TAG, "Null context.");
218     }
219     else
220     {
221         // Clear context variables.
222         context->endPoint = NULL;
223         context->resourceType = OIC_RESOURCE_TYPE_ERROR;
224         memset(&context->resourceUri, 0, sizeof(context->resourceUri));
225         context->requestedPermission = PERMISSION_ERROR;
226         memset(&context->responseInfo, 0, sizeof(context->responseInfo));
227         context->responseSent = false;
228         context->responseVal = ACCESS_DENIED_POLICY_ENGINE_ERROR;
229         context->requestInfo = NULL;
230         context->secureChannel = false;
231         context->slowResponseSent = false;
232         context->subjectIdType = SUBJECT_ID_TYPE_ERROR;
233         memset(&context->subjectUuid, 0, sizeof(context->subjectUuid));
234 #ifdef MULTIPLE_OWNER
235         context->payload = NULL;
236         context->payloadSize = 0;
237 #endif //MULTIPLE_OWNER
238     }
239
240     return;
241 }
242
243 // Returns true iff Request arrived over secure channel
244 // Note: context->subjectUuid must be copied from requestInfo prior to calling
245 // this function, or this function may incorrectly read the nil-UUID (0s)
246 // and assume CoAP request (which can result in request being incorrectly
247 // denied).
248 bool isRequestOverSecureChannel(SRMRequestContext_t *context)
249 {
250     OicUuid_t nullSubjectId = {.id = {0}};
251
252     // If flag set, return true
253     if (context->endPoint->flags & CA_SECURE)
254     {
255         OIC_LOG(DEBUG, TAG, "CA_SECURE flag is set; indicates secure channel.");
256         return true;
257     }
258
259     // A null subject ID indicates CoAP, so if non-null, also return true
260     if (SUBJECT_ID_TYPE_UUID == context->subjectIdType)
261     {
262         if (memcmp(context->subjectUuid.id, nullSubjectId.id,
263             sizeof(context->subjectUuid.id)) != 0)
264         {
265             OIC_LOG(DEBUG, TAG, "Subject ID is non-null; indicates secure channel.");
266             return true;
267         }
268     }
269
270     OIC_LOG(DEBUG, TAG, "CA_SECURE flag is not set, and Subject ID of requester \
271         is NULL; indicates unsecure channel.");
272     return false;
273 }
274
275 /**
276  * Entry point into SRM, called by lower layer to determine whether an incoming
277  * request should be GRANTED or DENIED.
278  *
279  * @param endPoint object from which the response is received.
280  * @param requestInfo contains information for the request.
281  */
282 void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requestInfo)
283 {
284     OIC_LOG(DEBUG, TAG, "Received request from remote device");
285
286     SRMRequestContext_t *ctx = &g_requestContext; // Always use our single ctx for now.
287
288     ClearRequestContext(ctx);
289
290     if (!endPoint || !requestInfo)
291     {
292         OIC_LOG(ERROR, TAG, "Invalid endPoint or requestInfo; can't process.");
293     }
294     else
295     {
296         ctx->endPoint = endPoint;
297         ctx->requestInfo = requestInfo;
298         ctx->requestedPermission = GetPermissionFromCAMethod_t(requestInfo->method);
299
300         // Copy the subjectID, truncating to 16-byte UUID (32 hex-digits).
301         // TODO IOT-1894 "Determine appropriate CA_MAX_ENDPOINT_IDENTITY_LEN"
302         ctx->subjectIdType = SUBJECT_ID_TYPE_UUID; // only supported type for now
303         memcpy(ctx->subjectUuid.id,
304             requestInfo->info.identity.id, sizeof(ctx->subjectUuid.id));
305
306 #ifndef NDEBUG // if debug build, log the ID being used for matching ACEs
307         if (SUBJECT_ID_TYPE_UUID == ctx->subjectIdType)
308         {
309             char strUuid[UUID_STRING_SIZE] = "UUID_ERROR";
310             if (OCConvertUuidToString(ctx->subjectUuid.id, strUuid))
311             {
312                 OIC_LOG_V(DEBUG, TAG, "ctx->subjectUuid for request: %s.", strUuid);
313             }
314             else
315             {
316                 OIC_LOG(ERROR, TAG, "failed to convert ctx->subjectUuid to str.");
317             }
318         }
319 #endif
320
321         // Set secure channel boolean.
322         ctx->secureChannel = isRequestOverSecureChannel(ctx);
323
324         // Set resource URI and type.
325         SetResourceUriAndType(ctx);
326
327         // Initialize responseInfo.
328         memcpy(&(ctx->responseInfo.info), &(requestInfo->info),
329             sizeof(ctx->responseInfo.info));
330         ctx->responseInfo.info.payload = NULL;
331         ctx->responseInfo.result = CA_INTERNAL_SERVER_ERROR;
332         ctx->responseInfo.info.dataType = CA_RESPONSE_DATA;
333
334         // Before consulting ACL, check if this is a forbidden request type.
335         CheckRequestForSecResourceOverUnsecureChannel(ctx);
336
337         // If DENIED response wasn't sent already, then it's time to check ACL.
338         if (false == ctx->responseSent)
339         {
340 #ifdef MULTIPLE_OWNER // TODO Samsung: please verify that these two calls belong
341                       // here inside this conditional statement.
342             // In case of ACL and CRED, The payload required to verify the payload.
343             // Payload information will be used for subowner's permission verification.
344             ctx->payload = (uint8_t*)requestInfo->info.payload;
345             ctx->payloadSize = requestInfo->info.payloadSize;
346 #endif //MULTIPLE_OWNER
347
348             OIC_LOG_V(DEBUG, TAG, "Processing request with uri, %s for method %d",
349                 ctx->requestInfo->info.resourceUri, ctx->requestInfo->method);
350             CheckPermission(ctx);
351             OIC_LOG_V(DEBUG, TAG, "Request for permission %d received responseVal %d.",
352                 ctx->requestedPermission, ctx->responseVal);
353
354             // Now that we have determined the correct response and set responseVal,
355             // we generate and send the response to the requester.
356             SRMGenerateResponse(ctx);
357         }
358     }
359
360     if (false == ctx->responseSent)
361     {
362         OIC_LOG(ERROR, TAG, "Exiting SRM without responding to requester!");
363     }
364
365     return;
366 }
367
368 /**
369  * Handle the response from the SRM.
370  *
371  * @param endPoint points to the remote endpoint.
372  * @param responseInfo contains response information from the endpoint.
373  */
374 void SRMResponseHandler(const CAEndpoint_t *endPoint, const CAResponseInfo_t *responseInfo)
375 {
376     OIC_LOG(DEBUG, TAG, "Received response from remote device");
377
378     // isProvResponse flag is to check whether response is catered by provisioning APIs or not.
379     // When token sent by CA response matches with token generated by provisioning request,
380     // gSPResponseHandler returns true and response is not sent to RI layer. In case
381     // gSPResponseHandler is null and isProvResponse is false response then the response is for
382     // RI layer.
383     bool isProvResponse = false;
384
385     if (gSPResponseHandler)
386     {
387         isProvResponse = gSPResponseHandler(endPoint, responseInfo);
388     }
389     if (!isProvResponse && gResponseHandler)
390     {
391         gResponseHandler(endPoint, responseInfo);
392     }
393 }
394
395 /**
396  * Handle the error from the SRM.
397  *
398  * @param endPoint is the remote endpoint.
399  * @param errorInfo contains error information from the endpoint.
400  */
401 void SRMErrorHandler(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo)
402 {
403     OIC_LOG_V(INFO, TAG, "Received error from remote device with result, %d for request uri, %s",
404         errorInfo->result, errorInfo->info.resourceUri);
405     if (gErrorHandler)
406     {
407         gErrorHandler(endPoint, errorInfo);
408     }
409 }
410
411 OCStackResult SRMRegisterHandler(CARequestCallback reqHandler,
412     CAResponseCallback respHandler, CAErrorCallback errHandler)
413 {
414     OIC_LOG(DEBUG, TAG, "SRMRegisterHandler !!");
415     if (!reqHandler || !respHandler || !errHandler)
416     {
417         OIC_LOG(ERROR, TAG, "Callback handlers are invalid");
418         return OC_STACK_INVALID_PARAM;
419     }
420     gRequestHandler = reqHandler;
421     gResponseHandler = respHandler;
422     gErrorHandler = errHandler;
423
424
425 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
426     CARegisterHandler(SRMRequestHandler, SRMResponseHandler, SRMErrorHandler);
427 #else
428     CARegisterHandler(reqHandler, respHandler, errHandler);
429 #endif /* __WITH_DTLS__ */
430     return OC_STACK_OK;
431 }
432
433 OCStackResult SRMRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler)
434 {
435     OIC_LOG(DEBUG, TAG, "SRMRegisterPersistentStorageHandler !!");
436     return OCRegisterPersistentStorageHandler(persistentStorageHandler);
437 }
438
439 OCPersistentStorage* SRMGetPersistentStorageHandler()
440 {
441     return OCGetPersistentStorageHandler();
442 }
443
444 OCStackResult SRMInitSecureResources()
445 {
446     // TODO: temporarily returning OC_STACK_OK every time until default
447     // behavior (for when SVR DB is missing) is settled.
448     InitSecureResources();
449     OCStackResult ret = OC_STACK_OK;
450 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
451     if (CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
452     {
453         OIC_LOG(ERROR, TAG, "Failed to revert TLS credential handler.");
454         ret = OC_STACK_ERROR;
455     }
456     CAregisterPkixInfoHandler(GetPkixInfo);
457     CAregisterGetCredentialTypesHandler(InitCipherSuiteList);
458 #endif // __WITH_DTLS__ or __WITH_TLS__
459     return ret;
460 }
461
462 void SRMDeInitSecureResources()
463 {
464     DestroySecureResources();
465 }
466
467 bool SRMIsSecurityResourceURI(const char* uri)
468 {
469     if (!uri)
470     {
471         return false;
472     }
473
474 #ifdef _MSC_VER
475     // The strings below are const but they are also marked as extern so they cause warnings.
476 #pragma warning(push)
477 #pragma warning(disable:4204)
478 #endif
479     const char *rsrcs[] = {
480         OIC_RSRC_SVC_URI,
481         OIC_RSRC_AMACL_URI,
482         OIC_RSRC_CRL_URI,
483         OIC_RSRC_CRED_URI,
484         OIC_RSRC_ACL_URI,
485         OIC_RSRC_DOXM_URI,
486         OIC_RSRC_PSTAT_URI,
487         OIC_RSRC_PCONF_URI,
488         OIC_RSRC_DPAIRING_URI,
489         OIC_RSRC_VER_URI,
490         OC_RSRVD_PROV_CRL_URL
491     };
492
493 #ifdef _MSC_VER
494 #pragma warning(pop)
495 #endif
496
497     // Remove query from Uri for resource string comparison
498     size_t uriLen = strlen(uri);
499     char *query = strchr (uri, '?');
500     if (query)
501     {
502         uriLen = query - uri;
503     }
504
505     for (size_t i = 0; i < sizeof(rsrcs)/sizeof(rsrcs[0]); i++)
506     {
507         size_t svrLen = strlen(rsrcs[i]);
508
509         if ((uriLen == svrLen) &&
510             (strncmp(uri, rsrcs[i], svrLen) == 0))
511         {
512             return true;
513         }
514     }
515
516     return false;
517 }
518
519 /**
520  * Get the Secure Virtual Resource (SVR) type from the URI.
521  * @param   uri [IN] Pointer to URI in question.
522  * @return  The OicSecSvrType_t of the URI passed (note: if not a Secure Virtual
523             Resource, e.g. /a/light, will return "NOT_A_SVR_TYPE" enum value)
524  */
525 static const char URI_QUERY_CHAR = '?';
526 OicSecSvrType_t GetSvrTypeFromUri(const char* uri)
527 {
528     if (!uri)
529     {
530         return NOT_A_SVR_RESOURCE;
531     }
532
533     // Remove query from Uri for resource string comparison
534     size_t uriLen = strlen(uri);
535     char *query = strchr (uri, URI_QUERY_CHAR);
536     if (query)
537     {
538         uriLen = query - uri;
539     }
540
541     size_t svrLen = 0;
542
543     svrLen = strlen(OIC_RSRC_ACL_URI);
544     if (uriLen == svrLen)
545     {
546         if (0 == strncmp(uri, OIC_RSRC_ACL_URI, svrLen))
547         {
548             return OIC_R_ACL_TYPE;
549         }
550     }
551
552     svrLen = strlen(OIC_RSRC_AMACL_URI);
553     if (uriLen == svrLen)
554     {
555         if (0 == strncmp(uri, OIC_RSRC_AMACL_URI, svrLen))
556         {
557             return OIC_R_AMACL_TYPE;
558         }
559     }
560
561     svrLen = strlen(OIC_RSRC_CRED_URI);
562     if (uriLen == svrLen)
563     {
564         if (0 == strncmp(uri, OIC_RSRC_CRED_URI, svrLen))
565         {
566             return OIC_R_CRED_TYPE;
567         }
568     }
569
570     svrLen = strlen(OIC_RSRC_CRL_URI);
571     if (uriLen == svrLen)
572     {
573         if (0 == strncmp(uri, OIC_RSRC_CRL_URI, svrLen))
574         {
575             return OIC_R_CRL_TYPE;
576         }
577     }
578
579     svrLen = strlen(OIC_RSRC_DOXM_URI);
580     if (uriLen == svrLen)
581     {
582         if (0 == strncmp(uri, OIC_RSRC_DOXM_URI, svrLen))
583         {
584             return OIC_R_DOXM_TYPE;
585         }
586     }
587
588     svrLen = strlen(OIC_RSRC_DPAIRING_URI);
589     if (uriLen == svrLen)
590     {
591         if (0 == strncmp(uri, OIC_RSRC_DPAIRING_URI, svrLen))
592         {
593             return OIC_R_DPAIRING_TYPE;
594         }
595     }
596
597     svrLen = strlen(OIC_RSRC_PCONF_URI);
598     if (uriLen == svrLen)
599     {
600         if (0 == strncmp(uri, OIC_RSRC_PCONF_URI, svrLen))
601         {
602             return OIC_R_PCONF_TYPE;
603         }
604     }
605
606     svrLen = strlen(OIC_RSRC_PSTAT_URI);
607     if (uriLen == svrLen)
608     {
609         if (0 == strncmp(uri, OIC_RSRC_PSTAT_URI, svrLen))
610         {
611             return OIC_R_PSTAT_TYPE;
612         }
613     }
614
615     svrLen = strlen(OIC_RSRC_SVC_URI);
616     if (uriLen == svrLen)
617     {
618         if (0 == strncmp(uri, OIC_RSRC_SVC_URI, svrLen))
619         {
620             return OIC_R_SVC_TYPE;
621         }
622     }
623
624     svrLen = strlen(OIC_RSRC_SACL_URI);
625     if (uriLen == svrLen)
626     {
627         if (0 == strncmp(uri, OIC_RSRC_SACL_URI, svrLen))
628         {
629             return OIC_R_SACL_TYPE;
630         }
631     }
632
633     return NOT_A_SVR_RESOURCE;
634 }