1 /*
2  * Copyright (C) 2022 The Android Open Source Project
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 package com.android.server.uwb.secure;
18 
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.util.Log;
22 
23 import androidx.annotation.NonNull;
24 
25 import com.android.server.uwb.pm.RunningProfileSessionInfo;
26 import com.android.server.uwb.secure.csml.CsmlUtil;
27 import com.android.server.uwb.secure.csml.DispatchResponse;
28 import com.android.server.uwb.secure.csml.SessionData;
29 
30 import java.util.Optional;
31 
32 /**
33  * Interface for a Dynamic STS session, which set up secure channel and exchange
34  * the UWB parameters.
35  */
36 public abstract class SecureSession {
37     private static final String LOG_TAG = "SecureSession";
38 
39     protected final Handler mWorkHandler;
40     protected final FiRaSecureChannel mFiRaSecureChannel;
41     protected final Callback mSessionCallback;
42     protected final RunningProfileSessionInfo mRunningProfileSessionInfo;
43 
44     // it could be sessionId for unicast session or subSessionId for multicast session.
45     protected Optional<Integer> mUniqueSessionId = Optional.empty();
46     // default session id/sub session id is derived in FiRa applet.
47     protected boolean mIsDefaultUniqueSessionId = false;
48     // session data is used by both controller and controlee finally.
49     protected SessionData mSessionData;
50 
51     protected boolean mIsController = false;
52 
53     private final FiRaSecureChannel.SecureChannelCallback mSecureChannelCallback =
54             new FiRaSecureChannel.SecureChannelCallback() {
55                 @Override
56                 public void onEstablished(Optional<Integer> defaultUniqueSessionId) {
57                     if (defaultUniqueSessionId.isPresent()) {
58                         mUniqueSessionId = defaultUniqueSessionId;
59                         mIsDefaultUniqueSessionId = true;
60                     } else if (mIsController) {
61                         mUniqueSessionId = Optional.of(CsmlUtil.generateRandomSessionId());
62                     }
63                     handleFiRaSecureChannelEstablished();
64                 }
65 
66                 @Override
67                 public void onSetUpError(FiRaSecureChannel.SetupError error) {
68                     logw("secure channel set up error: " + error);
69                     mFiRaSecureChannel.cleanUpTerminatedOrAbortedSession();
70                     mSessionCallback.onSessionAborted();
71                 }
72 
73                 @Override
74                 public void onDispatchResponseAvailable(DispatchResponse dispatchResponse) {
75                     handleDispatchResponse(dispatchResponse);
76                 }
77 
78                 @Override
79                 public void onDispatchCommandFailure() {
80                     handleDispatchCommandFailure();
81                 }
82 
83                 @Override
84                 public void onTerminated(boolean withError) {
85                     logd("session is terminated with error: " + withError);
86                     mSessionCallback.onSessionTerminated();
87                 }
88 
89                 @Override
90                 public void onSeChannelClosed(boolean withError) {
91                     // TODO: no action, may be removed.
92                 }
93 
94                 @Override
95                 public void onRdsAvailableAndTerminated(int sessionId) {
96                     mUniqueSessionId = Optional.of(sessionId);
97                     mSessionCallback.onSessionDataReady(
98                             sessionId, Optional.empty(), /*isSessionTerminated=*/ true);
99                 }
100             };
101 
SecureSession( @onNull Looper workLooper, @NonNull FiRaSecureChannel fiRaSecureChannel, @NonNull Callback sessionCallback, @NonNull RunningProfileSessionInfo runningProfileSessionInfo)102     SecureSession(
103             @NonNull Looper workLooper,
104             @NonNull FiRaSecureChannel fiRaSecureChannel,
105             @NonNull Callback sessionCallback,
106             @NonNull RunningProfileSessionInfo runningProfileSessionInfo) {
107         mWorkHandler = new Handler(workLooper);
108         mFiRaSecureChannel = fiRaSecureChannel;
109         mSessionCallback = sessionCallback;
110         mRunningProfileSessionInfo = runningProfileSessionInfo;
111     }
112 
handleDispatchCommandFailure()113     protected abstract void handleDispatchCommandFailure();
114 
handleDispatchResponse(@onNull DispatchResponse dispatchResponse)115     protected abstract void handleDispatchResponse(@NonNull DispatchResponse dispatchResponse);
116 
handleFiRaSecureChannelEstablished()117     protected abstract void handleFiRaSecureChannelEstablished();
118 
119     /**
120      * Start the dynamic STS secure session set up.
121      */
startSession()122     public final void startSession() {
123         mFiRaSecureChannel.init(mSecureChannelCallback);
124     }
125 
126     /**
127      * Terminate the dynamic STS secure session.
128      */
terminateSession()129     public abstract void terminateSession();
130 
131     /**
132      * Callback to get the secure session information.
133      */
134     public interface Callback {
135         /**
136          * The session data is ready, the UWB configuration of Controller can be sent to UWBS.
137          *
138          * @param sessionData         empty if the session is terminated automatically, profile/app
139          *                            defined the session data in advance.
140          * @param isSessionTerminated If the session is terminated, the client shouldn't use
141          *                            the session further.
142          */
onSessionDataReady( int updatedSessionId, Optional<SessionData> sessionData, boolean isSessionTerminated)143         void onSessionDataReady(
144                 int updatedSessionId,
145                 Optional<SessionData> sessionData,
146                 boolean isSessionTerminated);
147 
148         /**
149          * Something wrong, the session is aborted.
150          */
onSessionAborted()151         void onSessionAborted();
152 
153         /**
154          * Session is terminated as responding to the calling of {@code #terminateSession}.
155          */
onSessionTerminated()156         void onSessionTerminated();
157     }
158 
logd(@onNull String dbgMsg)159     private void logd(@NonNull String dbgMsg) {
160         Log.d(LOG_TAG, dbgMsg);
161     }
162 
logw(@onNull String dbgMsg)163     private void logw(@NonNull String dbgMsg) {
164         Log.w(LOG_TAG, dbgMsg);
165     }
166 }
167