summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Henigan <robert.henigan@livio.io>2021-03-25 14:51:50 -0400
committerGitHub <noreply@github.com>2021-03-25 14:51:50 -0400
commit33d2fbb99bf56bd363dc7177ab1b4eb5842207c9 (patch)
tree891f02407e4d003083d354c8fdff8b72618a8eaf
parent824de0e11c08b95c5bca679c299677bb3b6a6c40 (diff)
parent385f31462beeb2514d606203f5e5dd756750dd87 (diff)
downloadsdl_android-33d2fbb99bf56bd363dc7177ab1b4eb5842207c9.tar.gz
Merge pull request #1644 from smartdevicelink/bugfix/issue_1642
Implement multiframe encryption correctly
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java119
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/SdlPsm.java13
2 files changed, 84 insertions, 48 deletions
diff --git a/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java b/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
index d9e437548..64578e7ee 100644
--- a/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
+++ b/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
@@ -71,6 +71,10 @@ public class SdlProtocolBase {
private final static String FailurePropagating_Msg = "Failure propagating ";
private static final int TLS_MAX_RECORD_SIZE = 16384;
+ private final static int TLS_RECORD_HEADER_SIZE = 5;
+ private final static int TLS_RECORD_MES_AUTH_CDE_SIZE = 32;
+ private final static int TLS_MAX_RECORD_PADDING_SIZE = 256;
+ private final static int TLS_MAX_DATA_TO_ENCRYPT_SIZE = TLS_MAX_RECORD_SIZE - TLS_RECORD_HEADER_SIZE - TLS_RECORD_MES_AUTH_CDE_SIZE - TLS_MAX_RECORD_PADDING_SIZE;
private static final int PRIMARY_TRANSPORT_ID = 1;
private static final int SECONDARY_TRANSPORT_ID = 2;
@@ -561,7 +565,8 @@ public class SdlProtocolBase {
public void sendMessage(ProtocolMessage protocolMsg) {
SessionType sessionType = protocolMsg.getSessionType();
byte sessionID = protocolMsg.getSessionID();
-
+ boolean requiresEncryption = protocolMsg.getPayloadProtected();
+ SdlSecurityBase sdlSec = null;
byte[] data;
if (protocolVersion.getMajor() > 1 && sessionType != SessionType.NAV && sessionType != SessionType.PCM) {
if (sessionType.eq(SessionType.CONTROL)) {
@@ -590,21 +595,15 @@ public class SdlProtocolBase {
data = protocolMsg.getData();
}
- if (iSdlProtocol != null && protocolMsg.getPayloadProtected()) {
-
- if (data != null && data.length > 0) {
- byte[] dataToRead = new byte[TLS_MAX_RECORD_SIZE];
- SdlSecurityBase sdlSec = iSdlProtocol.getSdlSecurity();
- if (sdlSec == null)
- return;
-
- Integer iNumBytes = sdlSec.encryptData(data, dataToRead);
- if ((iNumBytes == null) || (iNumBytes <= 0))
- return;
-
- byte[] encryptedData = new byte[iNumBytes];
- System.arraycopy(dataToRead, 0, encryptedData, 0, iNumBytes);
- data = encryptedData;
+ if (requiresEncryption) {
+ if (iSdlProtocol == null) {
+ DebugTool.logError(TAG, "Unable to encrypt packet, protocol callback was null");
+ return;
+ }
+ sdlSec = iSdlProtocol.getSdlSecurity();
+ if (sdlSec == null) {
+ DebugTool.logError(TAG, "Unable to encrypt packet, security library not found");
+ return;
}
}
@@ -616,24 +615,25 @@ public class SdlProtocolBase {
return;
}
- synchronized (messageLock) {
- if (data != null && data.length > getMtu(sessionType)) {
+ //Set the MTU according to session MTU provided by the IVI or the max data size for encryption if required
+ final Long mtu = requiresEncryption ? TLS_MAX_DATA_TO_ENCRYPT_SIZE : getMtu(sessionType);
+ synchronized (messageLock) {
+ if (data != null && data.length > mtu) {
+ //Since the packet is larger than the mtu size, it will be sent as a multi-frame packet
messageID++;
// Assemble first frame.
- Long mtu = getMtu(sessionType);
- int frameCount = Long.valueOf(data.length / mtu).intValue();
- if (data.length % mtu > 0) {
- frameCount++;
- }
+ int frameCount = (int) Math.ceil(data.length / (double) mtu);
+
byte[] firstFrameData = new byte[8];
// First four bytes are data size.
System.arraycopy(BitConverter.intToByteArray(data.length), 0, firstFrameData, 0, 4);
// Second four bytes are frame count.
System.arraycopy(BitConverter.intToByteArray(frameCount), 0, firstFrameData, 4, 4);
- SdlPacket firstHeader = SdlPacketFactory.createMultiSendDataFirst(sessionType, sessionID, messageID, (byte) protocolVersion.getMajor(), firstFrameData, protocolMsg.getPayloadProtected());
+ //NOTE: First frames cannot be encrypted because their payloads need to be exactly 8 bytes
+ SdlPacket firstHeader = SdlPacketFactory.createMultiSendDataFirst(sessionType, sessionID, messageID, (byte) protocolVersion.getMajor(), firstFrameData, false);
firstHeader.setPriorityCoefficient(1 + protocolMsg.priorityCoefficient);
firstHeader.setTransportRecord(activeTransports.get(sessionType));
//Send the first frame
@@ -642,33 +642,65 @@ public class SdlProtocolBase {
int currentOffset = 0;
byte frameSequenceNumber = 0;
+ byte[] dataBuffer, encryptedData;
for (int i = 0; i < frameCount; i++) {
- if (i < (frameCount - 1)) {
+
+ frameSequenceNumber++;
+
+ if (frameSequenceNumber == SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
+ //If sequence numbers roll over to 0, increment again to avoid
+ //using the reserved sequence value for the final frame
++frameSequenceNumber;
- if (frameSequenceNumber ==
- SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
- // we can't use 0x00 as frameSequenceNumber, because
- // it's reserved for the last frame
- ++frameSequenceNumber;
- }
- } else {
+ }
+
+ if (i == frameCount - 1) {
frameSequenceNumber = SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME;
- } // end-if
+ }
int bytesToWrite = data.length - currentOffset;
if (bytesToWrite > mtu) {
bytesToWrite = mtu.intValue();
}
- SdlPacket consecHeader = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, bytesToWrite, frameSequenceNumber, messageID, (byte) protocolVersion.getMajor(), data, currentOffset, bytesToWrite, protocolMsg.getPayloadProtected());
- consecHeader.setTransportRecord(activeTransports.get(sessionType));
- consecHeader.setPriorityCoefficient(i + 2 + protocolMsg.priorityCoefficient);
- handlePacketToSend(consecHeader);
+
+ SdlPacket consecutiveFrame;
+ if (requiresEncryption) {
+ //Retrieve a chunk of the data into a temporary buffer to be encrypted
+ dataBuffer = new byte[bytesToWrite];
+ System.arraycopy(data, currentOffset, dataBuffer, 0, bytesToWrite);
+
+ encryptedData = new byte[TLS_MAX_RECORD_SIZE];
+ Integer numberOfBytesEncrypted = sdlSec.encryptData(dataBuffer, encryptedData);
+ if (numberOfBytesEncrypted == null || (numberOfBytesEncrypted <= 0)) {
+ DebugTool.logError(TAG, "Unable to encrypt data");
+ return;
+ }
+
+ consecutiveFrame = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, numberOfBytesEncrypted, frameSequenceNumber, messageID, (byte) protocolVersion.getMajor(), encryptedData, 0, numberOfBytesEncrypted, true);
+ } else {
+ consecutiveFrame = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, bytesToWrite, frameSequenceNumber, messageID, (byte) protocolVersion.getMajor(), data, currentOffset, bytesToWrite, false);
+ }
+
+ consecutiveFrame.setTransportRecord(activeTransports.get(sessionType));
+ consecutiveFrame.setPriorityCoefficient(i + 2 + protocolMsg.priorityCoefficient);
+ handlePacketToSend(consecutiveFrame);
currentOffset += bytesToWrite;
}
} else {
messageID++;
+ if (requiresEncryption && data != null && data.length > 0) {
+ //Encrypt the data before sending
+ byte[] encryptedData = new byte[TLS_MAX_RECORD_SIZE];
+ Integer numberOfBytesEncrypted = sdlSec.encryptData(data, encryptedData);
+ if (numberOfBytesEncrypted == null || (numberOfBytesEncrypted <= 0)) {
+ DebugTool.logError(TAG, "Unable to encrypt data");
+ return;
+ }
+ //Put the encrypted bytes back into the data array
+ data = new byte[numberOfBytesEncrypted];
+ System.arraycopy(encryptedData, 0, data, 0, numberOfBytesEncrypted);
+ }
int dataLength = data != null ? data.length : 0;
- SdlPacket header = SdlPacketFactory.createSingleSendData(sessionType, sessionID, dataLength, messageID, (byte) protocolVersion.getMajor(), data, protocolMsg.getPayloadProtected());
+ SdlPacket header = SdlPacketFactory.createSingleSendData(sessionType, sessionID, dataLength, messageID, (byte) protocolVersion.getMajor(), data, requiresEncryption);
header.setPriorityCoefficient(protocolMsg.priorityCoefficient);
header.setTransportRecord(activeTransports.get(sessionType));
handlePacketToSend(header);
@@ -1374,16 +1406,17 @@ public class SdlProtocolBase {
if (packet.getPayload() != null && packet.getDataSize() > 0 && packet.isEncrypted()) {
SdlSecurityBase sdlSec = iSdlProtocol.getSdlSecurity();
- byte[] dataToRead = new byte[4096];
+ byte[] dataToRead = new byte[TLS_MAX_RECORD_SIZE];
- Integer iNumBytes = sdlSec.decryptData(packet.getPayload(), dataToRead);
- if ((iNumBytes == null) || (iNumBytes <= 0)) {
+ Integer numberOfDecryptedBytes = sdlSec.decryptData(packet.getPayload(), dataToRead);
+ if ((numberOfDecryptedBytes == null) || (numberOfDecryptedBytes <= 0)) {
return;
}
- byte[] decryptedData = new byte[iNumBytes];
- System.arraycopy(dataToRead, 0, decryptedData, 0, iNumBytes);
+ byte[] decryptedData = new byte[numberOfDecryptedBytes];
+ System.arraycopy(dataToRead, 0, decryptedData, 0, numberOfDecryptedBytes);
packet.payload = decryptedData;
+ packet.dataSize = numberOfDecryptedBytes;
}
if (packet.getFrameType().equals(FrameType.Control)) {
diff --git a/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java b/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java
index a142cebad..99510b061 100644
--- a/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java
+++ b/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java
@@ -61,14 +61,14 @@ public class SdlPsm {
private static final byte FIRST_FRAME_DATA_SIZE = 0x08;
private static final int VERSION_MASK = 0xF0; //4 highest bits
- private static final int COMPRESSION_MASK = 0x08; //4th lowest bit
+ private static final int ENCRYPTION_MASK = 0x08; //4th lowest bit
private static final int FRAME_TYPE_MASK = 0x07; //3 lowest bits
int state;
int version;
- boolean compression;
+ boolean encrypted;
int frameType;
int serviceType;
int controlFrameInfo;
@@ -97,7 +97,7 @@ public class SdlPsm {
if (version == 0) { //It should never be 0
return ERROR_STATE;
}
- compression = (1 == ((rawByte & (byte) COMPRESSION_MASK) >> 3));
+ encrypted = (1 == ((rawByte & (byte) ENCRYPTION_MASK) >> 3));
frameType = rawByte & (byte) FRAME_TYPE_MASK;
@@ -194,7 +194,10 @@ public class SdlPsm {
break;
case SdlPacket.FRAME_TYPE_FIRST:
- if (dataLength == FIRST_FRAME_DATA_SIZE) {
+ if (dataLength == FIRST_FRAME_DATA_SIZE || this.encrypted) {
+ //In a few production releases of core the first frame could be
+ //encrypted. Therefore it is not an error state if the first frame data
+ //length is greater than 8 in that case alone.
break;
}
default:
@@ -263,7 +266,7 @@ public class SdlPsm {
public SdlPacket getFormedPacket() {
if (state == FINISHED_STATE) {
//Log.trace(TAG, "Finished packet.");
- return new SdlPacket(version, compression, frameType,
+ return new SdlPacket(version, encrypted, frameType,
serviceType, controlFrameInfo, sessionId,
dataLength, messageId, payload);
} else {