1 //******************************************************************
3 // Copyright 2017 Intel OpenSource Technology Center All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #include "deviceonboardingstate.h"
22 #include "srmutility.h"
25 #include "srmresourcestrings.h"
26 #include "aclresource.h"
27 #include "amaclresource.h"
28 #include "credresource.h"
29 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
30 #include "crlresource.h"
31 #endif /* (__WITH_DTLS__) || (__WITH_TLS__) */
32 #include "doxmresource.h"
33 #include "pstatresource.h"
34 #include "resourcemanager.h"
36 #define TAG "OIC_SRM_DOS"
39 * @return true if changing from oldState to newState is valid transition.
41 static bool IsValidStateTransition(OicSecDeviceOnboardingState_t oldState,
42 OicSecDeviceOnboardingState_t newState)
53 if (DOS_RFPRO == oldState)
60 if (DOS_RESET == oldState)
67 if (DOS_RFNOP == oldState
68 || DOS_RFOTM == oldState
69 || DOS_SRESET == oldState)
76 if (DOS_RFNOP == oldState
77 || DOS_RFPRO == oldState)
84 OIC_LOG_V(INFO, TAG, "%s: returning %s.", __func__, ret?"true":"false");
89 * @return true if Device meets requirements to enter RFNOP DOS.
91 static bool IsReadyToEnterRFNOP()
94 bool tempBool = false;
95 OicUuid_t tempUuid = {.id={0}};
97 // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
99 // Verify doxm.owned == TRUE.
100 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
101 VERIFY_TRUE_OR_EXIT(TAG, tempBool, WARNING);
103 // Verify doxm.devowneruuid != nil UUID.
104 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
105 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
107 // Verify doxm.deviceuuid != nil UUID.
108 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
109 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
111 // Verify oxmsel was the actual OTM used (no-op: CTT will verify this during
112 // certification testing, as it requires OBT cooperation to verify).
114 // Verify pstat.isop == false (Server sets isop on entry)
115 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatIsop(&tempBool), ERROR);
116 VERIFY_TRUE_OR_EXIT(TAG, !tempBool, WARNING);
118 // Verify implemented SVRs with rowneruuid Property have non-Nil rowneruuid
119 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetAclRownerId(&tempUuid), ERROR);
120 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
122 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCredRownerId(&tempUuid), ERROR);
123 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
125 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmRownerId(&tempUuid), ERROR);
126 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
128 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatRownerId(&tempUuid), ERROR);
129 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
131 // Verify each rowneruuid, devowneruuid has a corresponding /cred entry
137 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
142 * @return true if Device meets requirements to enter RFOTM DOS.
144 static bool IsReadyToEnterRFOTM()
147 bool tempBool = false;
148 OicUuid_t tempUuid = {.id={0}};
150 // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
152 // Verify doxm.owned == FALSE.
153 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
154 VERIFY_TRUE_OR_EXIT(TAG, !tempBool, WARNING);
156 // Verify doxm.devowneruuid == nil UUID.
157 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
158 VERIFY_TRUE_OR_EXIT(TAG, IsNilUuid(&tempUuid), WARNING);
160 // Check and log whether doxm.deviceuuid == nil UUID ("may" reqt not "shall")
161 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
162 if (!IsNilUuid(&tempUuid))
164 OIC_LOG_V(INFO, TAG, "%s: doxm.deviceuuid != Nil UUID... allowed but noted.",
171 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
176 * @return true if Device meets requirements to enter RFPRO DOS.
178 static bool IsReadyToEnterRFPRO()
181 bool tempBool = false;
182 OicUuid_t tempUuid = {.id={0}};
184 // Note: pstat.dos.p asserted by DoStateChange(), so not checked here.
186 // Verify doxm.owned == TRUE.
187 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
188 VERIFY_TRUE_OR_EXIT(TAG, tempBool, WARNING);
190 // Verify doxm.devowneruuid != nil UUID.
191 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
192 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
194 // Verify doxm.deviceuuid != nil UUID.
195 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
196 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
198 // doxm.sct and doxm.oxmsel retain previous values (checked by CTT)
200 // Verify implemented SVRs with rowneruuid Property have non-Nil rowneruuid
201 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetAclRownerId(&tempUuid), ERROR);
202 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
204 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCredRownerId(&tempUuid), ERROR);
205 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
207 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmRownerId(&tempUuid), ERROR);
208 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
210 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatRownerId(&tempUuid), ERROR);
211 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
213 // Verify each rowneruuid, devowneruuid has a corresponding /cred entry
219 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
224 * @return true if Device meets requirements to set pstat.dos.s = SRESET.
226 static bool IsReadyToEnterSRESET()
229 bool tempBool = false;
230 OicUuid_t tempUuid = {.id={0}};
232 // Note: pstat.dos.p set by DoStateChange(), so not checked here.
234 // TODO [IOT-2023]: sanity check SVRs (optional)
236 // Verify doxm.owned == TRUE.
237 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmIsOwned(&tempBool), ERROR);
238 VERIFY_TRUE_OR_EXIT(TAG, tempBool, WARNING);
240 // Verify doxm.devowneruuid != nil UUID.
241 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDevOwnerId(&tempUuid), ERROR);
242 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
244 // Verify doxm.deviceuuid != nil UUID.
245 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetDoxmDeviceID(&tempUuid), ERROR);
246 VERIFY_TRUE_OR_EXIT(TAG, !IsNilUuid(&tempUuid), WARNING);
248 // doxm.sct and doxm.oxmsel retain previous values (checked by CTT)
253 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
258 * Generic ops performed on entering most states, coalesced to avoid repeat code.
260 static bool EnterStateGeneric(bool isop,
265 OicSecDeviceOnboardingState_t state)
271 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatCm(&cm), ERROR);
272 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatTm(&tm), ERROR);
275 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatIsop(isop), ERROR);
280 cm |= RESET; // set RESET bit
284 cm &= ~RESET; // clear RESET bit
288 cm |= TAKE_OWNER; // set TAKE_OWNER bit
292 cm &= ~TAKE_OWNER; // clear TAKE_OWNER bit
294 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatCm(cm), ERROR);
299 tm |= RESET; // set RESET bit
303 tm &= ~RESET; // clear RESET bit
307 tm |= TAKE_OWNER; // set TAKE_OWNER bit
311 tm &= ~TAKE_OWNER; // clear TAKE_OWNER bit
313 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatTm(tm), ERROR);
316 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosS(state), ERROR);
321 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
326 * Enter RFNOP state and set all Server-controlled SVR Property values.
328 static bool EnterRFNOP()
332 // Set pstat.isop = TRUE
333 // Unset pstat.cm RESET and TAKE_OWNER bits
334 // Unset pstat.tm RESET and TAKE_OWNER bits
335 // Set pstat.dos to RFNOP
336 ret = EnterStateGeneric(true, false, false, false, false, DOS_RFNOP);
338 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
343 * Enter RFOTM state and set all Server-controlled SVR Property values.
345 static bool EnterRFOTM()
349 // Set pstat.isop = FALSE
350 // Unset pstat.cm RESET bit, and set TAKE_OWNER bit
351 // Unset pstat.tm RESET and TAKE_OWNER bits
352 // Set pstat.dos to RFOTM
353 ret = EnterStateGeneric(false, false, true, false, false, DOS_RFOTM);
355 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
360 * Enter RFPRO state and set all Server-controlled SVR Property values.
362 static bool EnterRFPRO()
366 // Set pstat.isop = FALSE
367 // Unset pstat.cm RESET and TAKE_OWNER bits
368 // Unset pstat.tm RESET and TAKE_OWNER bits
369 // Set pstat.dos to RFPRO
370 ret = EnterStateGeneric(false, false, false, false, false, DOS_RFPRO);
372 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
377 * Enter RESET state and set all Server-controlled SVR Property values.
379 static bool EnterRESET()
383 // Restore Mfr Defaults
384 // "Mfr Defaults" is defined by manufacturer. It could be "failsafe"
385 // SVRs (e.g. the hard-coded SVRs in IoTivity) or it could be a backup
386 // copy of the initally-provisioned SVRs (e.g. the ResetSecureResourceInPS
387 // function in IoTivity).
388 // TODO [IOT-2633]: VERIFY_SUCCESS(TAG, OC_STACK_OK == ResetSecureResources(), ERROR);
390 // Set doxm.deviceuuid = Mfr Default (handled above)
391 // Set doxm.sct = Mfr Default ("")
392 // Set doxm.oxmsel = Mfr Default ("")
393 // Set pstat.om = Mfr Default ("")
394 // Set pstat.sm = Mfr Default ("")
395 // Assert acl2, amacl, sacl, cred arrays = mfr defaults ("")
397 // Set doxm.owned = FALSE
398 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmIsOwned(false), ERROR);
400 // Set doxm.devowneruuid = Nil UUID
401 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmDevOwnerId(&THE_NIL_UUID), ERROR);
403 // Set acl, doxm, cred and pstat rowneruuids = Nil UUID
404 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetAclRownerId(&THE_NIL_UUID), ERROR);
405 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetDoxmRownerId(&THE_NIL_UUID), ERROR);
406 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatRownerId(&THE_NIL_UUID), ERROR);
408 // Set pstat.isop = FALSE
409 // Set pstat.cm RESET and unset TAKE_OWNER
410 // Unset pstat.tm and set TAKE_OWNER
411 // Set pstat.dos.s to RESET
413 EnterStateGeneric(false, true, false, false, true, DOS_RESET),
416 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
417 // Enable Anon DH cipher suite if appropriate
418 bool isAnonEnabled = false;
420 OC_STACK_OK == EnableAnonCipherSuiteIfUnOwnedAndJustWorksSelected(&isAnonEnabled),
422 OIC_LOG_V(INFO, TAG, "%s: Anon Ciphersuite %sENABLED.", __func__,
423 isAnonEnabled ? "" : "NOT ");
424 #endif // __WITH_DTLS__ or __WITH_TLS__
429 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
434 * Enter SRESET state and set all Server-controlled SVR Property values.
436 static bool EnterSRESET()
440 // Set pstat.isop = FALSE
441 // Set pstat.cm RESET and unset TAKE_OWNER
442 // Unset pstat.tm and unset TAKE_OWNER
443 // Set pstat.dos.s to RESET
445 EnterStateGeneric(false, true, false, false, false, DOS_SRESET),
451 OIC_LOG_V(DEBUG, TAG, "%s: returning %s.", __func__, ret?"true":"false");
456 * Set pstat.dos.p (pending) to true, then verify device is ready to perform
457 * the state change. If so, perform the state change. Finally, set
458 * pstat.dos.p (pending) to false.
459 * @return OC_STACK_OK if successful change to newState
460 * OC_STACK_FORBIDDEN_REQ if state change preconditions not met
461 * OC_STACK_INTERNAL_SERVER_ERROR if SVRs left in potentially unstable state
463 static OCStackResult DoStateChange(OicSecDeviceOnboardingState_t newState)
465 OCStackResult ret = OC_STACK_INTERNAL_SERVER_ERROR;
470 // No preconditions other than setting dos.p = true, which is done above
473 // if RESET succeeds, immediately enter RFOTM
474 if (IsReadyToEnterRFOTM())
482 ret = OC_STACK_INTERNAL_SERVER_ERROR;
487 ret = OC_STACK_FORBIDDEN_REQ;
492 ret = OC_STACK_INTERNAL_SERVER_ERROR;
497 if (IsReadyToEnterRFNOP())
505 ret = OC_STACK_INTERNAL_SERVER_ERROR;
510 ret = OC_STACK_FORBIDDEN_REQ;
515 if (IsReadyToEnterRFOTM())
523 ret = OC_STACK_INTERNAL_SERVER_ERROR;
528 ret = OC_STACK_FORBIDDEN_REQ;
533 if (IsReadyToEnterRFPRO())
541 ret = OC_STACK_INTERNAL_SERVER_ERROR;
546 ret = OC_STACK_FORBIDDEN_REQ;
551 if (IsReadyToEnterSRESET())
559 ret = OC_STACK_INTERNAL_SERVER_ERROR;
564 ret = OC_STACK_FORBIDDEN_REQ;
569 OIC_LOG_V(DEBUG, TAG, "%s: returning %d.", __func__, ret);
573 OCStackResult GetDos(OicSecDostype_t *dos)
577 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosS(&(dos->state)), ERROR);
578 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosP(&(dos->pending)), ERROR);
582 return OC_STACK_ERROR;
585 OCStackResult SetDosState(const OicSecDeviceOnboardingState_t desiredState)
587 OIC_LOG_V(INFO, TAG, "%s called for state %d.", __func__, desiredState);
589 OCStackResult ret = OC_STACK_ERROR;
590 bool pending = false;
592 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosP(&pending), ERROR);
597 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosP(true), ERROR);
599 OicSecDeviceOnboardingState_t oldState = DOS_RESET;
600 VERIFY_SUCCESS(TAG, OC_STACK_OK == GetPstatDosS(&oldState), ERROR);
601 if (IsValidStateTransition(oldState, desiredState))
603 OCStackResult stateChangeResult = DoStateChange(desiredState);
604 switch (stateChangeResult)
607 OIC_LOG_V(INFO, TAG, "%s: DOS state changed SUCCESSFULLY from %d to %d.",
608 __func__, oldState, desiredState);
612 case OC_STACK_FORBIDDEN_REQ:
613 OIC_LOG_V(WARNING, TAG, "%s: DOS state change change from %d to %d NOT ALLOWED.",
614 __func__, oldState, desiredState);
615 ret = OC_STACK_FORBIDDEN_REQ;
618 case OC_STACK_INTERNAL_SERVER_ERROR:
620 OIC_LOG_V(ERROR, TAG, "%s: DOS state change change from %d to %d FAILED."
621 " Internal error - SVRs may be in bad state.",
622 __func__, oldState, desiredState);
623 ret = OC_STACK_INTERNAL_SERVER_ERROR;
629 OIC_LOG_V(INFO, TAG, "%s: Invalid transition; cannot go from %d to %d.", \
630 __func__, oldState, desiredState);
631 ret = OC_STACK_FORBIDDEN_REQ;
634 VERIFY_SUCCESS(TAG, OC_STACK_OK == SetPstatDosP(false), ERROR);
639 OIC_LOG_V(WARNING, TAG, "%s: cannot set pstat->dos.s, change \
640 already pending.", __func__);
641 ret = OC_STACK_FORBIDDEN_REQ;
644 // TODO [IOT-2023] if OC_STACK_OK, update all SVRs in Persistent Storage?
649 return OC_STACK_INTERNAL_SERVER_ERROR;