blob: 4f1df7268856d408d60d27286b6f9d8634d1b6df [file] [log] [blame]
Android Auto Companiona7288fb2021-06-09 12:52:29 -07001/*
2 * Copyright (C) 2021 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.google.android.connecteddevice.connection
17
Android Auto Companion179c3e32021-06-23 09:04:17 -070018import android.content.Context
Android Auto Companion16c608d2022-02-02 10:13:13 -080019import android.os.ParcelUuid
Android Auto Companion179c3e32021-06-23 09:04:17 -070020import android.util.Base64
Android Auto Companione1421e92021-07-21 10:33:24 -070021import androidx.room.Room
Android Auto Companion179c3e32021-06-23 09:04:17 -070022import androidx.test.core.app.ApplicationProvider
Android Auto Companiona7288fb2021-06-09 12:52:29 -070023import androidx.test.ext.junit.runners.AndroidJUnit4
Android Auto Companion16c608d2022-02-02 10:13:13 -080024import com.google.android.companionprotos.VerificationCode
25import com.google.android.companionprotos.VerificationCodeState
Android Auto Companiona7288fb2021-06-09 12:52:29 -070026import com.google.android.connecteddevice.connection.MultiProtocolSecureChannel.ChannelError
27import com.google.android.connecteddevice.connection.MultiProtocolSecureChannel.MessageError
Android Auto Companion179c3e32021-06-23 09:04:17 -070028import com.google.android.connecteddevice.connection.MultiProtocolSecureChannel.ShowVerificationCodeListener
Android Auto Companiona7288fb2021-06-09 12:52:29 -070029import com.google.android.connecteddevice.model.DeviceMessage
30import com.google.android.connecteddevice.model.DeviceMessage.OperationType
Android Auto Companion9a35cab2021-10-13 10:00:56 -070031import com.google.android.connecteddevice.oob.OobRunner
Android Auto Companion179c3e32021-06-23 09:04:17 -070032import com.google.android.connecteddevice.storage.ConnectedDeviceDatabase
33import com.google.android.connecteddevice.storage.ConnectedDeviceStorage
34import com.google.android.connecteddevice.storage.CryptoHelper
Android Auto Companion16c608d2022-02-02 10:13:13 -080035import com.google.android.connecteddevice.transport.ConnectChallenge
Android Auto Companiona7288fb2021-06-09 12:52:29 -070036import com.google.android.connecteddevice.transport.ConnectionProtocol
Android Auto Companion16c608d2022-02-02 10:13:13 -080037import com.google.android.connecteddevice.transport.IDataSendCallback
38import com.google.android.connecteddevice.transport.IDiscoveryCallback
Android Auto Companione1421e92021-07-21 10:33:24 -070039import com.google.android.connecteddevice.transport.ProtocolDevice
Android Auto Companiona7288fb2021-06-09 12:52:29 -070040import com.google.android.connecteddevice.util.ByteUtils
41import com.google.android.encryptionrunner.EncryptionRunnerFactory
Android Auto Companion179c3e32021-06-23 09:04:17 -070042import com.google.android.encryptionrunner.FakeEncryptionRunner
Android Auto Companiona7288fb2021-06-09 12:52:29 -070043import com.google.android.encryptionrunner.HandshakeException
Android Auto Companiona7288fb2021-06-09 12:52:29 -070044import com.google.common.truth.Truth.assertThat
45import com.google.common.util.concurrent.MoreExecutors.directExecutor
Android Auto Companion16c608d2022-02-02 10:13:13 -080046import com.google.protobuf.ByteString
Android Auto Companiona7288fb2021-06-09 12:52:29 -070047import com.nhaarman.mockitokotlin2.any
48import com.nhaarman.mockitokotlin2.argumentCaptor
Android Auto Companion179c3e32021-06-23 09:04:17 -070049import com.nhaarman.mockitokotlin2.eq
Android Auto Companiona7288fb2021-06-09 12:52:29 -070050import com.nhaarman.mockitokotlin2.mock
51import com.nhaarman.mockitokotlin2.never
52import com.nhaarman.mockitokotlin2.spy
Android Auto Companion9a35cab2021-10-13 10:00:56 -070053import com.nhaarman.mockitokotlin2.times
Android Auto Companiona7288fb2021-06-09 12:52:29 -070054import com.nhaarman.mockitokotlin2.verify
55import com.nhaarman.mockitokotlin2.whenever
56import java.security.SignatureException
57import java.util.UUID
58import java.util.zip.DataFormatException
59import java.util.zip.Inflater
60import org.junit.Assert.fail
61import org.junit.Before
62import org.junit.Test
63import org.junit.runner.RunWith
64
Android Auto Companion179c3e32021-06-23 09:04:17 -070065private const val PROTOCOL_ID_1 = "testProtocol1"
Android Auto Companion9a35cab2021-10-13 10:00:56 -070066private const val PROTOCOL_ID_2 = "testProtocol2"
Android Auto Companion179c3e32021-06-23 09:04:17 -070067private val SERVER_DEVICE_ID = UUID.fromString("a29f0c74-2014-4b14-ac02-be6ed15b545a")
Android Auto Companiona7288fb2021-06-09 12:52:29 -070068
69@RunWith(AndroidJUnit4::class)
70class MultiProtocolSecureChannelTest {
Android Auto Companion179c3e32021-06-23 09:04:17 -070071 private val context = ApplicationProvider.getApplicationContext<Context>()
Android Auto Companion16c608d2022-02-02 10:13:13 -080072 private val stream1 = spy(ProtocolStream(ProtocolDevice(TestProtocol(), PROTOCOL_ID_1)))
73 private val stream2 = spy(ProtocolStream(ProtocolDevice(TestProtocol(), PROTOCOL_ID_2)))
Android Auto Companiona7288fb2021-06-09 12:52:29 -070074 private val mockInflater: Inflater = mock()
75 private val mockCallback: MultiProtocolSecureChannel.Callback = mock()
Android Auto Companion9a35cab2021-10-13 10:00:56 -070076 private val mockOobRunner: OobRunner = mock()
Android Auto Companiona7288fb2021-06-09 12:52:29 -070077
Android Auto Companiona7288fb2021-06-09 12:52:29 -070078 private lateinit var secureChannel: MultiProtocolSecureChannel
Android Auto Companion179c3e32021-06-23 09:04:17 -070079 private lateinit var spyStorage: ConnectedDeviceStorage
80 private val mockShowVerificationCodeListener: ShowVerificationCodeListener = mock()
Android Auto Companiona7288fb2021-06-09 12:52:29 -070081
82 @Before
83 @Throws(SignatureException::class)
84 fun setUp() {
Android Auto Companion179c3e32021-06-23 09:04:17 -070085 val database =
86 Room.inMemoryDatabaseBuilder(context, ConnectedDeviceDatabase::class.java)
87 .allowMainThreadQueries()
88 .setQueryExecutor(directExecutor())
89 .build()
90 .associatedDeviceDao()
Android Auto Companiona34dde22021-12-08 09:12:15 -080091 spyStorage =
92 spy(ConnectedDeviceStorage(context, Base64CryptoHelper(), database, directExecutor()))
Android Auto Companion179c3e32021-06-23 09:04:17 -070093 whenever(spyStorage.uniqueId).thenReturn(SERVER_DEVICE_ID)
Android Auto Companiona7288fb2021-06-09 12:52:29 -070094 }
95
96 @Test
97 @Throws(SignatureException::class)
98 fun decryptMessage_doesNothingForUnencryptedMessage() {
Android Auto Companion179c3e32021-06-23 09:04:17 -070099 val testPayload = ByteUtils.randomBytes(10)
100 completeHandshakeAndSaveTheKey()
101
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700102 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700103 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700104 UUID.randomUUID(),
105 /* isMessageEncrypted= */ false,
106 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700107 testPayload
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700108 )
109 secureChannel.decryptMessage(message)
Android Auto Companion179c3e32021-06-23 09:04:17 -0700110 assertThat(message.message).isEqualTo(testPayload)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700111 }
112
113 @Test
114 @Throws(SignatureException::class)
115 fun decryptMessage_decryptsEncryptedMessage() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700116 completeHandshakeAndSaveTheKey()
117
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700118 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700119 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700120 UUID.randomUUID(),
121 /* isMessageEncrypted= */ true,
122 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700123 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700124 )
Android Auto Companion179c3e32021-06-23 09:04:17 -0700125 assertThat(secureChannel.decryptMessage(message)).isTrue()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700126 }
127
128 @Test
129 @Throws(InterruptedException::class)
130 fun decryptMessage_onMessageReceivedErrorForEncryptedMessageWithNoKey() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700131 setupSecureChannel(true)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700132 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700133 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700134 UUID.randomUUID(),
135 /* isMessageEncrypted= */ true,
136 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700137 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700138 )
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700139 assertThat(secureChannel.decryptMessage(message)).isFalse()
140 verify(mockCallback).onMessageReceivedError(MessageError.MESSAGE_ERROR_DECRYPTION_FAILURE)
141 assertThat(message.message).isEmpty()
142 }
143
144 @Test
145 fun onDeviceMessageReceived_onEstablishSecureChannelFailureBadHandshakeMessage() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700146 setupSecureChannel(true)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700147 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700148 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700149 UUID.randomUUID(),
150 /* isMessageEncrypted= */ true,
151 OperationType.ENCRYPTION_HANDSHAKE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700152 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700153 )
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700154 secureChannel.onDeviceMessageReceived(message)
155 verify(mockCallback).onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_MSG)
156 }
157
158 @Test
159 fun onDeviceMessageReceived_onMessageReceivedNotIssuedForEmptyMessage() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700160 completeHandshakeAndSaveTheKey()
161
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700162 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700163 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700164 UUID.randomUUID(),
165 /* isMessageEncrypted= */ false,
166 OperationType.CLIENT_MESSAGE,
167 /* message= */ byteArrayOf()
168 )
169 secureChannel.onDeviceMessageReceived(message)
170 verify(mockCallback, never()).onMessageReceived(any())
171 }
172
173 @Test
174 fun onDeviceMessageReceived_processHandshakeExceptionIssuesSecureChannelFailureCallback() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700175 setupSecureChannel(true)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700176 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700177 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700178 UUID.randomUUID(),
179 /* isMessageEncrypted= */ false,
180 OperationType.ENCRYPTION_HANDSHAKE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700181 FakeEncryptionRunner.INIT_MESSAGE
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700182 )
Android Auto Companion179c3e32021-06-23 09:04:17 -0700183
184 whenever(secureChannel.processHandshake(message.message)).then {
185 throw HandshakeException("test")
186 }
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700187 secureChannel.onDeviceMessageReceived(message)
188 verify(mockCallback)
189 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_HANDSHAKE)
190 }
191
192 @Test
193 fun onDeviceMessageReceived_processClientMessageIssuesMessageReceivedErrorCallback() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700194 setupSecureChannel(true)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700195 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700196 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700197 UUID.randomUUID(),
198 /* isMessageEncrypted= */ true,
199 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700200 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700201 )
202 secureChannel.onDeviceMessageReceived(message)
203 verify(mockCallback).onMessageReceivedError(MessageError.MESSAGE_ERROR_DECRYPTION_FAILURE)
204 }
205
206 @Test
Android Auto Companion16c608d2022-02-02 10:13:13 -0800207 fun onDeviceMessageReceived_noExceptionWhenReceivedUnknownMessageType() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700208 completeHandshakeAndSaveTheKey()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700209 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700210 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700211 UUID.randomUUID(),
212 /* isMessageEncrypted= */ true,
213 OperationType.UNKNOWN,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700214 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700215 )
216 try {
217 secureChannel.onDeviceMessageReceived(message)
218 } catch (e: Exception) {
219 fail("Should not throw exception.")
220 }
221 }
222
223 @Test
Android Auto Companione1421e92021-07-21 10:33:24 -0700224 fun onDeviceMessageReceived_issueOnMessageReceivedWhenHandshakeFinished() {
225 completeHandshakeAndSaveTheKey()
226 val message =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700227 DeviceMessage.createOutgoingMessage(
Android Auto Companione1421e92021-07-21 10:33:24 -0700228 UUID.randomUUID(),
229 /* isMessageEncrypted= */ true,
230 OperationType.ENCRYPTION_HANDSHAKE,
231 ByteUtils.randomBytes(10)
232 )
233 secureChannel.onDeviceMessageReceived(message)
234 verify(mockCallback).onMessageReceived(message)
235 }
236
237 @Test
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700238 fun decompressMessage_returnsOriginalMessageIfOriginalSizeIsZero() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700239 val testPayload = ByteUtils.randomBytes(10)
240 completeHandshakeAndSaveTheKey()
241
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700242 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700243 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700244 UUID.randomUUID(),
245 /* isMessageEncrypted= */ false,
246 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700247 testPayload
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700248 )
249 deviceMessage.originalMessageSize = 0
250 assertThat(secureChannel.decompressMessage(deviceMessage)).isTrue()
Android Auto Companion179c3e32021-06-23 09:04:17 -0700251 assertThat(deviceMessage.message).isEqualTo(testPayload)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700252 }
253
254 @Test
Android Auto Companion16c608d2022-02-02 10:13:13 -0800255 fun decompressMessage_returnsFalseWhenThereAreDataFormatException() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700256 completeHandshakeAndSaveTheKey()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700257 whenever(mockInflater.inflate(any())).then { throw DataFormatException() }
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700258 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700259 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700260 UUID.randomUUID(),
261 /* isMessageEncrypted= */ false,
262 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700263 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700264 )
265 secureChannel.callback = mockCallback
266 deviceMessage.originalMessageSize = 1
267 assertThat(secureChannel.decompressMessage(deviceMessage)).isFalse()
268 verify(mockCallback).onMessageReceivedError(MessageError.MESSAGE_ERROR_DECOMPRESSION_FAILURE)
269 }
270
271 @Test
272 fun compressMessage_returnsCompressedMessageWithOriginalSize() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700273 completeHandshakeAndSaveTheKey()
274
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700275 val message = ByteArray(100)
276 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700277 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700278 UUID.randomUUID(),
279 /* isMessageEncrypted= */ false,
280 OperationType.CLIENT_MESSAGE,
281 message
282 )
283 secureChannel.compressMessage(deviceMessage)
284 assertThat(deviceMessage.message).isNotEqualTo(message)
285 assertThat(deviceMessage.originalMessageSize).isEqualTo(message.size)
286 }
287
288 @Test
289 fun compressedMessageCanBeDecompressed() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700290 completeHandshakeAndSaveTheKey()
291
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700292 val message = ByteArray(100)
293 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700294 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700295 UUID.randomUUID(),
296 /* isMessageEncrypted= */ false,
297 OperationType.CLIENT_MESSAGE,
298 message
299 )
300 secureChannel.compressMessage(deviceMessage)
301 assertThat(secureChannel.decompressMessage(deviceMessage)).isTrue()
Android Auto Companione1421e92021-07-21 10:33:24 -0700302 assertThat(deviceMessage.message).isEqualTo(message)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700303 }
304
305 @Test
306 fun addStream_notifyCallbackWhenMessageReceived() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700307 completeHandshakeAndSaveTheKey()
308
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700309 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700310 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700311 UUID.randomUUID(),
312 /* isMessageEncrypted= */ true,
313 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700314 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700315 )
Android Auto Companion179c3e32021-06-23 09:04:17 -0700316 secureChannel.addStream(stream2)
317 assertThat(stream2.messageReceivedListener).isNotNull()
318 stream2.messageReceivedListener!!.onMessageReceived(deviceMessage)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700319 verify(mockCallback).onMessageReceived(any())
320 }
321
322 @Test
323 fun addStream_notifyCallbackWhenProtocolDisconnected() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700324 setupSecureChannel(true)
325
326 assertThat(stream1.protocolDisconnectListener).isNotNull()
327 stream1.protocolDisconnectListener!!.onProtocolDisconnected()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700328 verify(mockCallback)
329 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_DEVICE_DISCONNECTED)
330 }
331
332 @Test
333 fun addStream_doNotNotifyCallbackWhenProtocolDisconnected() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700334 setupSecureChannel(true)
335 secureChannel.addStream(stream2)
336 assertThat(stream2.protocolDisconnectListener).isNotNull()
337 stream2.protocolDisconnectListener!!.onProtocolDisconnected()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700338 verify(mockCallback, never())
339 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_DEVICE_DISCONNECTED)
340 }
341
342 @Test
343 fun sendClientMessage_FailedToSendMessageWithNullKey() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700344 setupSecureChannel(true)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700345 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700346 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700347 UUID.randomUUID(),
348 /* isMessageEncrypted= */ true,
349 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700350 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700351 )
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700352
353 assertThat(secureChannel.sendClientMessage(deviceMessage)).isFalse()
354 }
355
356 @Test
357 fun sendClientMessage_FailedToSendMessageWithEmptyStream() {
358 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700359 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700360 UUID.randomUUID(),
361 /* isMessageEncrypted= */ true,
362 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700363 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700364 )
Android Auto Companion179c3e32021-06-23 09:04:17 -0700365 completeHandshakeAndSaveTheKey()
366
367 stream1.protocolDisconnectListener!!.onProtocolDisconnected()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700368 assertThat(secureChannel.sendClientMessage(deviceMessage)).isFalse()
369 }
370
371 @Test
Android Auto Companione1421e92021-07-21 10:33:24 -0700372 fun sendClientMessage_successfullySendMessage() {
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700373 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700374 DeviceMessage.createOutgoingMessage(
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700375 UUID.randomUUID(),
376 /* isMessageEncrypted= */ true,
377 OperationType.CLIENT_MESSAGE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700378 ByteUtils.randomBytes(10)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700379 )
Android Auto Companion179c3e32021-06-23 09:04:17 -0700380
381 completeHandshakeAndSaveTheKey()
382
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700383 assertThat(secureChannel.sendClientMessage(deviceMessage)).isTrue()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700384 }
385
386 @Test
Android Auto Companione1421e92021-07-21 10:33:24 -0700387 fun sendClientMessage_successfullyEncryptAndSetMessage() {
388 val testPayload = ByteUtils.randomBytes(10)
389 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700390 DeviceMessage.createOutgoingMessage(
Android Auto Companione1421e92021-07-21 10:33:24 -0700391 UUID.randomUUID(),
392 /* isMessageEncrypted= */ true,
393 OperationType.CLIENT_MESSAGE,
394 testPayload
395 )
396
397 completeHandshakeAndSaveTheKey()
398 secureChannel.sendClientMessage(deviceMessage)
399
400 assertThat(deviceMessage.message).isNotEqualTo(testPayload)
401 }
402
403 @Test
Android Auto Companion179c3e32021-06-23 09:04:17 -0700404 fun association_secureChannelEstablishedSuccessfully() {
405 val clientId = UUID.randomUUID()
406 setupSecureChannel(false)
407 secureChannel.showVerificationCodeListener = mockShowVerificationCodeListener
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700408 argumentCaptor<DeviceMessage>().apply {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700409 initHandshakeMessage()
410 verify(stream1).sendMessage(capture())
Android Auto Companione1421e92021-07-21 10:33:24 -0700411 val response = firstValue.message
Android Auto Companion179c3e32021-06-23 09:04:17 -0700412 assertThat(response).isEqualTo(FakeEncryptionRunner.INIT_RESPONSE)
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700413 }
Android Auto Companion179c3e32021-06-23 09:04:17 -0700414 respondToContinueMessage()
Android Auto Companion16c608d2022-02-02 10:13:13 -0800415 val testVerificationCodeMessage =
416 VerificationCode.newBuilder().setState(VerificationCodeState.VISUAL_VERIFICATION).build()
417 val deviceMessage =
418 DeviceMessage.createOutgoingMessage(
419 /* recipient= */ null,
420 /* isMessageEncrypted= */ false,
421 OperationType.ENCRYPTION_HANDSHAKE,
422 testVerificationCodeMessage.toByteArray()
423 )
424 secureChannel.onDeviceMessageReceived(deviceMessage)
425
Android Auto Companion179c3e32021-06-23 09:04:17 -0700426 verify(mockShowVerificationCodeListener).showVerificationCode(any())
427
428 secureChannel.notifyVerificationCodeAccepted()
Android Auto Companione1421e92021-07-21 10:33:24 -0700429 secureChannel.setDeviceIdDuringAssociation(clientId)
Android Auto Companion179c3e32021-06-23 09:04:17 -0700430 verify(spyStorage).saveEncryptionKey(eq(clientId.toString()), any())
431 verify(mockCallback).onSecureChannelEstablished()
432 }
433
434 @Test
435 fun association_wrongInitHandshakeMessage_issueInvalidHandshakeError() {
436 setupSecureChannel(false)
437
438 // Wrong init handshake message
439 respondToContinueMessage()
440 verify(mockCallback)
441 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_HANDSHAKE)
442 }
443
444 @Test
445 @Throws(InterruptedException::class)
446 fun association_wrongRespondToContinueMessage_issueInvalidHandshakeError() {
447 setupSecureChannel(false)
448 initHandshakeMessage()
449
450 // Wrong respond to continue message
451 initHandshakeMessage()
452 verify(mockCallback)
453 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_HANDSHAKE)
454 }
455
456 @Test
457 fun reconnect_secureChannelEstablishedSuccessfully() {
458 val clientId = UUID.randomUUID()
459 whenever(spyStorage.getEncryptionKey(clientId.toString())).thenReturn(byteArrayOf())
460 setupSecureChannel(true, clientId.toString())
461 initHandshakeMessage()
462 respondToContinueMessage()
463 respondToResumeMessage()
464
465 verify(spyStorage).saveEncryptionKey(eq(clientId.toString()), any())
466 verify(mockCallback).onSecureChannelEstablished()
467 }
468
469 @Test
470 fun reconnect_deviceIdNotSet_issueInvalidStateError() {
471 setupSecureChannel(true)
472
473 initHandshakeMessage()
474 respondToContinueMessage()
475 respondToResumeMessage()
476
477 verify(mockCallback).onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_STATE)
478 }
479
480 @Test
481 fun reconnect_keyNotSet_issueInvalidKeyError() {
482 setupSecureChannel(true, UUID.randomUUID().toString())
483 initHandshakeMessage()
484 respondToContinueMessage()
485 respondToResumeMessage()
486
487 verify(mockCallback)
488 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_ENCRYPTION_KEY)
489 }
490
491 @Test
492 fun processHandshakeResumingSession_incorrectHandshakeState_issueInvalidStateError() {
493 val clientId = UUID.randomUUID().toString()
494 setupSecureChannel(true, clientId)
495 whenever(spyStorage.getEncryptionKey(clientId)).thenReturn(byteArrayOf())
496 initHandshakeMessage()
497 respondToContinueMessage()
498 respondToResumeMessage(FakeEncryptionRunner.RECONNECTION_MESSAGE_STATE_ERROR)
499
500 verify(mockCallback).onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_STATE)
501 }
502
503 @Test
504 fun processHandshakeResumingSession_emptyNewKey_issueInvalidKeyError() {
505 val clientId = UUID.randomUUID().toString()
506 setupSecureChannel(true, clientId)
507 whenever(spyStorage.getEncryptionKey(clientId)).thenReturn(byteArrayOf())
508 initHandshakeMessage()
509 respondToContinueMessage()
510 respondToResumeMessage(FakeEncryptionRunner.RECONNECTION_MESSAGE_KEY_ERROR)
511
512 verify(mockCallback)
513 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_ENCRYPTION_KEY)
514 }
515
516 @Test
517 fun processHandshakeResumingSession_emptyNextMessage_issueInvalidMessageError() {
518 val clientId = UUID.randomUUID().toString()
519 setupSecureChannel(true, clientId)
520 whenever(spyStorage.getEncryptionKey(clientId)).thenReturn(byteArrayOf())
521 initHandshakeMessage()
522 respondToContinueMessage()
523 respondToResumeMessage(FakeEncryptionRunner.RECONNECTION_MESSAGE_EMPTY_RESPONSE)
524
525 verify(mockCallback).onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_MSG)
526 }
527
528 @Test
529 fun processHandshake_invalidState_issueInvalidStateError() {
530 setupSecureChannel(false)
531 secureChannel.showVerificationCodeListener = mockShowVerificationCodeListener
532 initHandshakeMessage()
533 respondToContinueMessage()
534 secureChannel.processHandshake(byteArrayOf())
535
536 verify(mockCallback).onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_STATE)
537 }
538
539 @Test
540 fun processHandshake_receivedMessageAfterFinish_ignoreMessage() {
541 setupSecureChannel(false)
542 secureChannel.showVerificationCodeListener = mockShowVerificationCodeListener
543 initHandshakeMessage()
544 respondToContinueMessage()
545 secureChannel.notifyVerificationCodeAccepted()
546 secureChannel.processHandshake(byteArrayOf())
547
548 verify(mockCallback, never()).onEstablishSecureChannelFailure(any())
549 }
550
551 @Test
552 fun processHandshakeInitialization_nextMessageIsNull_issueInvalidHandshakeError() {
553 setupSecureChannel(false)
554 initHandshakeMessage(FakeEncryptionRunner.INIT_MESSAGE_EMPTY_RESPONSE)
555
556 verify(mockCallback)
557 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_HANDSHAKE)
558 }
559
560 @Test
561 fun processVerificationCode_listenerNotSet_issueInvalidStateError() {
562 setupSecureChannel(false)
563 initHandshakeMessage()
564 respondToContinueMessage()
Android Auto Companion16c608d2022-02-02 10:13:13 -0800565
566 val testVerificationCodeMessage =
567 VerificationCode.newBuilder().setState(VerificationCodeState.VISUAL_VERIFICATION).build()
568 val deviceMessage =
569 DeviceMessage.createOutgoingMessage(
570 /* recipient= */ null,
571 /* isMessageEncrypted= */ false,
572 OperationType.ENCRYPTION_HANDSHAKE,
573 testVerificationCodeMessage.toByteArray()
574 )
575 secureChannel.onDeviceMessageReceived(deviceMessage)
576
Android Auto Companion179c3e32021-06-23 09:04:17 -0700577 verify(mockCallback).onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_STATE)
578 }
579
580 @Test
Android Auto Companione1421e92021-07-21 10:33:24 -0700581 fun setDeviceIdDuringAssociation_encryptionKeyNotSet_issueInvalidKeyError() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700582 setupSecureChannel(false)
Android Auto Companione1421e92021-07-21 10:33:24 -0700583 secureChannel.setDeviceIdDuringAssociation(UUID.randomUUID())
Android Auto Companion179c3e32021-06-23 09:04:17 -0700584
585 verify(mockCallback)
586 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_ENCRYPTION_KEY)
587 }
588
589 @Test
590 fun notifyVerificationCodeAccepted_invalidState_issueInvalidVerificationError() {
591 setupSecureChannel(false)
592 initHandshakeMessage()
593 secureChannel.notifyVerificationCodeAccepted()
594
595 verify(mockCallback)
596 .onEstablishSecureChannelFailure(ChannelError.CHANNEL_ERROR_INVALID_VERIFICATION)
597 }
598
Android Auto Companione1421e92021-07-21 10:33:24 -0700599 @Test
Android Auto Companion16c608d2022-02-02 10:13:13 -0800600 fun processVerificationCodeMessage_oobVerification_verifyOobCode() {
601 setupSecureChannel(false)
Android Auto Companione1421e92021-07-21 10:33:24 -0700602 initHandshakeMessage()
603 respondToContinueMessage()
Android Auto Companion16c608d2022-02-02 10:13:13 -0800604 val testPayload = "testPayload".toByteArray()
605 val testVerificationCodeMessage =
606 VerificationCode.newBuilder().run {
607 setState(VerificationCodeState.OOB_VERIFICATION)
608 setPayload(ByteString.copyFrom(testPayload))
609 build()
610 }
611 val deviceMessage =
612 DeviceMessage.createOutgoingMessage(
613 /* recipient= */ null,
614 /* isMessageEncrypted= */ false,
615 OperationType.ENCRYPTION_HANDSHAKE,
616 testVerificationCodeMessage.toByteArray()
617 )
618 secureChannel.onDeviceMessageReceived(deviceMessage)
619
620 verify(mockOobRunner).decryptData(testPayload)
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700621 }
622
623 @Test
Android Auto Companion16c608d2022-02-02 10:13:13 -0800624 fun createOobResponse_oobCodeMatch_sendCorrectMessage() {
625 val testPayload = "testPayload".toByteArray()
626 whenever(mockOobRunner.decryptData(testPayload))
627 .thenReturn(FakeEncryptionRunner.VERIFICATION_CODE)
628 whenever(mockOobRunner.encryptData(FakeEncryptionRunner.VERIFICATION_CODE))
629 .thenReturn(testPayload)
630 setupSecureChannel(false)
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700631 initHandshakeMessage()
632 respondToContinueMessage()
Android Auto Companion16c608d2022-02-02 10:13:13 -0800633 val testVerificationCodeMessage =
634 VerificationCode.newBuilder().run {
635 setState(VerificationCodeState.OOB_VERIFICATION)
636 setPayload(ByteString.copyFrom(testPayload))
637 build()
638 }
639 val deviceMessage =
640 DeviceMessage.createOutgoingMessage(
641 /* recipient= */ null,
642 /* isMessageEncrypted= */ false,
643 OperationType.ENCRYPTION_HANDSHAKE,
644 testVerificationCodeMessage.toByteArray()
645 )
646 secureChannel.onDeviceMessageReceived(deviceMessage)
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700647
Android Auto Companion16c608d2022-02-02 10:13:13 -0800648 val confirmationMessage =
649 argumentCaptor<DeviceMessage>().run {
650 verify(stream1, times(2)).sendMessage(capture())
651 secondValue.message
652 }
653 val verificationCodeMessage = VerificationCode.parseFrom(confirmationMessage)
654 assertThat(verificationCodeMessage.state).isEqualTo(VerificationCodeState.OOB_VERIFICATION)
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700655 }
656
657 @Test
Android Auto Companion16c608d2022-02-02 10:13:13 -0800658 fun onVisualVerificationCodeConfirmed_sendConfirmationMessage() {
659 setupSecureChannel(false)
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700660 initHandshakeMessage()
661 respondToContinueMessage()
Android Auto Companion16c608d2022-02-02 10:13:13 -0800662 val testVerificationCodeMessage =
663 VerificationCode.newBuilder().setState(VerificationCodeState.VISUAL_VERIFICATION).build()
664 val deviceMessage =
665 DeviceMessage.createOutgoingMessage(
666 /* recipient= */ null,
667 /* isMessageEncrypted= */ false,
668 OperationType.ENCRYPTION_HANDSHAKE,
669 testVerificationCodeMessage.toByteArray()
670 )
671 secureChannel.onDeviceMessageReceived(deviceMessage)
672 secureChannel.notifyVerificationCodeAccepted()
673 val confirmationMessage =
674 argumentCaptor<DeviceMessage>().run {
675 verify(stream1, times(2)).sendMessage(capture())
676 secondValue.message
677 }
678 val verificationCodeMessage = VerificationCode.parseFrom(confirmationMessage)
679 assertThat(verificationCodeMessage.state).isEqualTo(VerificationCodeState.VISUAL_CONFIRMATION)
Android Auto Companione1421e92021-07-21 10:33:24 -0700680 }
681
Android Auto Companion179c3e32021-06-23 09:04:17 -0700682 private fun setupSecureChannel(isReconnect: Boolean, deviceId: String? = null) {
Android Auto Companione1421e92021-07-21 10:33:24 -0700683 val encryptionRunner = EncryptionRunnerFactory.newFakeRunner()
684 encryptionRunner.setIsReconnect(isReconnect)
Android Auto Companion179c3e32021-06-23 09:04:17 -0700685 secureChannel =
686 spy(
Android Auto Companion16c608d2022-02-02 10:13:13 -0800687 MultiProtocolSecureChannel(
Android Auto Companion179c3e32021-06-23 09:04:17 -0700688 stream1,
689 spyStorage,
Android Auto Companione1421e92021-07-21 10:33:24 -0700690 encryptionRunner,
Android Auto Companion16c608d2022-02-02 10:13:13 -0800691 mockOobRunner,
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700692 deviceId = deviceId,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700693 inflater = mockInflater
694 )
695 .apply { callback = mockCallback }
696 )
697 }
698
699 private fun initHandshakeMessage(message: ByteArray = FakeEncryptionRunner.INIT_MESSAGE) {
700 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700701 DeviceMessage.createOutgoingMessage(
Android Auto Companion179c3e32021-06-23 09:04:17 -0700702 /* recipient= */ null,
703 /* isMessageEncrypted= */ false,
Android Auto Companione1421e92021-07-21 10:33:24 -0700704 OperationType.ENCRYPTION_HANDSHAKE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700705 message
706 )
707 secureChannel.onDeviceMessageReceived(deviceMessage)
708 }
709
710 private fun respondToContinueMessage(message: ByteArray = FakeEncryptionRunner.CLIENT_RESPONSE) {
711 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700712 DeviceMessage.createOutgoingMessage(
Android Auto Companion179c3e32021-06-23 09:04:17 -0700713 /* recipient= */ null,
714 /* isMessageEncrypted= */ false,
Android Auto Companione1421e92021-07-21 10:33:24 -0700715 OperationType.ENCRYPTION_HANDSHAKE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700716 message
717 )
718 secureChannel.onDeviceMessageReceived(deviceMessage)
719 }
720
721 private fun respondToResumeMessage(message: ByteArray = "Placeholder Message".toByteArray()) {
722 val deviceMessage =
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700723 DeviceMessage.createOutgoingMessage(
Android Auto Companion179c3e32021-06-23 09:04:17 -0700724 /* recipient= */ null,
725 /* isMessageEncrypted= */ false,
Android Auto Companione1421e92021-07-21 10:33:24 -0700726 OperationType.ENCRYPTION_HANDSHAKE,
Android Auto Companion179c3e32021-06-23 09:04:17 -0700727 message
728 )
729 secureChannel.onDeviceMessageReceived(deviceMessage)
730 }
731
732 private fun completeHandshakeAndSaveTheKey() {
Android Auto Companion179c3e32021-06-23 09:04:17 -0700733 setupSecureChannel(false)
734 secureChannel.showVerificationCodeListener = mockShowVerificationCodeListener
735 initHandshakeMessage()
736 respondToContinueMessage()
737 secureChannel.notifyVerificationCodeAccepted()
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700738 }
739}
740
Android Auto Companion6b2e6912021-11-10 10:01:49 -0800741private open class TestProtocol : ConnectionProtocol() {
Android Auto Companion16c608d2022-02-02 10:13:13 -0800742 override fun isDeviceVerificationRequired() = false
Android Auto Companione1421e92021-07-21 10:33:24 -0700743
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700744 override fun startAssociationDiscovery(
745 name: String,
Android Auto Companion16c608d2022-02-02 10:13:13 -0800746 identifier: ParcelUuid,
747 callback: IDiscoveryCallback
Android Auto Companion9a35cab2021-10-13 10:00:56 -0700748 ) {}
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700749
750 override fun startConnectionDiscovery(
Android Auto Companion16c608d2022-02-02 10:13:13 -0800751 id: ParcelUuid,
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700752 challenge: ConnectChallenge,
Android Auto Companion16c608d2022-02-02 10:13:13 -0800753 callback: IDiscoveryCallback
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700754 ) {}
755
756 override fun stopAssociationDiscovery() {}
757
Android Auto Companion16c608d2022-02-02 10:13:13 -0800758 override fun stopConnectionDiscovery(id: ParcelUuid) {}
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700759
Android Auto Companion16c608d2022-02-02 10:13:13 -0800760 override fun sendData(protocolId: String, data: ByteArray, callback: IDataSendCallback?) {}
Android Auto Companiona7288fb2021-06-09 12:52:29 -0700761
762 override fun disconnectDevice(protocolId: String) {}
763
764 override fun reset() {}
765
766 override fun getMaxWriteSize(protocolId: String): Int {
767 return 0
768 }
769}
770
Android Auto Companion179c3e32021-06-23 09:04:17 -0700771private class Base64CryptoHelper : CryptoHelper {
772 override fun encrypt(value: ByteArray?): String? = Base64.encodeToString(value, Base64.DEFAULT)
773
774 override fun decrypt(value: String?): ByteArray? = Base64.decode(value, Base64.DEFAULT)
775}