dash eap: bugfix
Shift the MSB of the lenght by 1 byte, not one bit.
This commit is contained in:
parent
7dd8fc1bf6
commit
923d8d33ef
6 changed files with 82 additions and 40 deletions
|
@ -1,20 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
class CryptSequence(var sqn: Long) {
|
|
||||||
|
|
||||||
fun incrementForEnDecrypt(fromPdmToPod: Boolean): ByteArray {
|
|
||||||
sqn++
|
|
||||||
val ret = ByteBuffer.allocate(8)
|
|
||||||
.putLong(sqn)
|
|
||||||
.array()
|
|
||||||
.copyOfRange(3, 8)
|
|
||||||
if (fromPdmToPod) {
|
|
||||||
ret[0] = (ret[0].toInt() and 127).toByte()
|
|
||||||
} else {
|
|
||||||
ret[0] = (ret[0].toInt() or 128).toByte()
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,6 +9,7 @@ enum class EapAkaAttributeType(val type: Byte) {
|
||||||
AT_RAND(1),
|
AT_RAND(1),
|
||||||
AT_AUTN(2),
|
AT_AUTN(2),
|
||||||
AT_RES(3),
|
AT_RES(3),
|
||||||
|
AT_CLIENT_ERROR_CODE(22),
|
||||||
AT_CUSTOM_IV(126);
|
AT_CUSTOM_IV(126);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -30,7 +31,7 @@ sealed class EapAkaAttribute {
|
||||||
fun parseAttributes(aapsLogger: AAPSLogger, payload: ByteArray): List<EapAkaAttribute> {
|
fun parseAttributes(aapsLogger: AAPSLogger, payload: ByteArray): List<EapAkaAttribute> {
|
||||||
var tail = payload
|
var tail = payload
|
||||||
val ret = LinkedList<EapAkaAttribute>()
|
val ret = LinkedList<EapAkaAttribute>()
|
||||||
while (tail.size > 0) {
|
while (tail.isNotEmpty()) {
|
||||||
if (tail.size < 2) {
|
if (tail.size < 2) {
|
||||||
throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}")
|
throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}")
|
||||||
}
|
}
|
||||||
|
@ -41,11 +42,15 @@ sealed class EapAkaAttribute {
|
||||||
val type = EapAkaAttributeType.byValue(tail[0])
|
val type = EapAkaAttributeType.byValue(tail[0])
|
||||||
when (type) {
|
when (type) {
|
||||||
EapAkaAttributeType.AT_RES ->
|
EapAkaAttributeType.AT_RES ->
|
||||||
ret.add(EapAkaAttributeRes.parse(tail.copyOfRange(2, size)))
|
ret.add(EapAkaAttributeRes.parse(tail.copyOfRange(2, EapAkaAttributeRes.SIZE)))
|
||||||
EapAkaAttributeType.AT_CUSTOM_IV ->
|
EapAkaAttributeType.AT_CUSTOM_IV ->
|
||||||
ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, size)))
|
ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, EapAkaAttributeCustomIV.SIZE)))
|
||||||
else ->
|
EapAkaAttributeType.AT_AUTN ->
|
||||||
throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}. Expecting only AT_RES or CUSTOM_IV attribute types from the POD")
|
ret.add(EapAkaAttributeAutn.parse(tail.copyOfRange(2, EapAkaAttributeAutn.SIZE)))
|
||||||
|
EapAkaAttributeType.AT_RAND ->
|
||||||
|
ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE)))
|
||||||
|
EapAkaAttributeType.AT_CLIENT_ERROR_CODE ->
|
||||||
|
ret.add(EapAkaAttributeClientErrorCode.parse(tail.copyOfRange(2, EapAkaAttributeClientErrorCode.SIZE)))
|
||||||
}
|
}
|
||||||
tail = tail.copyOfRange(size, tail.size)
|
tail = tail.copyOfRange(size, tail.size)
|
||||||
}
|
}
|
||||||
|
@ -61,12 +66,17 @@ data class EapAkaAttributeRand(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
return byteArrayOf(EapAkaAttributeType.AT_RAND.type, SIZE, 0, 0) + payload
|
return byteArrayOf(EapAkaAttributeType.AT_RAND.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
fun parse(payload: ByteArray): EapAkaAttribute {
|
||||||
private const val SIZE = (20 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=16
|
if (payload.size < 2 + 16) {
|
||||||
|
throw MessageIOException("Could not parse RAND attribute: ${payload.toHex()}")
|
||||||
|
}
|
||||||
|
return EapAkaAttributeRand(payload.copyOfRange(2, 2 + 16))
|
||||||
|
}
|
||||||
|
const val SIZE = 20 // type, size, 2 reserved bytes, payload=16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +87,19 @@ data class EapAkaAttributeAutn(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
return byteArrayOf(EapAkaAttributeType.AT_AUTN.type, SIZE, 0, 0) + payload
|
return byteArrayOf(EapAkaAttributeType.AT_AUTN.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val SIZE = (20 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=16
|
fun parse(payload: ByteArray): EapAkaAttribute {
|
||||||
|
if (payload.size < 2 + 16) {
|
||||||
|
throw MessageIOException("Could not parse AUTN attribute: ${payload.toHex()}")
|
||||||
|
}
|
||||||
|
return EapAkaAttributeAutn(payload.copyOfRange(2, 2 + 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
const val SIZE = 20 // type, size, 2 reserved bytes, payload=16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +110,7 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
return byteArrayOf(EapAkaAttributeType.AT_RES.type, SIZE, 0, PAYLOAD_SIZE_BITS) + payload
|
return byteArrayOf(EapAkaAttributeType.AT_RES.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, PAYLOAD_SIZE_BITS) + payload
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -105,7 +122,7 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
return EapAkaAttributeRes(payload.copyOfRange(2, 2 + 8))
|
return EapAkaAttributeRes(payload.copyOfRange(2, 2 + 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val SIZE = (12 / SIZE_MULTIPLIER).toByte() // type, size, len in bits=2, payload=8
|
const val SIZE = 12 // type, size, len in bits=2, payload=8
|
||||||
private const val PAYLOAD_SIZE_BITS = 64.toByte() // type, size, 2 reserved bytes, payload
|
private const val PAYLOAD_SIZE_BITS = 64.toByte() // type, size, 2 reserved bytes, payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,7 +134,7 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
return byteArrayOf(EapAkaAttributeType.AT_CUSTOM_IV.type, SIZE, 0, 0) + payload
|
return byteArrayOf(EapAkaAttributeType.AT_CUSTOM_IV.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -128,7 +145,29 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
}
|
}
|
||||||
return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4))
|
return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4))
|
||||||
}
|
}
|
||||||
|
const val SIZE = 8 // type, size, 2 reserved bytes, payload=4
|
||||||
private const val SIZE = (8 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=4
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class EapAkaAttributeClientErrorCode(val payload: ByteArray) : EapAkaAttribute() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(payload.size == 2) { "Error code hast to be 2 bytes. Payload: ${payload.toHex()}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toByteArray(): ByteArray {
|
||||||
|
return byteArrayOf(EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun parse(payload: ByteArray): EapAkaAttributeClientErrorCode {
|
||||||
|
if (payload.size < 2 + 2) {
|
||||||
|
throw MessageIOException("Could not parse CLIENT_ERROR_CODE attribute: ${payload.toHex()}")
|
||||||
|
}
|
||||||
|
return EapAkaAttributeClientErrorCode(payload.copyOfRange(2, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
const val SIZE = 4 // type, size=1, payload:2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ data class EapMessage(
|
||||||
.allocate(totalSize)
|
.allocate(totalSize)
|
||||||
.put(code.code)
|
.put(code.code)
|
||||||
.put(identifier)
|
.put(identifier)
|
||||||
.put(((totalSize ushr 1) and 0XFF).toByte())
|
.put(((totalSize ushr 8) and 0XFF).toByte())
|
||||||
.put((totalSize and 0XFF).toByte())
|
.put((totalSize and 0XFF).toByte())
|
||||||
.put(AKA_PACKET_TYPE)
|
.put(AKA_PACKET_TYPE)
|
||||||
.put(SUBTYPE_AKA_CHALLENGE)
|
.put(SUBTYPE_AKA_CHALLENGE)
|
||||||
|
@ -62,7 +62,7 @@ data class EapMessage(
|
||||||
if (payload.size < 4) {
|
if (payload.size < 4) {
|
||||||
throw MessageIOException("Invalid eap payload: ${payload.toHex()}")
|
throw MessageIOException("Invalid eap payload: ${payload.toHex()}")
|
||||||
}
|
}
|
||||||
val totalSize = (payload[2].toInt() shl 1) or payload[3].toInt()
|
val totalSize = (payload[2].toInt() shl 8) or payload[3].toInt()
|
||||||
if (totalSize > payload.size) {
|
if (totalSize > payload.size) {
|
||||||
throw MessageIOException("Invalid eap payload. Too short: ${payload.toHex()}")
|
throw MessageIOException("Invalid eap payload. Too short: ${payload.toHex()}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,11 @@ class SessionEstablisher(
|
||||||
// TODO verify that identifier matches identifer from the Challenge
|
// TODO verify that identifier matches identifer from the Challenge
|
||||||
val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload)
|
val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload)
|
||||||
if (eapMsg.attributes.size != 2) {
|
if (eapMsg.attributes.size != 2) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got RES message: $eapMsg")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg")
|
||||||
|
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
|
||||||
|
// TODO: special exception for this
|
||||||
|
throw SessionEstablishmentException("Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${eapMsg.attributes[0].toByteArray().toHex()}")
|
||||||
|
}
|
||||||
throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}")
|
throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}")
|
||||||
}
|
}
|
||||||
for (attr in eapMsg.attributes) {
|
for (attr in eapMsg.attributes) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ class EnDecryptTest {
|
||||||
aapsLogger,
|
aapsLogger,
|
||||||
Nonce(
|
Nonce(
|
||||||
Hex.decode("dda23c090a0a0a0a"),
|
Hex.decode("dda23c090a0a0a0a"),
|
||||||
Hex.decode("0000000001")
|
0
|
||||||
),
|
),
|
||||||
Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"),
|
Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"),
|
||||||
)
|
)
|
||||||
|
@ -39,7 +39,7 @@ class EnDecryptTest {
|
||||||
aapsLogger,
|
aapsLogger,
|
||||||
Nonce(
|
Nonce(
|
||||||
Hex.decode("dda23c090a0a0a0a"),
|
Hex.decode("dda23c090a0a0a0a"),
|
||||||
Hex.decode("0000000001")
|
0
|
||||||
),
|
),
|
||||||
Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"),
|
Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLoggerTest
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Test
|
||||||
|
import org.spongycastle.util.encoders.Hex
|
||||||
|
|
||||||
|
class EapMessageTest {
|
||||||
|
|
||||||
|
@Test fun testParseAndBack() {
|
||||||
|
val aapsLogger = AAPSLoggerTest()
|
||||||
|
val payload = Hex.decode("01bd0038170100000205000000c55c78e8d3b9b9e935860a7259f6c001050000c2cd1248451103bd77a6c7ef88c441ba7e0200006cff5d18")
|
||||||
|
val eapMsg = EapMessage.parse(aapsLogger, payload)
|
||||||
|
val back = eapMsg.toByteArray()
|
||||||
|
Assert.assertEquals(back.toHex(), payload.toHex())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue