This commit is contained in:
Andrei Vereha 2021-04-04 13:32:09 +02:00
parent 64fbea6afe
commit ff6a67cc97
4 changed files with 91 additions and 63 deletions

View file

@ -137,6 +137,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
private fun establishSession(msgSeq: Byte) { private fun establishSession(msgSeq: Byte) {
val conn = connection ?: throw FailedToConnectException("connection lost") val conn = connection ?: throw FailedToConnectException("connection lost")
val ltk: ByteArray = podState.ltk ?: throw FailedToConnectException("Missing LTK, activate the pod first") val ltk: ByteArray = podState.ltk ?: throw FailedToConnectException("Missing LTK, activate the pod first")
val uniqueId = podState.uniqueId val uniqueId = podState.uniqueId
val podId = uniqueId?.let { Id.fromLong(uniqueId) } val podId = uniqueId?.let { Id.fromLong(uniqueId) }
?: myId.increment() // pod not activated ?: myId.increment() // pod not activated

View file

@ -97,20 +97,18 @@ open class BleIO(
* @return * @return
*/ */
fun readyToRead(): BleSendResult { fun readyToRead(): BleSendResult {
val notificationSet = gatt.setCharacteristicNotification(characteristic, true) gatt.setCharacteristicNotification(characteristic, true)
if (!notificationSet) { .assertTrue("enable notifications")
throw ConnectException("Could not enable notifications")
}
val descriptors = characteristic.descriptors val descriptors = characteristic.descriptors
if (descriptors.size != 1) { if (descriptors.size != 1) {
throw ConnectException("Expecting one descriptor, found: ${descriptors.size}") throw ConnectException("Expecting one descriptor, found: ${descriptors.size}")
} }
val descriptor = descriptors[0] val descriptor = descriptors[0]
descriptor.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE descriptor.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
val wrote = gatt.writeDescriptor(descriptor) gatt.writeDescriptor(descriptor)
if (!wrote) { .assertTrue("enable indications on descriptor")
throw ConnectException("Could not enable indications on descriptor")
}
aapsLogger.debug(LTag.PUMPBTCOMM, "Enabling indications for $type") aapsLogger.debug(LTag.PUMPBTCOMM, "Enabling indications for $type")
val confirmation = bleCommCallbacks.confirmWrite( val confirmation = bleCommCallbacks.confirmWrite(
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE,
@ -130,3 +128,9 @@ open class BleIO(
const val DEFAULT_IO_TIMEOUT_MS = 1000.toLong() const val DEFAULT_IO_TIMEOUT_MS = 1000.toLong()
} }
} }
private fun Boolean.assertTrue(operation: String) {
if (!this) {
throw ConnectException("Could not $operation")
}
}

View file

@ -62,13 +62,11 @@ data class EapMessage(
private const val AKA_PACKET_TYPE = 0x17.toByte() private const val AKA_PACKET_TYPE = 0x17.toByte()
fun parse(aapsLogger: AAPSLogger, payload: ByteArray): EapMessage { fun parse(aapsLogger: AAPSLogger, payload: ByteArray): EapMessage {
if (payload.size < 4) { payload.assertSizeAtLeast(4)
throw MessageIOException("Invalid eap payload: ${payload.toHex()}")
}
val totalSize = (payload[2].toInt() shl 8) or payload[3].toInt() val totalSize = (payload[2].toInt() shl 8) or payload[3].toInt()
if (totalSize > payload.size) { payload.assertSizeAtLeast(totalSize)
throw MessageIOException("Invalid eap payload. Too short: ${payload.toHex()}")
}
if (payload.size == 4) { // SUCCESS/FAILURE if (payload.size == 4) { // SUCCESS/FAILURE
return EapMessage( return EapMessage(
code = EapCode.byValue(payload[0]), code = EapCode.byValue(payload[0]),
@ -90,3 +88,9 @@ data class EapMessage(
} }
} }
} }
private fun ByteArray.assertSizeAtLeast(size: Int) {
if (this.size < size) {
throw MessageIOException("Payload too short: ${this.toHex()}")
}
}

View file

@ -90,20 +90,65 @@ class SessionEstablisher(
) )
} }
private fun processChallengeResponse(challengeResponse: MessagePacket): EapSqn? { private fun assertIdentifier(msg: EapMessage) {
val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload) if (msg.identifier != identifier) {
if (eapMsg.identifier != identifier) {
aapsLogger.debug( aapsLogger.debug(
LTag.PUMPBTCOMM, LTag.PUMPBTCOMM,
"EAP-AKA: got incorrect identifier ${eapMsg.identifier} expected: $identifier" "EAP-AKA: got incorrect identifier ${msg.identifier} expected: $identifier"
) )
throw SessionEstablishmentException("Received incorrect EAP identifier: ${eapMsg.identifier}") throw SessionEstablishmentException("Received incorrect EAP identifier: ${msg.identifier}")
}
} }
if (eapMsg.subType == EapMessage.SUBTYPE_SYNCRONIZATION_FAILURE && private fun processChallengeResponse(challengeResponse: MessagePacket): EapSqn? {
eapMsg.attributes.size == 1 && val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload)
eapMsg.attributes[0] is EapAkaAttributeAuts
) { assertIdentifier(eapMsg)
val eapSqn = isResynchronization(eapMsg)
if (eapSqn != null) {
return eapSqn
}
assertValidAkaMessage(eapMsg)
for (attr in eapMsg.attributes) {
when (attr) {
is EapAkaAttributeRes ->
if (!milenage.res.contentEquals(attr.payload)) {
throw SessionEstablishmentException("RES mismatch." +
"Expected: ${milenage.res.toHex()}." +
"Actual: ${attr.payload.toHex()}.")
}
is EapAkaAttributeCustomIV ->
nodeIV = attr.payload.copyOfRange(0, IV_SIZE)
else ->
throw SessionEstablishmentException("Unknown attribute received: $attr")
}
}
return null
}
private fun assertValidAkaMessage(eapMsg: EapMessage) {
if (eapMsg.attributes.size != 2) {
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got incorrect: $eapMsg")
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
throw SessionEstablishmentException(
"Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${
eapMsg.attributes[0].toByteArray().toHex()
}"
)
}
throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}")
}
}
private fun isResynchronization(eapMsg: EapMessage): EapSqn? {
if (eapMsg.subType != EapMessage.SUBTYPE_SYNCRONIZATION_FAILURE ||
eapMsg.attributes.size != 1 ||
eapMsg.attributes[0] !is EapAkaAttributeAuts)
return null
val auts = eapMsg.attributes[0] as EapAkaAttributeAuts val auts = eapMsg.attributes[0] as EapAkaAttributeAuts
val autsMilenage = Milenage( val autsMilenage = Milenage(
aapsLogger = aapsLogger, aapsLogger = aapsLogger,
@ -130,33 +175,7 @@ class SessionEstablisher(
) )
} }
return EapSqn(autsMilenage.synchronizationSqn) return EapSqn(autsMilenage.synchronizationSqn)
}
if (eapMsg.attributes.size != 2) {
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg")
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
throw SessionEstablishmentException(
"Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${
eapMsg.attributes[0].toByteArray().toHex()
}"
)
}
throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}")
}
for (attr in eapMsg.attributes) {
when (attr) {
is EapAkaAttributeRes ->
if (!milenage.res.contentEquals(attr.payload)) {
throw SessionEstablishmentException("RES mismatch. Expected: ${milenage.res.toHex()} Actual: ${attr.payload.toHex()} ")
}
is EapAkaAttributeCustomIV ->
nodeIV = attr.payload.copyOfRange(0, IV_SIZE)
else ->
throw SessionEstablishmentException("Unknown attribute received: $attr")
}
}
return null
} }
private fun eapSuccess(): MessagePacket { private fun eapSuccess(): MessagePacket {