chande from SP names to OIDS
[iotivity.git] / resource / csdk / security / src / spresource.c
1 //******************************************************************
2 // Copyright 2018 Cable Television Laboratories, Inc.
3 //
4 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 //      http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific lan guage governing permissions and
16 // limitations under the License.
17 //
18 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
19
20 #include "iotivity_config.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25
26 #include "ocstack.h"
27 #include "oic_malloc.h"
28 #include "oic_string.h"
29 #include "ocpayload.h"
30 #include "ocpayloadcbor.h"
31 #include "experimental/payload_logging.h"
32 #include "psinterface.h"
33 #include "resourcemanager.h"
34 #include "spresource.h"
35 #include "deviceonboardingstate.h"
36 #include "srmutility.h"
37 #include "srmresourcestrings.h"
38
39 #define TAG  "OIC_SRM_SP"
40
41 #define OIC_CBOR_SP_NAME "sp"
42
43 static OCResourceHandle    gSpHandle  = NULL;
44 static OicSecSp_t         *gSp        = NULL;
45
46 // Default sp values
47 char * gSupportedProfiles[] = { "1.3.6.1.4.1.51414.0.1.0" };
48 OicSecSp_t gDefaultSp =
49 {
50     1,                     // supportedLen
51     gSupportedProfiles,    // supportedProfiles[0]
52     "1.3.6.1.4.1.51414.0.1.0", // currentProfile
53 };
54
55 bool gAllProps[SP_PROPERTY_COUNT] = { true, true };
56
57 // Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
58 // The value of payload size is increased until reaching below max cbor size.
59 static const uint16_t CBOR_SIZE = 512;
60
61 // Max cbor size payload.
62 static const uint16_t CBOR_MAX_SIZE = 4400;
63
64 // Minimum SP map size (rt, if)
65 static const uint8_t SP_MIN_MAP_SIZE = 2;
66
67 OCStackResult SpToCBORPayload(const OicSecSp_t *sp, uint8_t **payload, size_t *size)
68 {
69     bool allProps[SP_PROPERTY_COUNT];
70     SetAllSpProps(allProps, true);
71
72     return SpToCBORPayloadPartial(sp, payload, size, allProps);
73 }
74
75 OCStackResult SpToCBORPayloadPartial(const OicSecSp_t *sp,
76                                      uint8_t **payload, size_t *size,
77                                      const bool *propertiesToInclude)
78 {
79     if (NULL == sp || NULL == payload || NULL != *payload || NULL == size)
80     {
81         return OC_STACK_INVALID_PARAM;
82     }
83
84     size_t cborLen = *size;
85     if (0 == cborLen)
86     {
87         cborLen = CBOR_SIZE;
88     }
89
90     *payload = NULL;
91     *size = 0;
92
93     OCStackResult ret = OC_STACK_ERROR;
94     int64_t cborEncoderResult = CborNoError;
95
96     CborEncoder encoder;
97     CborEncoder spMap;
98
99     // Calculate map size
100     size_t spMapSize = SP_MIN_MAP_SIZE;
101     for (int i = 0; i < SP_PROPERTY_COUNT; i++)
102     {
103         if (propertiesToInclude[i])
104         {
105             spMapSize++;
106         }
107     }
108
109     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
110     VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_ERROR);
111
112     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
113     cborEncoderResult = cbor_encoder_create_map(&encoder, &spMap, spMapSize);
114     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding sp Map.");
115
116     // supportedprofiles
117     if (propertiesToInclude[SP_SUPPORTED_PROFILES])
118     {
119         VERIFY_OR_LOG_AND_EXIT(TAG, (0 < sp->supportedLen),
120             "List of supported security profiles can't be empty", ERROR);
121
122         cborEncoderResult = cbor_encode_text_string(
123             &spMap, OIC_JSON_SUPPORTED_SP_NAME, strlen(OIC_JSON_SUPPORTED_SP_NAME));
124         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult,
125             "Failed Adding supportedprofiles Name Tag.");
126         OIC_LOG_V(DEBUG, TAG, "%s encoded sp %s tag.", __func__, OIC_JSON_SUPPORTED_SP_NAME);
127
128         CborEncoder supportedProfiles;
129         cborEncoderResult = cbor_encoder_create_array(&spMap, &supportedProfiles, sp->supportedLen);
130         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed creating supported_types Array.");
131         OIC_LOG_V(DEBUG, TAG, "%s created sp supportedprofiles array.", __func__);
132         for(size_t i = 0; i < sp->supportedLen; i++)
133         {
134             char* curProfile = sp->supportedProfiles[i];
135             cborEncoderResult = cbor_encode_text_string(&supportedProfiles, curProfile, strlen(curProfile));
136             VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding supportedprofiles Value.");
137             OIC_LOG_V(DEBUG, TAG, "%s encoded sp supportedprofiles value %s.", __func__, curProfile);
138         }
139
140         cborEncoderResult = cbor_encoder_close_container(&spMap, &supportedProfiles);
141         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing supportedProfiles.");
142         OIC_LOG_V(DEBUG, TAG, "%s closed sp supportedprofiles map.", __func__);
143     }
144
145     // current profile
146     if (propertiesToInclude[SP_CURRENT_PROFILE])
147     {
148         cborEncoderResult = cbor_encode_text_string(
149             &spMap, OIC_JSON_CURRENT_SP_NAME, strlen(OIC_JSON_CURRENT_SP_NAME));
150         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding currentprofile Name Tag.");
151         OIC_LOG_V(DEBUG, TAG, "%s encoded sp %s tag.", __func__, OIC_JSON_CURRENT_SP_NAME);
152
153         cborEncoderResult = cbor_encode_text_string(
154             &spMap, sp->currentProfile, strlen(sp->currentProfile));
155         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding supportedprofiles Value.");
156         OIC_LOG_V(DEBUG, TAG, "%s encoded sp currentprofile value %s.", __func__, sp->currentProfile);
157     }
158
159     // rt (mandatory)
160
161     CborEncoder rtArray;
162     cborEncoderResult = cbor_encode_text_string(
163         &spMap, OIC_JSON_RT_NAME, strlen(OIC_JSON_RT_NAME));
164     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
165     cborEncoderResult = cbor_encoder_create_array(&spMap, &rtArray, 1);
166     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding RT Value.");
167     for (size_t i = 0; i < 1; i++)
168     {
169         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_SP,
170                 strlen(OIC_RSRC_TYPE_SEC_SP));
171         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding RT Value.");
172     }
173     cborEncoderResult = cbor_encoder_close_container(&spMap, &rtArray);
174     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing RT.");
175
176     // if (mandatory)
177
178     CborEncoder ifArray;
179     cborEncoderResult = cbor_encode_text_string(&spMap, OIC_JSON_IF_NAME,
180        strlen(OIC_JSON_IF_NAME));
181     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
182     cborEncoderResult = cbor_encoder_create_array(&spMap, &ifArray, 1);
183     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Addding IF Value.");
184     for (size_t i = 0; i < 1; i++)
185     {
186         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
187                 strlen(OC_RSRVD_INTERFACE_DEFAULT));
188         VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Adding IF Value.");
189     }
190     cborEncoderResult = cbor_encoder_close_container(&spMap, &ifArray);
191     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing IF.");
192
193     cborEncoderResult = cbor_encoder_close_container(&encoder, &spMap);
194     VERIFY_CBOR_SUCCESS_OR_OUT_OF_MEMORY(TAG, cborEncoderResult, "Failed Closing SP Map.");
195
196     if (CborNoError == cborEncoderResult)
197     {
198         *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
199         *payload = outPayload;
200         ret = OC_STACK_OK;
201     }
202
203 exit:
204     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
205     {
206         // reallocate and try again!
207         OICFree(outPayload);
208         outPayload = NULL;
209
210         // Since the allocated initial memory failed, double the memory.
211         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
212         cborEncoderResult = CborNoError;
213         ret = SpToCBORPayloadPartial(sp, payload, &cborLen, propertiesToInclude);
214         if (OC_STACK_OK == ret)
215         {
216             *size = cborLen;
217         }
218     }
219
220     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
221     {
222         OICFree(outPayload);
223         outPayload = NULL;
224         *payload = NULL;
225         *size = 0;
226         ret = OC_STACK_ERROR;
227     }
228
229     return ret;
230 }
231
232 /**
233  * Static method to extract a supportedprofiles array from spMap.
234  *
235  * @param [i] spMap             sp map positioned at supportedprofiles array
236  * @param [o] supportedProfiles allocated and extracted list of supported profile names
237  * @param [o] supportedLen      length of the extracted supportedProfiles array
238  *
239  * @return ::OC_STACK_OK for Success, otherwise some error value.
240  *
241  * @note: this fxn allocates the supportedProfiles array, free with OICFree when done
242 */
243 static OCStackResult SupportedProfilesFromCBOR(CborValue *spMap,
244                                                char*** supportedProfiles,
245                                                size_t* supportedLen)
246 {
247     OCStackResult ret = OC_STACK_ERROR;
248     CborError cborResult = CborNoError;
249     *supportedProfiles = NULL;
250     *supportedLen = 0;
251
252     size_t readLen = 0;
253
254     cborResult = cbor_value_get_array_length(spMap, supportedLen);
255     VERIFY_OR_LOG_AND_EXIT(TAG, (CborNoError == cborResult) && (0 != supportedLen),
256         "Failed to find sp supportedprofiles array length", ERROR);
257
258     *supportedProfiles = (char**)OICCalloc(*supportedLen, sizeof(char*));
259     VERIFY_NOT_NULL(TAG, *supportedProfiles, ERROR);
260
261     CborValue supportedProfilesCbor;
262     cborResult = cbor_value_enter_container(spMap, &supportedProfilesCbor);
263     VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to enter SP supportedprofiles array");
264
265     size_t numProfilesExtracted = 0;
266     for(size_t i = 0;
267        cbor_value_is_valid(&supportedProfilesCbor) &&
268        cbor_value_is_text_string(&supportedProfilesCbor); i++)
269     {
270         // Extract the current profile name
271         cborResult = cbor_value_dup_text_string(
272             &supportedProfilesCbor, &((*supportedProfiles)[i]), &readLen, NULL);
273         VERIFY_CBOR_SUCCESS(TAG, cborResult,
274             "Failed to extract SP security profile name from supportedprofiles.");
275         numProfilesExtracted++;
276
277         // advance to the next profile
278         cborResult = cbor_value_advance(&supportedProfilesCbor);
279         VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to advance to the SP next security profile name.");
280     }
281
282     // Make sure we extracted the entire contents of the cbor array
283     VERIFY_OR_LOG_AND_EXIT(TAG, (*supportedLen == numProfilesExtracted),
284         "Not all of the profiles from SP supportedprofiles were extracted", ERROR);
285
286     ret = OC_STACK_OK;
287
288 exit:
289
290     if ((CborNoError != cborResult) && (NULL != *supportedProfiles))
291     {
292         OICFree(supportedProfiles);
293         *supportedProfiles = NULL;
294         *supportedLen = 0;
295         ret = OC_STACK_ERROR;
296     }
297
298     return ret;
299 }
300
301 /**
302  * Static method to extract the currentprofile from a spMap, and determine the
303  * corresponding index into the supportedProfiles array
304  *
305  * @param [i] spMap             sp map positioned at supportedprofiles map
306  * @param [i] supportedProfiles array of supported profile names
307  * @param [i] supportedLen      length of supportedProfiles array
308  *
309  * @param [o] currentProfile     current profile
310  *                              NULL on error
311  *
312  * @return ::OC_STACK_OK for Success, otherwise error value.
313  */
314 static OCStackResult CurrentProfileFromCBOR(CborValue *spMap, char **currentProfile)
315 {
316     OCStackResult ret = OC_STACK_ERROR;
317     CborError cborResult = CborNoError;
318     *currentProfile = NULL;
319
320     size_t readLen = 0;
321
322     // extract the current profile name
323     cborResult = cbor_value_dup_text_string(spMap, currentProfile, &readLen, NULL);
324     VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to extract SP current profile name.");
325
326     ret = OC_STACK_OK;
327
328 exit:
329     return ret;
330 }
331
332 OCStackResult CBORPayloadToSp(const uint8_t *cborPayload,
333                               const size_t size,
334                               OicSecSp_t **secSp,
335                               bool *decodedProperties)
336 {
337
338
339     if (NULL == cborPayload || NULL == secSp || NULL != *secSp || 0 == size)
340     {
341         return OC_STACK_INVALID_PARAM;
342     }
343
344     OCStackResult ret = OC_STACK_ERROR;
345     CborError cborResult = CborNoError;
346
347     CborParser parser = { .end = NULL };
348     CborValue spCbor = { .parser = NULL };
349     CborValue spMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
350
351     OicSecSp_t *sp = NULL;
352
353     if (NULL != decodedProperties)
354     {
355         SetAllSpProps(decodedProperties, false);
356     }
357
358     // init cbor parser
359     cbor_parser_init(cborPayload, size, 0, &parser, &spCbor);
360
361     // allocate sp struct
362     sp = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
363     VERIFY_NOT_NULL(TAG, sp, ERROR);
364
365     // Enter sp map
366     cborResult = cbor_value_enter_container(&spCbor, &spMap);
367     VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to enter the SP map");
368
369     // loop over all cbor entries looking for known keys
370     char* tagName = NULL;
371     size_t tagLen = 0;
372     while (cbor_value_is_valid(&spMap))
373     {
374         // Determine the next tag and advance to the corresponding value
375         CborType type = cbor_value_get_type(&spMap);
376         if (type == CborTextStringType && cbor_value_is_text_string(&spMap))
377         {
378             cborResult = cbor_value_dup_text_string(&spMap, &tagName, &tagLen, NULL);
379             VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed to find next tag name in SP Map.");
380             cborResult = cbor_value_advance(&spMap);
381             VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed Advancing Value in SP Map.");
382         }
383
384         if(NULL != tagName)
385         {
386             // supportedprofiles
387             if (strcmp(tagName, OIC_JSON_SUPPORTED_SP_NAME) == 0)
388             {
389                 ret = SupportedProfilesFromCBOR(
390                     &spMap, &sp->supportedProfiles, &sp->supportedLen);
391                 VERIFY_OR_LOG_AND_EXIT(TAG, OC_STACK_OK == ret,
392                     "Failed to extract list of supported profiles", ERROR);
393                 if (NULL != decodedProperties)
394                 {
395                     decodedProperties[SP_SUPPORTED_PROFILES] = true;
396                 }
397             }
398
399             // current profile
400             else if (strcmp(tagName, OIC_JSON_CURRENT_SP_NAME) == 0)
401             {
402                 ret = CurrentProfileFromCBOR(&spMap, &sp->currentProfile);
403                 VERIFY_OR_LOG_AND_EXIT(TAG, (OC_STACK_OK == ret) && (NULL != sp->currentProfile),
404                     "Failed to extract SP current profile", ERROR);
405                 if (NULL != decodedProperties)
406                 {
407                     decodedProperties[SP_CURRENT_PROFILE] = true;
408                 }
409             }
410
411             // advance to the next tag
412             if (cbor_value_is_valid(&spMap))
413             {
414                 cborResult = cbor_value_advance(&spMap);
415                 VERIFY_CBOR_SUCCESS(TAG, cborResult, "Failed Advancing SP Map.");
416             }
417
418             // cbor using malloc directly, so free() used instead of OICFree
419             free(tagName);
420             tagName = NULL;
421         }
422     }
423
424     *secSp = sp;
425     ret = OC_STACK_OK;
426
427 exit:
428     if (CborNoError != cborResult)
429     {
430         OIC_LOG(ERROR, TAG, "CBORPayloadToSp failed");
431         DeleteSpBinData(sp);
432         sp = NULL;
433         *secSp = NULL;
434         ret = OC_STACK_ERROR;
435     }
436
437     return ret;
438 }
439
440 void DeleteSupportedProfiles(size_t supportedLen, char** supportedProfiles)
441 {
442     if ((0 < supportedLen) && (NULL != supportedProfiles))
443     {
444         for(size_t i = 0; i < supportedLen; i++)
445         {
446             if(NULL != supportedProfiles[i])
447             {
448                 OICFree(supportedProfiles[i]);
449             }
450         }
451     }
452     if (NULL != supportedProfiles)
453     {
454         OICFree(supportedProfiles);
455     }
456 }
457
458 void DeleteSpBinData(OicSecSp_t* sp)
459 {
460     if ((NULL != sp) && (sp != &gDefaultSp))
461     {
462         DeleteSupportedProfiles(sp->supportedLen, sp->supportedProfiles);
463         sp->supportedLen = 0;
464         sp->supportedProfiles = NULL;
465
466         if (NULL != sp->currentProfile)
467         {
468             OICFree(sp->currentProfile);
469         }
470         sp->currentProfile = NULL;
471     }
472 }
473
474 bool RequiredSpPropsPresentAndValid(OicSecSp_t* sp, bool *propertiesPresent)
475 {
476     bool requiredPropsPresentAndValid = false;
477
478     VERIFY_OR_LOG_AND_EXIT(TAG, (true == propertiesPresent[SP_SUPPORTED_PROFILES]),
479         "Required SP property supportedprofiles not present", WARNING);
480
481     VERIFY_OR_LOG_AND_EXIT(TAG, ((NULL != sp->supportedProfiles) && (0 < sp->supportedLen)),
482         "Required SP property supportedprofiles list is empty", WARNING);
483
484     VERIFY_OR_LOG_AND_EXIT(TAG, (true == propertiesPresent[SP_CURRENT_PROFILE]),
485         "Required SP property currentprofile not present", WARNING);
486
487     VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != sp->currentProfile),
488         "Required SP property currentprofile is invalid", WARNING);
489
490     VERIFY_OR_LOG_AND_EXIT(TAG, (0 <= ProfileIdx(sp->supportedLen, sp->supportedProfiles, sp->currentProfile)),
491         "Currentprofile is not contained in supportedprofiles list", WARNING);
492
493     requiredPropsPresentAndValid = true;
494
495 exit:
496
497     return requiredPropsPresentAndValid;
498 }
499
500 /**
501  * Get the default value.
502  *
503  * @return the gDefaultSp pointer.
504  */
505 static OicSecSp_t* GetSpDefault()
506 {
507     return &gDefaultSp;
508 }
509
510 static bool ValidateQuery(const char * query)
511 {
512     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
513     if(NULL == gSp)
514     {
515         return false;
516     }
517
518     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
519     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
520
521     OicParseQueryIter_t parseIter = {.attrPos = NULL};
522
523     ParseQueryIterInit((unsigned char*)query, &parseIter);
524
525     while (GetNextQuery(&parseIter))
526     {
527         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
528         {
529             bInterfaceQry = true;
530             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
531             {
532                 bInterfaceMatch = true;
533             }
534         }
535     }
536     return (bInterfaceQry ? bInterfaceMatch: true);
537 }
538
539 /**
540  * The entity handler determines how to process a GET request.
541  */
542 static OCEntityHandlerResult HandleSpGetRequest (const OCEntityHandlerRequest * ehRequest)
543 {
544     OCEntityHandlerResult ehRet = OC_EH_OK;
545
546     OIC_LOG(INFO, TAG, "HandleSpGetRequest  processing GET request");
547
548     //Checking if Get request is a query.
549     if (ehRequest->query)
550     {
551         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
552         OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
553         if (!ValidateQuery(ehRequest->query))
554         {
555             ehRet = OC_EH_ERROR;
556         }
557     }
558
559     /*
560      * For GET or Valid Query request return pstat resource CBOR payload.
561      * For non-valid query return NULL payload.
562      * A device will 'always' have a default Pstat, so PstatToCBORPayload will
563      * return valid pstat resource json.
564      */
565     size_t size = 0;
566     uint8_t *payload = NULL;
567     if (ehRet == OC_EH_OK)
568     {
569         if(OC_STACK_OK != SpToCBORPayload(gSp, &payload, &size))
570         {
571             OIC_LOG_V(WARNING, TAG, "%s SpToCBORPayload failed.", __func__);
572         }
573     }
574
575     // Send response payload to request originator
576     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
577                    OC_EH_OK : OC_EH_ERROR;
578     OICFree(payload);
579
580     LogSp(gSp, DEBUG, TAG, "SP resource being sent in response to GET:");
581
582     return ehRet;
583 }
584
585 static bool UpdatePersistentStorage(OicSecSp_t *sp)
586 {
587     bool bRet = false;
588
589     size_t size = 0;
590     uint8_t *cborPayload = NULL;
591     OCStackResult ret = SpToCBORPayload(sp, &cborPayload, &size);
592     if (OC_STACK_OK == ret)
593     {
594         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_SP_NAME, cborPayload, size))
595         {
596             bRet = true;
597         }
598         OICFree(cborPayload);
599     }
600
601     return bRet;
602 }
603
604 static char** SpSupportedProfilesDup(size_t supportedLen, char** supportedProfilesSrc)
605 {
606     OCStackResult status = OC_STACK_ERROR;
607     char** supportedProfilesDup = NULL;
608
609     VERIFY_OR_LOG_AND_EXIT(TAG, (0 < supportedLen),
610         "sp supported profiles duplicate: invalid length for supportedprofiles array", ERROR);
611
612     VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != supportedProfilesSrc),
613         "sp  supported profiles duplicate: supportedprofiles array not present", ERROR);
614
615     // allocate and populate list of supported profiles
616     supportedProfilesDup = (char**)OICCalloc(supportedLen, sizeof(char*));
617     VERIFY_NOT_NULL(TAG, supportedProfilesDup, ERROR);
618
619     for(size_t i = 0; i < supportedLen; i++)
620     {
621         if (NULL != supportedProfilesSrc[i])
622         {
623             supportedProfilesDup[i] = OICStrdup(supportedProfilesSrc[i]);
624             VERIFY_NOT_NULL(TAG, supportedProfilesDup[i], ERROR);
625         }
626         else
627         {
628             OIC_LOG_V(WARNING, TAG, "SP supported profiles entry %lu is null, skipping", (unsigned long)i);
629
630         }
631     }
632
633     status = OC_STACK_OK;
634
635 exit:
636     if (OC_STACK_OK != status)
637     {
638         if (NULL != supportedProfilesDup)
639         {
640             DeleteSupportedProfiles(supportedLen, supportedProfilesDup);
641         }
642         return NULL;
643     }
644
645     return supportedProfilesDup;
646 }
647
648
649 // allocate new SP, setting props to spToDup.  Returns NULL on error
650 static OicSecSp_t* SpDup(OicSecSp_t* spToDup)
651 {
652     OicSecSp_t *spToRet = NULL;
653
654     OicSecSp_t *dupSp = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
655     VERIFY_NOT_NULL(TAG, dupSp, ERROR);
656
657     dupSp->supportedLen = spToDup->supportedLen;
658     dupSp->currentProfile = OICStrdup(spToDup->currentProfile);
659     VERIFY_NOT_NULL(TAG, dupSp->currentProfile, ERROR);
660
661     dupSp->supportedProfiles = SpSupportedProfilesDup(spToDup->supportedLen, spToDup->supportedProfiles);
662     VERIFY_NOT_NULL(TAG, dupSp->supportedProfiles, ERROR);
663
664     spToRet = dupSp;
665
666 exit:
667
668     if (NULL == spToRet)
669     {
670         DeleteSpBinData(dupSp);
671     }
672
673     return spToRet;
674 }
675
676 OCStackResult InstallTestSp(OicSecSp_t* testSp)
677 {
678     OCStackResult ret = OC_STACK_ERROR;
679     OicSecSp_t* spCopy = SpDup(testSp);
680     VERIFY_NOT_NULL(TAG, spCopy, ERROR);
681
682     ret = OC_STACK_OK;
683
684 exit:
685
686     if(OC_STACK_OK != ret )
687     {
688         DeleteSpBinData(spCopy);
689     }
690     else
691     {
692         DeleteSpBinData(gSp);
693         gSp = spCopy;
694     }
695
696     return ret;
697 }
698
699 /**
700  * The entity handler determines how to process a POST request.
701  * Per the REST paradigm, POST can also be used to update representation of existing
702  * resource or create a new resource.
703  */
704 static OCEntityHandlerResult HandleSpPostRequest(OCEntityHandlerRequest *ehRequest)
705 {
706     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
707
708     OCEntityHandlerResult ehRet = OC_EH_ERROR;
709     OCStackResult ret = OC_STACK_ERROR;
710
711     OicSecSp_t *spIncoming = NULL;
712     OicSecSp_t *spUpdate = NULL;
713
714     char** supportedProfilesSrc = NULL;
715     char* currentProfileSrc = NULL;
716
717     bool newSupportedProfiles = false;
718     bool newCurrentProfile = false;
719
720     const char * dosNames[] = { "RESET", "RFOTM", "RFPRO", "RFNOP", "SRESET" };
721     (void) dosNames; // to avoid compiler warnings (some compilers don't recognize use in macros)
722
723     uint8_t *payload = NULL;
724     size_t size = 0;
725     OicSecDostype_t dos;
726     ret = GetDos(&dos);
727     VERIFY_OR_LOG_AND_EXIT(TAG, (OC_STACK_OK == ret),
728         "Not able to get onboarding state (pstat.dos) for /sp POST request", ERROR);
729
730     OIC_LOG_V(DEBUG, TAG, "/sp POST request, pstat.dos state = %s (%d)", dosNames[dos.state], dos.state);
731     if ((DOS_RESET == dos.state) || (DOS_RFNOP == dos.state)) {
732         OIC_LOG(ERROR, TAG, "/sp resource is read-only in RESET and RFNOP");
733         ehRet = OC_EH_NOT_ACCEPTABLE;
734         goto exit;
735     }
736
737     VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != ehRequest->payload), "sp POST : no payload supplied ", ERROR);
738     VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != gSp), "sp POST : corrupt internal SP resource ", ERROR);
739
740     payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
741     size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
742     VERIFY_NOT_NULL(TAG, payload, ERROR);
743
744     bool decodedProperties[SP_PROPERTY_COUNT];
745     ret = CBORPayloadToSp(payload, size, &spIncoming, decodedProperties);
746     VERIFY_OR_LOG_AND_EXIT(TAG, ((OC_STACK_OK == ret) && (NULL != spIncoming)),
747         "sp POST : error decoding incoming payload", ERROR);
748
749     newSupportedProfiles = decodedProperties[SP_SUPPORTED_PROFILES];
750     newCurrentProfile = decodedProperties[SP_CURRENT_PROFILE];
751
752     spUpdate = (OicSecSp_t *)OICCalloc(1, sizeof(OicSecSp_t));
753     VERIFY_NOT_NULL(TAG, spUpdate, ERROR);
754
755     // supported profiles
756     spUpdate->supportedLen = newSupportedProfiles ? spIncoming->supportedLen : gSp->supportedLen;
757     supportedProfilesSrc = newSupportedProfiles ? spIncoming->supportedProfiles : gSp->supportedProfiles;
758     spUpdate->supportedProfiles = SpSupportedProfilesDup(spUpdate->supportedLen, supportedProfilesSrc);
759     VERIFY_OR_LOG_AND_EXIT(TAG, (NULL != spUpdate),
760         "Problems duplicating supported profiles list for sp POST", WARNING);
761
762     // log the impact of the post on supported profiles
763     OIC_LOG_V(DEBUG, TAG, "Supported security profiles to be applied as a result of update (%lu entries, %s by POST)",
764              (unsigned long)spUpdate->supportedLen, newSupportedProfiles ? "changed" : "unchanged");
765     for (size_t i = 0; i < spUpdate->supportedLen; i++)
766     {
767         OIC_LOG_V(DEBUG, TAG, "  %lu: %s", (unsigned long)i, spUpdate->supportedProfiles[i]);
768     }
769
770     // current profile
771     currentProfileSrc = newCurrentProfile ? spIncoming->currentProfile : gSp->currentProfile;
772     spUpdate->currentProfile = OICStrdup(currentProfileSrc);
773     VERIFY_NOT_NULL(TAG, spUpdate->currentProfile, ERROR);
774
775     // log the impact of the post on current profile
776     OIC_LOG_V(DEBUG, TAG, "Active profile to be applied as a result of update (%s by POST): %s",
777               newCurrentProfile ? "changed" : "unchanged", spUpdate->currentProfile);
778
779     // make sure current profile is in supported profiles list
780     VERIFY_OR_LOG_AND_EXIT(TAG,
781         (0 <= ProfileIdx(spUpdate->supportedLen, spUpdate->supportedProfiles, spUpdate->currentProfile)),
782         "sp POST : currentprofile is not contained in supportedprofiles list", ERROR);
783
784     // Before we update the sp, lets make sure everthing is valid
785     VERIFY_OR_LOG_AND_EXIT(TAG,
786         (true == RequiredSpPropsPresentAndValid(spUpdate, gAllProps)),
787         "sp POST : update version of security profiles not valid, not updating", ERROR);
788
789     // whew ...
790     ehRet = OC_EH_OK;
791
792 exit:
793
794     if ((OC_EH_OK == ehRet) && (NULL != spUpdate))
795     {
796         if( true != UpdatePersistentStorage(spUpdate))
797         {
798             OIC_LOG_V(DEBUG, TAG, "sp POST : Problems updating persistant storage");
799             ehRet = OC_EH_NOT_ACCEPTABLE;
800
801         }
802         else
803         {
804             // replace our internal copy
805             DeleteSpBinData(gSp);
806             gSp = spUpdate;
807
808             LogSp(gSp, DEBUG, TAG, "State of SP resource after being updated by POST:");
809
810             ehRet = OC_EH_OK;
811         }
812     }
813     else
814     {
815         ehRet = OC_EH_NOT_ACCEPTABLE;
816     }
817
818     if ((OC_EH_OK != ehRet) && (NULL != spUpdate))
819     {
820         DeleteSpBinData(spUpdate);
821     }
822
823     DeleteSpBinData(spIncoming);
824
825     // Send response payload to request originator
826     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
827         OC_EH_OK : OC_EH_ERROR;
828
829     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
830
831     return ehRet;
832 }
833
834 int ProfileIdx( size_t supportedLen, char **supportedProfiles, char *profileName)
835 {
836     if ((NULL != supportedProfiles) && (NULL != profileName))
837     {
838         for (size_t i = 0; i < supportedLen; i++)
839         {
840             if ((NULL != supportedProfiles[i]) && (0 == strcmp(profileName, supportedProfiles[i])))
841             {
842                 return (int)i;
843             }
844         }
845     }
846     return -1;
847 }
848
849 OCEntityHandlerResult SpEntityHandler(OCEntityHandlerFlag flag,
850                                       OCEntityHandlerRequest * ehRequest,
851                                       void* callbackParameter)
852 {
853     OC_UNUSED(callbackParameter);
854     OCEntityHandlerResult ehRet = OC_EH_ERROR;
855
856     // This method will handle REST request (GET/POST) for /oic/sec/sp
857     if (flag & OC_REQUEST_FLAG)
858     {
859         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
860         switch (ehRequest->method)
861         {
862             case OC_REST_GET:
863                 ehRet = HandleSpGetRequest(ehRequest);
864                 break;
865             case OC_REST_POST:
866                 ehRet = HandleSpPostRequest(ehRequest);
867                 break;
868             default:
869                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
870                     OC_EH_OK : OC_EH_ERROR;
871                 break;
872         }
873     }
874     return ehRet;
875 }
876
877 #undef SP_RESOURCE_DISABLE
878 OCStackResult CreateSpResource()
879 {
880     OCStackResult ret = OC_STACK_OK;
881
882 #ifndef SP_RESOURCE_DISABLE
883     ret = OCCreateResource(&gSpHandle,
884                                          OIC_RSRC_TYPE_SEC_SP,
885                                          OC_RSRVD_INTERFACE_DEFAULT,
886                                          OIC_RSRC_SP_URI,
887                                          SpEntityHandler,
888                                          NULL,
889                                          OC_SECURE |
890                                          OC_DISCOVERABLE);
891     if (OC_STACK_OK != ret)
892     {
893         OIC_LOG(FATAL, TAG, "Unable to instantiate sp resource");
894         DeInitSpResource();
895     }
896 #else
897     OIC_LOG_V(WARNING, TAG, "/sp Resource disabled in this build; not creating Resource.");
898 #endif // SP_RESOURCE_DISABLE
899
900     return ret;
901 }
902
903 OCStackResult DeInitSpResource()
904 {
905     if (gSp != &gDefaultSp)
906     {
907         DeleteSpBinData(gSp);
908         gSp = NULL;
909     }
910     return OCDeleteResource(gSpHandle);
911 }
912
913 OCStackResult InitSpResource()
914 {
915     OCStackResult ret = OC_STACK_ERROR;
916
917     // Read sp resource from PS
918     uint8_t *data = NULL;
919     size_t size = 0;
920     ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_SP_NAME, &data, &size);
921
922     // If database read failed
923     if (OC_STACK_OK != ret)
924     {
925         OIC_LOG (DEBUG, TAG, "GetSecureVirtualDatabaseFromPS failed trying to read sp data");
926     }
927     if (data)
928     {
929         // Read sp resource from PS
930         bool decodedProperties[SP_PROPERTY_COUNT];
931         ret = CBORPayloadToSp(data, size, &gSp, decodedProperties);
932         OICFree(data);
933
934         if (false == RequiredSpPropsPresentAndValid(gSp, decodedProperties))
935         {
936             OIC_LOG (WARNING, TAG, "One or more required sp properties missing from  initialization database");
937         }
938     }
939
940     if ((OC_STACK_OK != ret) || !gSp)
941     {
942         gSp = GetSpDefault();
943     }
944     VERIFY_NOT_NULL(TAG, gSp, FATAL);
945
946     // Instantiate 'oic.sec.SP'
947     ret = CreateSpResource();
948
949 exit:
950
951     if (OC_STACK_OK != ret)
952     {
953         DeInitSpResource();
954     }
955     else
956     {
957         LogSp(gSp, DEBUG, TAG, "SP resource after startup initialization");
958     }
959
960     return ret;
961 }
962
963 bool IsPropArraySame(bool* spProps1, bool* spProps2)
964 {
965     for (int i = 0; i < SP_PROPERTY_COUNT; i++)
966     {
967         if ( spProps1[i] != spProps2[i])
968         {
969             return false;
970         }
971     }
972     return true;
973 }
974
975 bool IsSpSame(OicSecSp_t* sp1, OicSecSp_t* sp2, bool *propertiesToCheck)
976 {
977     if ((NULL == sp1) || (NULL == sp2))
978     {
979         return false;
980     }
981
982     if (true == propertiesToCheck[SP_SUPPORTED_PROFILES] || (NULL == propertiesToCheck))
983     {
984         if ((NULL == sp1->supportedProfiles) || (NULL == sp2->supportedProfiles) ||
985             (sp1->supportedLen != sp2->supportedLen))
986         {
987             return false;
988         }
989
990         // check for 100% overlap in supported profiles lists
991         for (size_t i = 0; i < sp1->supportedLen; i++)
992         {
993             if (0 > ProfileIdx(sp1->supportedLen, sp1->supportedProfiles, sp2->supportedProfiles[i]))
994             {
995                 return false;
996             }
997         }
998
999     }
1000
1001     if (true == propertiesToCheck[SP_CURRENT_PROFILE] || (NULL == propertiesToCheck))
1002     {
1003         if ((NULL == sp1->currentProfile) || (NULL == sp2->currentProfile) ||
1004             (0 != strcmp(sp1->currentProfile, sp2->currentProfile)))
1005         {
1006             return false;
1007         }
1008     }
1009
1010     return true;
1011 }
1012
1013 void SetAllSpProps(bool* spProps, bool setTo)
1014 {
1015     for (int i = 0; i < SP_PROPERTY_COUNT; i++)
1016     {
1017         spProps[i] = setTo;
1018     }
1019 }
1020
1021
1022 void LogSp(OicSecSp_t* sp, int level, const char* tag, const char* msg)
1023 {
1024     // some compilers not flagging the use of level and tag in the logging
1025     // macros as being used.  This is to get around these compiler warnings
1026     (void) level;
1027     (void) tag;
1028     (void) msg;
1029
1030     if (NULL != msg)
1031     {
1032         OIC_LOG(level, tag, "-------------------------------------------------");
1033         OIC_LOG_V(level, tag, "%s", msg);
1034     }
1035
1036     OIC_LOG(level, tag, "-------------------------------------------------");
1037     OIC_LOG_V(level, tag, "# security profiles supported: %lu", (unsigned long)sp->supportedLen);
1038     for (size_t i = 0; i < sp->supportedLen; i++)
1039     {
1040         OIC_LOG_V(level, tag, "  %lu: %s", (unsigned long)i, sp->supportedProfiles[i]);
1041     }
1042     OIC_LOG_V(level, tag, "Current security profile: %s", sp->currentProfile);
1043     OIC_LOG(level, tag, "-------------------------------------------------");
1044 }