Line data Source code
1 : /* 2 : * Copyright (c) 2021 Project CHIP Authors 3 : * 4 : * Licensed under the Apache License, Version 2.0 (the "License"); 5 : * you may not use this file except in compliance with the License. 6 : * You may obtain a copy of the License at 7 : * 8 : * http://www.apache.org/licenses/LICENSE-2.0 9 : * 10 : * Unless required by applicable law or agreed to in writing, software 11 : * distributed under the License is distributed on an "AS IS" BASIS, 12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 : * See the License for the specific language governing permissions and 14 : * limitations under the License. 15 : */ 16 : 17 : #include <access/AuthMode.h> 18 : #include <transport/SecureSession.h> 19 : #include <transport/SecureSessionTable.h> 20 : 21 : namespace chip { 22 : namespace Transport { 23 : 24 134968 : void SecureSessionDeleter::Release(SecureSession * entry) 25 : { 26 134968 : entry->mTable.ReleaseSession(entry); 27 134968 : } 28 : 29 110 : void SecureSession::Activate(const ScopedNodeId & localNode, const ScopedNodeId & peerNode, CATValues peerCATs, 30 : uint16_t peerSessionId, const SessionParameters & sessionParameters) 31 : { 32 110 : VerifyOrDie(mState == State::kEstablishing); 33 110 : VerifyOrDie(peerNode.GetFabricIndex() == localNode.GetFabricIndex()); 34 : 35 : // PASE sessions must always start unassociated with a Fabric! 36 110 : VerifyOrDie(!((mSecureSessionType == Type::kPASE) && (peerNode.GetFabricIndex() != kUndefinedFabricIndex))); 37 : // CASE sessions must always start "associated" a given Fabric! 38 110 : VerifyOrDie(!((mSecureSessionType == Type::kCASE) && (peerNode.GetFabricIndex() == kUndefinedFabricIndex))); 39 : // CASE sessions can only be activated against operational node IDs! 40 110 : VerifyOrDie(!((mSecureSessionType == Type::kCASE) && 41 : (!IsOperationalNodeId(peerNode.GetNodeId()) || !IsOperationalNodeId(localNode.GetNodeId())))); 42 : 43 110 : mPeerNodeId = peerNode.GetNodeId(); 44 110 : mLocalNodeId = localNode.GetNodeId(); 45 110 : mPeerCATs = peerCATs; 46 110 : mPeerSessionId = peerSessionId; 47 110 : mRemoteSessionParams = sessionParameters; 48 110 : SetFabricIndex(peerNode.GetFabricIndex()); 49 110 : MarkActiveRx(); // Initialize SessionTimestamp and ActiveTimestamp per spec. 50 : 51 110 : Retain(); // This ref is released inside MarkForEviction 52 110 : MoveToState(State::kActive); 53 : 54 110 : if (mSecureSessionType == Type::kCASE) 55 100 : mTable.NewerSessionAvailable(this); 56 : 57 110 : ChipLogDetail(Inet, "SecureSession[%p]: Activated - Type:%d LSID:%d", this, to_underlying(mSecureSessionType), mLocalSessionId); 58 110 : } 59 : 60 272826 : const char * SecureSession::StateToString(State state) const 61 : { 62 272826 : switch (state) 63 : { 64 135044 : case State::kEstablishing: 65 135044 : return "kEstablishing"; 66 : break; 67 : 68 2846 : case State::kActive: 69 2846 : return "kActive"; 70 : break; 71 : 72 17 : case State::kDefunct: 73 17 : return "kDefunct"; 74 : break; 75 : 76 134919 : case State::kPendingEviction: 77 134919 : return "kPendingEviction"; 78 : break; 79 : 80 0 : default: 81 0 : return "???"; 82 : break; 83 : } 84 : } 85 : 86 136371 : void SecureSession::MoveToState(State targetState) 87 : { 88 136371 : if (mState != targetState) 89 : { 90 136371 : ChipLogProgress(SecureChannel, "SecureSession[%p, LSID:%d]: State change '%s' --> '%s'", this, mLocalSessionId, 91 : StateToString(mState), StateToString(targetState)); 92 136371 : mState = targetState; 93 : } 94 136371 : } 95 : 96 5 : void SecureSession::MarkAsDefunct() 97 : { 98 5 : ChipLogDetail(Inet, "SecureSession[%p]: MarkAsDefunct Type:%d LSID:%d", this, to_underlying(mSecureSessionType), 99 : mLocalSessionId); 100 5 : ReferenceCountedHandle<Transport::Session> ref(*this); 101 : 102 5 : switch (mState) 103 : { 104 0 : case State::kEstablishing: 105 : // 106 : // A session can only be marked as defunct from the state of Active. 107 : // 108 0 : VerifyOrDie(false); 109 : return; 110 : 111 4 : case State::kActive: 112 4 : MoveToState(State::kDefunct); 113 4 : return; 114 : 115 0 : case State::kDefunct: 116 : // 117 : // Do nothing 118 : // 119 0 : return; 120 : 121 1 : case State::kPendingEviction: 122 : // 123 : // Once a session is headed for eviction, we CANNOT bring it back to either being active or defunct. Let's just 124 : // do nothing and return. 125 : // 126 1 : return; 127 : } 128 5 : } 129 : 130 134919 : void SecureSession::MarkForEviction() 131 : { 132 134919 : ChipLogDetail(Inet, "SecureSession[%p]: MarkForEviction Type:%d LSID:%d", this, to_underlying(mSecureSessionType), 133 : mLocalSessionId); 134 134919 : ReferenceCountedHandle<Transport::Session> ref(*this); 135 : 136 134919 : switch (mState) 137 : { 138 133594 : case State::kEstablishing: 139 133594 : MoveToState(State::kPendingEviction); 140 : // Interrupt the pairing 141 133594 : NotifySessionReleased(); 142 133594 : return; 143 : 144 1325 : case State::kDefunct: 145 : FALLTHROUGH; 146 : case State::kActive: 147 1325 : Release(); // Decrease the ref which is retained at Activate 148 1325 : MoveToState(State::kPendingEviction); 149 1325 : NotifySessionReleased(); 150 1325 : return; 151 : 152 0 : case State::kPendingEviction: 153 : // Do nothing 154 0 : return; 155 : } 156 134919 : } 157 : 158 6682 : Access::SubjectDescriptor SecureSession::GetSubjectDescriptor() const 159 : { 160 6682 : Access::SubjectDescriptor subjectDescriptor; 161 6682 : if (IsOperationalNodeId(mPeerNodeId)) 162 : { 163 6682 : subjectDescriptor.authMode = Access::AuthMode::kCase; 164 6682 : subjectDescriptor.subject = mPeerNodeId; 165 6682 : subjectDescriptor.cats = mPeerCATs; 166 6682 : subjectDescriptor.fabricIndex = GetFabricIndex(); 167 : } 168 0 : else if (IsPAKEKeyId(mPeerNodeId)) 169 : { 170 : // Responder (aka commissionee) gets subject descriptor filled in. 171 : // Initiator (aka commissioner) leaves subject descriptor unfilled. 172 0 : if (GetCryptoContext().IsResponder()) 173 : { 174 0 : subjectDescriptor.authMode = Access::AuthMode::kPase; 175 0 : subjectDescriptor.subject = mPeerNodeId; 176 0 : subjectDescriptor.fabricIndex = GetFabricIndex(); 177 : } 178 : } 179 : else 180 : { 181 0 : VerifyOrDie(false); 182 : } 183 6682 : return subjectDescriptor; 184 : } 185 : 186 760644 : void SecureSession::Retain() 187 : { 188 : #if CHIP_CONFIG_SECURE_SESSION_REFCOUNT_LOGGING 189 : ChipLogProgress(SecureChannel, "SecureSession[%p]: ++ %d -> %d", this, GetReferenceCount(), GetReferenceCount() + 1); 190 : #endif 191 : 192 760644 : ReferenceCounted<SecureSession, SecureSessionDeleter, 0, uint16_t>::Retain(); 193 760644 : } 194 : 195 760521 : void SecureSession::Release() 196 : { 197 : #if CHIP_CONFIG_SECURE_SESSION_REFCOUNT_LOGGING 198 : ChipLogProgress(SecureChannel, "SecureSession[%p]: -- %d -> %d", this, GetReferenceCount(), GetReferenceCount() - 1); 199 : #endif 200 : 201 760521 : ReferenceCounted<SecureSession, SecureSessionDeleter, 0, uint16_t>::Release(); 202 760521 : } 203 : 204 54 : void SecureSession::NewerSessionAvailable(const SessionHandle & session) 205 : { 206 : // Shift to the new session, checks are performed by the the caller SecureSessionTable::NewerSessionAvailable. 207 54 : IntrusiveList<SessionHolder>::Iterator iter = mHolders.begin(); 208 100 : while (iter != mHolders.end()) 209 : { 210 : // The iterator can be invalid once the session holder is migrated to another session. So we store its next value before 211 : // notifying the holder. 212 46 : IntrusiveList<SessionHolder>::Iterator next = iter; 213 46 : ++next; 214 : 215 46 : iter->ShiftToSession(session); 216 : 217 46 : iter = next; 218 : } 219 54 : } 220 : 221 : } // namespace Transport 222 : } // namespace chip