1/*
2 * Copyright (C) 2017 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 */
16package com.android.car.trust;
17
18import android.bluetooth.BluetoothDevice;
19import android.bluetooth.BluetoothGattCharacteristic;
20import android.bluetooth.BluetoothGattService;
21import android.content.Intent;
22import android.os.Binder;
23import android.os.IBinder;
24import android.os.ParcelUuid;
25import android.util.Log;
26import com.android.car.trust.comms.SimpleBleServer;
27
28import java.util.HashSet;
29import java.util.UUID;
30
31/**
32 * A service that receives escrow token enrollment requests from remote devices.
33 */
34public class CarEnrolmentService extends SimpleBleServer {
35    private static final String TAG = "CarEnrolmentService";
36
37    public interface EnrolmentCallback {
38        void onEnrolmentDataReceived(byte[] token);
39    }
40
41    private BluetoothGattService mEnrolmentService;
42    private BluetoothGattCharacteristic mEnrolmentEscrowToken;
43    private BluetoothGattCharacteristic mEnrolmentTokenHandle;
44
45    private HashSet<EnrolmentCallback> mCallbacks;
46
47    private final IBinder mBinder = new EnrolmentServiceBinder();
48
49    @Override
50    public void onCreate() {
51        super.onCreate();
52        mCallbacks = new HashSet<>();
53        setupEnrolmentService();
54    }
55
56    public void start() {
57        ParcelUuid uuid = new ParcelUuid(
58                UUID.fromString(getString(R.string.enrollment_service_uuid)));
59        start(uuid, mEnrolmentService);
60    }
61
62    @Override
63    public IBinder onBind(Intent intent) {
64        return mBinder;
65    }
66
67    @Override
68    public void onCharacteristicWrite(BluetoothDevice device,
69            int requestId, BluetoothGattCharacteristic characteristic,
70            boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
71        if (characteristic.getUuid().equals(mEnrolmentEscrowToken.getUuid())) {
72            if (Log.isLoggable(TAG, Log.DEBUG)) {
73                Log.d(TAG, "Enrolment token received, value: " + Utils.getLong(value));
74            }
75
76            for (EnrolmentCallback callback : mCallbacks) {
77                callback.onEnrolmentDataReceived(value);
78            }
79        }
80    }
81
82    @Override
83    public void onCharacteristicRead(BluetoothDevice device,
84            int requestId, int offset, BluetoothGattCharacteristic characteristic) {
85        //Enrolment service should not have any read requests.
86    }
87
88    public void addEnrolmentCallback(EnrolmentCallback callback) {
89        mCallbacks.add(callback);
90    }
91
92    public void sendHandle(long handle, BluetoothDevice device) {
93        mEnrolmentTokenHandle.setValue(Utils.getBytes(handle));
94
95        if (Log.isLoggable(TAG, Log.DEBUG)) {
96            Log.d(TAG, "Sending notification for EscrowToken Handle");
97        }
98        mGattServer.notifyCharacteristicChanged(device,
99                mEnrolmentTokenHandle, false /* confirm */);
100    }
101
102    public class EnrolmentServiceBinder extends Binder {
103        public CarEnrolmentService getService() {
104            return CarEnrolmentService.this;
105        }
106    }
107
108    // Create services and characteristics for enrolling new unlocking escrow tokens
109    private void setupEnrolmentService() {
110        mEnrolmentService = new BluetoothGattService(
111                UUID.fromString(getString(R.string.enrollment_service_uuid)),
112                BluetoothGattService.SERVICE_TYPE_PRIMARY);
113
114        // Characteristic to describe the escrow token being used for unlock
115        mEnrolmentEscrowToken = new BluetoothGattCharacteristic(
116                UUID.fromString(getString(R.string.enrollment_token_uuid)),
117                BluetoothGattCharacteristic.PROPERTY_WRITE,
118                BluetoothGattCharacteristic.PERMISSION_WRITE);
119
120        // Characteristic to describe the handle being used for this escrow token
121        mEnrolmentTokenHandle = new BluetoothGattCharacteristic(
122                UUID.fromString(getString(R.string.enrollment_handle_uuid)),
123                BluetoothGattCharacteristic.PROPERTY_NOTIFY,
124                BluetoothGattCharacteristic.PERMISSION_READ);
125
126        mEnrolmentService.addCharacteristic(mEnrolmentEscrowToken);
127        mEnrolmentService.addCharacteristic(mEnrolmentTokenHandle);
128    }
129}
130