Skip to content

Commit 33d2fbb

Browse files
author
Robert Henigan
authored
Merge pull request #1644 from smartdevicelink/bugfix/issue_1642
Implement multiframe encryption correctly
2 parents 824de0e + 385f314 commit 33d2fbb

2 files changed

Lines changed: 84 additions & 48 deletions

File tree

base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public class SdlProtocolBase {
7171
private final static String FailurePropagating_Msg = "Failure propagating ";
7272

7373
private static final int TLS_MAX_RECORD_SIZE = 16384;
74+
private final static int TLS_RECORD_HEADER_SIZE = 5;
75+
private final static int TLS_RECORD_MES_AUTH_CDE_SIZE = 32;
76+
private final static int TLS_MAX_RECORD_PADDING_SIZE = 256;
77+
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;
7478

7579
private static final int PRIMARY_TRANSPORT_ID = 1;
7680
private static final int SECONDARY_TRANSPORT_ID = 2;
@@ -561,7 +565,8 @@ public void endSession(byte sessionID) {
561565
public void sendMessage(ProtocolMessage protocolMsg) {
562566
SessionType sessionType = protocolMsg.getSessionType();
563567
byte sessionID = protocolMsg.getSessionID();
564-
568+
boolean requiresEncryption = protocolMsg.getPayloadProtected();
569+
SdlSecurityBase sdlSec = null;
565570
byte[] data;
566571
if (protocolVersion.getMajor() > 1 && sessionType != SessionType.NAV && sessionType != SessionType.PCM) {
567572
if (sessionType.eq(SessionType.CONTROL)) {
@@ -590,21 +595,15 @@ public void sendMessage(ProtocolMessage protocolMsg) {
590595
data = protocolMsg.getData();
591596
}
592597

593-
if (iSdlProtocol != null && protocolMsg.getPayloadProtected()) {
594-
595-
if (data != null && data.length > 0) {
596-
byte[] dataToRead = new byte[TLS_MAX_RECORD_SIZE];
597-
SdlSecurityBase sdlSec = iSdlProtocol.getSdlSecurity();
598-
if (sdlSec == null)
599-
return;
600-
601-
Integer iNumBytes = sdlSec.encryptData(data, dataToRead);
602-
if ((iNumBytes == null) || (iNumBytes <= 0))
603-
return;
604-
605-
byte[] encryptedData = new byte[iNumBytes];
606-
System.arraycopy(dataToRead, 0, encryptedData, 0, iNumBytes);
607-
data = encryptedData;
598+
if (requiresEncryption) {
599+
if (iSdlProtocol == null) {
600+
DebugTool.logError(TAG, "Unable to encrypt packet, protocol callback was null");
601+
return;
602+
}
603+
sdlSec = iSdlProtocol.getSdlSecurity();
604+
if (sdlSec == null) {
605+
DebugTool.logError(TAG, "Unable to encrypt packet, security library not found");
606+
return;
608607
}
609608
}
610609

@@ -616,24 +615,25 @@ public void sendMessage(ProtocolMessage protocolMsg) {
616615
return;
617616
}
618617

619-
synchronized (messageLock) {
620-
if (data != null && data.length > getMtu(sessionType)) {
618+
//Set the MTU according to session MTU provided by the IVI or the max data size for encryption if required
619+
final Long mtu = requiresEncryption ? TLS_MAX_DATA_TO_ENCRYPT_SIZE : getMtu(sessionType);
621620

621+
synchronized (messageLock) {
622+
if (data != null && data.length > mtu) {
623+
//Since the packet is larger than the mtu size, it will be sent as a multi-frame packet
622624
messageID++;
623625

624626
// Assemble first frame.
625-
Long mtu = getMtu(sessionType);
626-
int frameCount = Long.valueOf(data.length / mtu).intValue();
627-
if (data.length % mtu > 0) {
628-
frameCount++;
629-
}
627+
int frameCount = (int) Math.ceil(data.length / (double) mtu);
628+
630629
byte[] firstFrameData = new byte[8];
631630
// First four bytes are data size.
632631
System.arraycopy(BitConverter.intToByteArray(data.length), 0, firstFrameData, 0, 4);
633632
// Second four bytes are frame count.
634633
System.arraycopy(BitConverter.intToByteArray(frameCount), 0, firstFrameData, 4, 4);
635634

636-
SdlPacket firstHeader = SdlPacketFactory.createMultiSendDataFirst(sessionType, sessionID, messageID, (byte) protocolVersion.getMajor(), firstFrameData, protocolMsg.getPayloadProtected());
635+
//NOTE: First frames cannot be encrypted because their payloads need to be exactly 8 bytes
636+
SdlPacket firstHeader = SdlPacketFactory.createMultiSendDataFirst(sessionType, sessionID, messageID, (byte) protocolVersion.getMajor(), firstFrameData, false);
637637
firstHeader.setPriorityCoefficient(1 + protocolMsg.priorityCoefficient);
638638
firstHeader.setTransportRecord(activeTransports.get(sessionType));
639639
//Send the first frame
@@ -642,33 +642,65 @@ public void sendMessage(ProtocolMessage protocolMsg) {
642642
int currentOffset = 0;
643643
byte frameSequenceNumber = 0;
644644

645+
byte[] dataBuffer, encryptedData;
645646
for (int i = 0; i < frameCount; i++) {
646-
if (i < (frameCount - 1)) {
647+
648+
frameSequenceNumber++;
649+
650+
if (frameSequenceNumber == SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
651+
//If sequence numbers roll over to 0, increment again to avoid
652+
//using the reserved sequence value for the final frame
647653
++frameSequenceNumber;
648-
if (frameSequenceNumber ==
649-
SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME) {
650-
// we can't use 0x00 as frameSequenceNumber, because
651-
// it's reserved for the last frame
652-
++frameSequenceNumber;
653-
}
654-
} else {
654+
}
655+
656+
if (i == frameCount - 1) {
655657
frameSequenceNumber = SdlPacket.FRAME_INFO_FINAL_CONNESCUTIVE_FRAME;
656-
} // end-if
658+
}
657659

658660
int bytesToWrite = data.length - currentOffset;
659661
if (bytesToWrite > mtu) {
660662
bytesToWrite = mtu.intValue();
661663
}
662-
SdlPacket consecHeader = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, bytesToWrite, frameSequenceNumber, messageID, (byte) protocolVersion.getMajor(), data, currentOffset, bytesToWrite, protocolMsg.getPayloadProtected());
663-
consecHeader.setTransportRecord(activeTransports.get(sessionType));
664-
consecHeader.setPriorityCoefficient(i + 2 + protocolMsg.priorityCoefficient);
665-
handlePacketToSend(consecHeader);
664+
665+
SdlPacket consecutiveFrame;
666+
if (requiresEncryption) {
667+
//Retrieve a chunk of the data into a temporary buffer to be encrypted
668+
dataBuffer = new byte[bytesToWrite];
669+
System.arraycopy(data, currentOffset, dataBuffer, 0, bytesToWrite);
670+
671+
encryptedData = new byte[TLS_MAX_RECORD_SIZE];
672+
Integer numberOfBytesEncrypted = sdlSec.encryptData(dataBuffer, encryptedData);
673+
if (numberOfBytesEncrypted == null || (numberOfBytesEncrypted <= 0)) {
674+
DebugTool.logError(TAG, "Unable to encrypt data");
675+
return;
676+
}
677+
678+
consecutiveFrame = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, numberOfBytesEncrypted, frameSequenceNumber, messageID, (byte) protocolVersion.getMajor(), encryptedData, 0, numberOfBytesEncrypted, true);
679+
} else {
680+
consecutiveFrame = SdlPacketFactory.createMultiSendDataRest(sessionType, sessionID, bytesToWrite, frameSequenceNumber, messageID, (byte) protocolVersion.getMajor(), data, currentOffset, bytesToWrite, false);
681+
}
682+
683+
consecutiveFrame.setTransportRecord(activeTransports.get(sessionType));
684+
consecutiveFrame.setPriorityCoefficient(i + 2 + protocolMsg.priorityCoefficient);
685+
handlePacketToSend(consecutiveFrame);
666686
currentOffset += bytesToWrite;
667687
}
668688
} else {
669689
messageID++;
690+
if (requiresEncryption && data != null && data.length > 0) {
691+
//Encrypt the data before sending
692+
byte[] encryptedData = new byte[TLS_MAX_RECORD_SIZE];
693+
Integer numberOfBytesEncrypted = sdlSec.encryptData(data, encryptedData);
694+
if (numberOfBytesEncrypted == null || (numberOfBytesEncrypted <= 0)) {
695+
DebugTool.logError(TAG, "Unable to encrypt data");
696+
return;
697+
}
698+
//Put the encrypted bytes back into the data array
699+
data = new byte[numberOfBytesEncrypted];
700+
System.arraycopy(encryptedData, 0, data, 0, numberOfBytesEncrypted);
701+
}
670702
int dataLength = data != null ? data.length : 0;
671-
SdlPacket header = SdlPacketFactory.createSingleSendData(sessionType, sessionID, dataLength, messageID, (byte) protocolVersion.getMajor(), data, protocolMsg.getPayloadProtected());
703+
SdlPacket header = SdlPacketFactory.createSingleSendData(sessionType, sessionID, dataLength, messageID, (byte) protocolVersion.getMajor(), data, requiresEncryption);
672704
header.setPriorityCoefficient(protocolMsg.priorityCoefficient);
673705
header.setTransportRecord(activeTransports.get(sessionType));
674706
handlePacketToSend(header);
@@ -1374,16 +1406,17 @@ protected void handleFrame(SdlPacket packet) {
13741406
if (packet.getPayload() != null && packet.getDataSize() > 0 && packet.isEncrypted()) {
13751407

13761408
SdlSecurityBase sdlSec = iSdlProtocol.getSdlSecurity();
1377-
byte[] dataToRead = new byte[4096];
1409+
byte[] dataToRead = new byte[TLS_MAX_RECORD_SIZE];
13781410

1379-
Integer iNumBytes = sdlSec.decryptData(packet.getPayload(), dataToRead);
1380-
if ((iNumBytes == null) || (iNumBytes <= 0)) {
1411+
Integer numberOfDecryptedBytes = sdlSec.decryptData(packet.getPayload(), dataToRead);
1412+
if ((numberOfDecryptedBytes == null) || (numberOfDecryptedBytes <= 0)) {
13811413
return;
13821414
}
13831415

1384-
byte[] decryptedData = new byte[iNumBytes];
1385-
System.arraycopy(dataToRead, 0, decryptedData, 0, iNumBytes);
1416+
byte[] decryptedData = new byte[numberOfDecryptedBytes];
1417+
System.arraycopy(dataToRead, 0, decryptedData, 0, numberOfDecryptedBytes);
13861418
packet.payload = decryptedData;
1419+
packet.dataSize = numberOfDecryptedBytes;
13871420
}
13881421

13891422
if (packet.getFrameType().equals(FrameType.Control)) {

base/src/main/java/com/smartdevicelink/transport/SdlPsm.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ public class SdlPsm {
6161
private static final byte FIRST_FRAME_DATA_SIZE = 0x08;
6262

6363
private static final int VERSION_MASK = 0xF0; //4 highest bits
64-
private static final int COMPRESSION_MASK = 0x08; //4th lowest bit
64+
private static final int ENCRYPTION_MASK = 0x08; //4th lowest bit
6565
private static final int FRAME_TYPE_MASK = 0x07; //3 lowest bits
6666

6767

6868
int state;
6969

7070
int version;
71-
boolean compression;
71+
boolean encrypted;
7272
int frameType;
7373
int serviceType;
7474
int controlFrameInfo;
@@ -97,7 +97,7 @@ private int transitionOnInput(byte rawByte, int state) {
9797
if (version == 0) { //It should never be 0
9898
return ERROR_STATE;
9999
}
100-
compression = (1 == ((rawByte & (byte) COMPRESSION_MASK) >> 3));
100+
encrypted = (1 == ((rawByte & (byte) ENCRYPTION_MASK) >> 3));
101101

102102

103103
frameType = rawByte & (byte) FRAME_TYPE_MASK;
@@ -194,7 +194,10 @@ private int transitionOnInput(byte rawByte, int state) {
194194
break;
195195

196196
case SdlPacket.FRAME_TYPE_FIRST:
197-
if (dataLength == FIRST_FRAME_DATA_SIZE) {
197+
if (dataLength == FIRST_FRAME_DATA_SIZE || this.encrypted) {
198+
//In a few production releases of core the first frame could be
199+
//encrypted. Therefore it is not an error state if the first frame data
200+
//length is greater than 8 in that case alone.
198201
break;
199202
}
200203
default:
@@ -263,7 +266,7 @@ private int transitionOnInput(byte rawByte, int state) {
263266
public SdlPacket getFormedPacket() {
264267
if (state == FINISHED_STATE) {
265268
//Log.trace(TAG, "Finished packet.");
266-
return new SdlPacket(version, compression, frameType,
269+
return new SdlPacket(version, encrypted, frameType,
267270
serviceType, controlFrameInfo, sessionId,
268271
dataLength, messageId, payload);
269272
} else {

0 commit comments

Comments
 (0)