1 /*
2  * Copyright (C) 2024 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.bluetooth.pbap;
18 
19 import android.bluetooth.BluetoothProfile;
20 import android.bluetooth.BluetoothProtoEnums;
21 import android.util.Log;
22 
23 import com.android.bluetooth.BluetoothStatsLog;
24 import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils;
25 import com.android.internal.annotations.VisibleForTesting;
26 import com.android.obex.Authenticator;
27 import com.android.obex.PasswordAuthentication;
28 
29 /**
30  * BluetoothPbapAuthenticator is a used by BluetoothObexServer for obex authentication procedure.
31  */
32 // Next tag value for ContentProfileErrorReportUtils.report(): 1
33 public class BluetoothPbapAuthenticator implements Authenticator {
34     private static final String TAG = "PbapAuthenticator";
35 
36     @VisibleForTesting boolean mChallenged;
37     @VisibleForTesting boolean mAuthCancelled;
38     @VisibleForTesting String mSessionKey;
39     @VisibleForTesting PbapStateMachine mPbapStateMachine;
40 
BluetoothPbapAuthenticator(final PbapStateMachine stateMachine)41     BluetoothPbapAuthenticator(final PbapStateMachine stateMachine) {
42         mPbapStateMachine = stateMachine;
43         mChallenged = false;
44         mAuthCancelled = false;
45         mSessionKey = null;
46     }
47 
setChallenged(final boolean bool)48     final synchronized void setChallenged(final boolean bool) {
49         mChallenged = bool;
50         notify();
51     }
52 
setCancelled(final boolean bool)53     final synchronized void setCancelled(final boolean bool) {
54         mAuthCancelled = bool;
55         notify();
56     }
57 
setSessionKey(final String string)58     final synchronized void setSessionKey(final String string) {
59         mSessionKey = string;
60     }
61 
waitUserConfirmation()62     private void waitUserConfirmation() {
63         mPbapStateMachine.sendMessage(PbapStateMachine.CREATE_NOTIFICATION);
64         mPbapStateMachine.sendMessageDelayed(
65                 PbapStateMachine.REMOVE_NOTIFICATION,
66                 BluetoothPbapService.USER_CONFIRM_TIMEOUT_VALUE);
67         synchronized (this) {
68             while (!mChallenged && !mAuthCancelled) {
69                 try {
70                     wait();
71                 } catch (InterruptedException e) {
72                     ContentProfileErrorReportUtils.report(
73                             BluetoothProfile.PBAP,
74                             BluetoothProtoEnums.BLUETOOTH_PBAP_AUTHENTICATOR,
75                             BluetoothStatsLog
76                                     .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION,
77                             0);
78                     Log.e(TAG, "Interrupted while waiting on isChallenged or AuthCancelled");
79                 }
80             }
81         }
82     }
83 
84     @Override
onAuthenticationChallenge( final String description, final boolean isUserIdRequired, final boolean isFullAccess)85     public PasswordAuthentication onAuthenticationChallenge(
86             final String description, final boolean isUserIdRequired, final boolean isFullAccess) {
87         waitUserConfirmation();
88         if (mSessionKey.trim().length() != 0) {
89             return new PasswordAuthentication(null, mSessionKey.getBytes());
90         }
91         return null;
92     }
93 
94     // TODO: Reserved for future use only, in case PSE challenge PCE
95     @Override
onAuthenticationResponse(final byte[] userName)96     public byte[] onAuthenticationResponse(final byte[] userName) {
97         byte[] b = null;
98         return b;
99     }
100 }
101