summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Henigan <robert.henigan@livio.io>2021-09-22 10:03:59 -0400
committerGitHub <noreply@github.com>2021-09-22 10:03:59 -0400
commit9a2398fc82bf7a1400aa514b4e4f7ec9f2c519f1 (patch)
tree90bc9bbafbbf5cadb04962da2784d6782239df7e
parent470e703dffd3e672cedf1315a0a03e04cc680fe5 (diff)
parentb890c4e82336c9eeaeb5aef03b17d1783673781b (diff)
downloadsdl_android-9a2398fc82bf7a1400aa514b4e4f7ec9f2c519f1.tar.gz
Merge pull request #1724 from smartdevicelink/bugfix/issue_1720
[SDL 0317] Protocol Security Spec
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java73
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java126
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java189
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java91
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java97
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/BaseSdlPacket.java5
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/ProtocolMessage.java5
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java6
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/SecurityQueryPayload.java157
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryErrorCode.java61
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryID.java105
-rw-r--r--base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryType.java41
-rw-r--r--base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java65
13 files changed, 1010 insertions, 11 deletions
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
index e8d89c818..094b29794 100644
--- a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/Validator.java
@@ -3,6 +3,9 @@ package com.smartdevicelink.test;
import com.smartdevicelink.managers.file.filetypes.SdlFile;
import com.smartdevicelink.protocol.enums.FrameDataControlFrameType;
import com.smartdevicelink.protocol.enums.FrameType;
+import com.smartdevicelink.protocol.enums.SecurityQueryErrorCode;
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.rpc.*;
import com.smartdevicelink.proxy.rpc.enums.AppServiceType;
@@ -10,7 +13,6 @@ import com.smartdevicelink.proxy.rpc.enums.DefrostZone;
import com.smartdevicelink.proxy.rpc.enums.FileType;
import com.smartdevicelink.proxy.rpc.enums.HMILevel;
import com.smartdevicelink.proxy.rpc.enums.HmiZoneCapabilities;
-import com.smartdevicelink.proxy.rpc.enums.KeyboardLayout;
import com.smartdevicelink.proxy.rpc.enums.PRNDL;
import com.smartdevicelink.proxy.rpc.enums.PrerecordedSpeech;
import com.smartdevicelink.proxy.rpc.enums.SpeechCapabilities;
@@ -126,6 +128,75 @@ public class Validator {
return true;
}
+ public static boolean validateQueryTypeArray(SecurityQueryType[] array1, SecurityQueryType[] array2) {
+
+ if (array1 == null) {
+ return (array2 == null);
+ }
+
+ if (array2 == null) {
+ return (array1 == null);
+ }
+
+ if (array1.length != array2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateQueryIDArray(SecurityQueryID[] array1, SecurityQueryID[] array2) {
+
+ if (array1 == null) {
+ return (array2 == null);
+ }
+
+ if (array2 == null) {
+ return (array1 == null);
+ }
+
+ if (array1.length != array2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean validateQueryErrorCodeArray(SecurityQueryErrorCode[] array1, SecurityQueryErrorCode[] array2) {
+
+ if (array1 == null) {
+ return (array2 == null);
+ }
+
+ if (array2 == null) {
+ return (array1 == null);
+ }
+
+ if (array1.length != array2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public static boolean validateFrameDataControlFrameTypeArray(FrameDataControlFrameType[] array1, FrameDataControlFrameType[] array2) {
if (array1 == null) {
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java
new file mode 100644
index 000000000..8c0c36041
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/SecurityQueryPayloadTests.java
@@ -0,0 +1,126 @@
+package com.smartdevicelink.test.protocol;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.smartdevicelink.protocol.SecurityQueryPayload;
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
+import com.smartdevicelink.util.BitConverter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+@RunWith(AndroidJUnit4.class)
+public class SecurityQueryPayloadTests {
+
+ public static SecurityQueryPayload createDummyBqh() {
+ SecurityQueryPayload bqh = new SecurityQueryPayload();
+ bqh.setCorrelationID(123);
+ bqh.setQueryID(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ bqh.setQueryType(SecurityQueryType.REQUEST);
+ bqh.setBulkData(null);
+ bqh.setJsonSize(0);
+ return bqh;
+ }
+
+ public SecurityQueryPayload safeParse(byte[] array) {
+ try {
+ return SecurityQueryPayload.parseBinaryQueryHeader(array);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Test
+ public void testCorrectParsing() {
+ byte[] array = new byte[12];
+ array[0] = 0;
+ array[1] = 0;
+ array[2] = 0;
+ array[3] = 2;
+ array[4] = 0;
+ array[5] = 0;
+ array[6] = 0;
+ array[7] = 3;
+ array[8] = 0;
+ array[9] = 0;
+ array[10] = 0;
+ array[11] = 0;
+
+ SecurityQueryPayload parsedBqh = SecurityQueryPayload.parseBinaryQueryHeader(array);
+ assertEquals(parsedBqh.getQueryType(), SecurityQueryType.REQUEST);
+ assertEquals(parsedBqh.getQueryID(), SecurityQueryID.SEND_INTERNAL_ERROR);
+ assertEquals(parsedBqh.getCorrelationID(), 3);
+ assertEquals(parsedBqh.getJsonSize(), 0);
+ }
+
+ @Test
+ public void testCorrectHeaderAssembly() {
+ SecurityQueryPayload dummyBqh = new SecurityQueryPayload();
+ dummyBqh.setQueryType(SecurityQueryType.REQUEST);
+ dummyBqh.setQueryID(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ dummyBqh.setCorrelationID(3);
+ dummyBqh.setJsonSize(0);
+
+ byte[] assembledHeader = dummyBqh.assembleHeaderBytes();
+ assertEquals(dummyBqh.getQueryType(), SecurityQueryType.valueOf(assembledHeader[0]));
+ byte[] queryIDFromHeader = new byte[3];
+ System.arraycopy(assembledHeader, 1, queryIDFromHeader, 0, 3);
+ assertEquals(dummyBqh.getQueryID(), SecurityQueryID.valueOf(queryIDFromHeader));
+ assertEquals(dummyBqh.getCorrelationID(), BitConverter.intFromByteArray(assembledHeader, 4));
+ assertEquals(dummyBqh.getJsonSize(), BitConverter.intFromByteArray(assembledHeader, 8));
+ }
+
+ @Test
+ public void testAssemblyAndParse() {
+ SecurityQueryPayload bqh = createDummyBqh();
+
+ byte[] bqhBytes = bqh.assembleHeaderBytes();
+ assertNotNull(bqhBytes);
+
+ SecurityQueryPayload parsedBqh = SecurityQueryPayload.parseBinaryQueryHeader(bqhBytes);
+ assertNotNull(parsedBqh);
+
+ assertEquals(bqh.getCorrelationID(), parsedBqh.getCorrelationID());
+ assertEquals(bqh.getQueryID(), parsedBqh.getQueryID());
+ assertEquals(bqh.getQueryType(), parsedBqh.getQueryType());
+ assertEquals(bqh.getBulkData(), parsedBqh.getBulkData());
+ assertEquals(bqh.getJsonData(), parsedBqh.getJsonData());
+ assertEquals(bqh.getJsonSize(), parsedBqh.getJsonSize());
+ }
+
+ @Test
+ public void testCorruptHeader() {
+ SecurityQueryPayload bqh = createDummyBqh();
+
+ byte[] bqhBytes = bqh.assembleHeaderBytes();
+
+ assertNotNull(safeParse(bqhBytes));
+
+ int size = bqhBytes.length;
+ for (int i = 0; i < size; i++) {
+ bqhBytes[i] = (byte) 0x99;
+ }
+
+ assertNull(safeParse(bqhBytes));
+ SecurityQueryPayload head = SecurityQueryPayload.parseBinaryQueryHeader(bqhBytes);
+ assertNull(head);
+ }
+
+ @Test
+ public void testJsonSetException() {
+ try {
+ SecurityQueryPayload bqh = createDummyBqh();
+ bqh.setJsonData(null);
+ fail("Setting JSON data to null should have thrown an exception");
+ } catch (Exception e) {
+ //Pass
+ }
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java
new file mode 100644
index 000000000..0b6cd3f61
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryErrorCodeTests.java
@@ -0,0 +1,189 @@
+package com.smartdevicelink.test.protocol.enums;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryErrorCode;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+public class SecurityQueryErrorCodeTests extends TestCase {
+
+ private Vector<SecurityQueryErrorCode> list = SecurityQueryErrorCode.getList();
+
+ public void testValidEnums() {
+ final byte ERROR_SUCCESS_BYTE = (byte) 0x00;
+ final String ERROR_SUCCESS_STRING = "ERROR_SUCCESS";
+
+ final byte ERROR_INVALID_QUERY_SIZE_BYTE = (byte) 0x01;
+ final String ERROR_INVALID_QUERY_SIZE_STRING = "ERROR_INVALID_QUERY_SIZE";
+
+ final byte ERROR_INVALID_QUERY_ID_BYTE = (byte) 0x02;
+ final String ERROR_INVALID_QUERY_ID_STRING = "ERROR_INVALID_QUERY_ID";
+
+ final byte ERROR_NOT_SUPPORTED_BYTE = (byte) 0x03;
+ final String ERROR_NOT_SUPPORTED_STRING = "ERROR_NOT_SUPPORTED";
+
+ final byte ERROR_SERVICE_ALREADY_PROTECTED_BYTE = (byte) 0x04;
+ final String ERROR_SERVICE_ALREADY_PROTECTED_STRING = "ERROR_SERVICE_ALREADY_PROTECTED";
+
+ final byte ERROR_SERVICE_NOT_PROTECTED_BYTE = (byte) 0x05;
+ final String ERROR_SERVICE_NOT_PROTECTED_STRING = "ERROR_SERVICE_NOT_PROTECTED";
+
+ final byte ERROR_DECRYPTION_FAILED_BYTE = (byte) 0x06;
+ final String ERROR_DECRYPTION_FAILED_STRING = "ERROR_DECRYPTION_FAILED";
+
+ final byte ERROR_ENCRYPTION_FAILED_BYTE = (byte) 0x07;
+ final String ERROR_ENCRYPTION_FAILED_STRING = "ERROR_ENCRYPTION_FAILED";
+
+ final byte ERROR_SSL_INVALID_DATA_BYTE = (byte) 0x08;
+ final String ERROR_SSL_INVALID_DATA_STRING = "ERROR_SSL_INVALID_DATA";
+
+ final byte ERROR_HANDSHAKE_FAILED_BYTE = (byte) 0x09;
+ final String ERROR_HANDSHAKE_FAILED_STRING = "ERROR_HANDSHAKE_FAILED";
+
+ final byte INVALID_CERT_BYTE = (byte) 0x0A;
+ final String INVALID_CERT_STRING = "INVALID_CERT";
+
+ final byte EXPIRED_CERT_BYTE = (byte) 0x0B;
+ final String EXPIRED_CERT_STRING = "EXPIRED_CERT";
+
+ final byte ERROR_INTERNAL_BYTE = (byte) 0xFF;
+ final String ERROR_INTERNAL_STRING = "ERROR_INTERNAL";
+
+ final byte ERROR_UNKNOWN_INTERNAL_ERROR_BYTE = (byte) 0xFE;
+ final String ERROR_UNKNOWN_INTERNAL_ERROR_STRING = "ERROR_UNKNOWN_INTERNAL_ERROR";
+
+ try {
+ assertNotNull("QueryErrorCode list returned null", list);
+
+ SecurityQueryErrorCode enumSuccess = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SUCCESS_BYTE);
+ SecurityQueryErrorCode enumInvalidQuerySize = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_SIZE_BYTE);
+ SecurityQueryErrorCode enumInvalidQueryID = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_ID_BYTE);
+ SecurityQueryErrorCode enumNotSupported = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_NOT_SUPPORTED_BYTE);
+ SecurityQueryErrorCode enumServiceAlreadyProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_ALREADY_PROTECTED_BYTE);
+ SecurityQueryErrorCode enumServiceNotProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_NOT_PROTECTED_BYTE);
+ SecurityQueryErrorCode enumDecryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_DECRYPTION_FAILED_BYTE);
+ SecurityQueryErrorCode enumEncryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_ENCRYPTION_FAILED_BYTE);
+ SecurityQueryErrorCode enumSSLInvalidData = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SSL_INVALID_DATA_BYTE);
+ SecurityQueryErrorCode enumHandshakeFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_HANDSHAKE_FAILED_BYTE);
+ SecurityQueryErrorCode enumInvalidCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_CERT_BYTE);
+ SecurityQueryErrorCode enumExpiredCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, EXPIRED_CERT_BYTE);
+ SecurityQueryErrorCode enumInternal = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INTERNAL_BYTE);
+ SecurityQueryErrorCode enumUnknownInternalError = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_UNKNOWN_INTERNAL_ERROR_BYTE);
+
+ assertNotNull("Success byte match returned null", enumSuccess);
+ assertNotNull("Invalid Query Size byte match returned null", enumInvalidQuerySize);
+ assertNotNull("Invalid Query ID byte match returned null", enumInvalidQueryID);
+ assertNotNull("Not Supported byte match returned null", enumNotSupported);
+ assertNotNull("Service Already Protected byte match returned null", enumServiceAlreadyProtected);
+ assertNotNull("Service Not Protected byte match returned null", enumServiceNotProtected);
+ assertNotNull("Decryption Failed byte match returned null", enumDecryptionFailed);
+ assertNotNull("Encryption Failed byte match returned null", enumEncryptionFailed);
+ assertNotNull("SSL Invalid Data byte match returned null", enumSSLInvalidData);
+ assertNotNull("Handshake Failed byte match returned null", enumHandshakeFailed);
+ assertNotNull("Invalid Cert byte match returned null", enumInvalidCert);
+ assertNotNull("Expired Cert byte match returned null", enumExpiredCert);
+ assertNotNull("Internal byte match returned null", enumInternal);
+ assertNotNull("Unknown Internal byte match returned null", enumUnknownInternalError);
+
+ enumSuccess = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SUCCESS_STRING);
+ enumInvalidQuerySize = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_SIZE_STRING);
+ enumInvalidQueryID = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INVALID_QUERY_ID_STRING);
+ enumNotSupported = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_NOT_SUPPORTED_STRING);
+ enumServiceAlreadyProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_ALREADY_PROTECTED_STRING);
+ enumServiceNotProtected = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SERVICE_NOT_PROTECTED_STRING);
+ enumDecryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_DECRYPTION_FAILED_STRING);
+ enumEncryptionFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_ENCRYPTION_FAILED_STRING);
+ enumSSLInvalidData = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_SSL_INVALID_DATA_STRING);
+ enumHandshakeFailed = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_HANDSHAKE_FAILED_STRING);
+ enumInvalidCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_CERT_STRING);
+ enumExpiredCert = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, EXPIRED_CERT_STRING);
+ enumInternal = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_INTERNAL_STRING);
+ enumUnknownInternalError = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, ERROR_UNKNOWN_INTERNAL_ERROR_STRING);
+
+ assertNotNull("Success string match returned null", enumSuccess);
+ assertNotNull("Invalid Query Size string match returned null", enumInvalidQuerySize);
+ assertNotNull("Invalid Query ID string match returned null", enumInvalidQueryID);
+ assertNotNull("Not Supported string match returned null", enumNotSupported);
+ assertNotNull("Service Already Protected string match returned null", enumServiceAlreadyProtected);
+ assertNotNull("Service Not Protected string match returned null", enumServiceNotProtected);
+ assertNotNull("Decryption Failed string match returned null", enumDecryptionFailed);
+ assertNotNull("Encryption Failed string match returned null", enumEncryptionFailed);
+ assertNotNull("SSL Invalid Data string match returned null", enumSSLInvalidData);
+ assertNotNull("Handshake Failed string match returned null", enumHandshakeFailed);
+ assertNotNull("Invalid Cert string match returned null", enumInvalidCert);
+ assertNotNull("Expired Cert string match returned null", enumExpiredCert);
+ assertNotNull("Internal string match returned null", enumInternal);
+ assertNotNull("Unknown Internal string match returned null", enumUnknownInternalError);
+ } catch (NullPointerException exception) {
+ fail("Null enum list throws NullPointerException.");
+ }
+ }
+
+ public void testInvalidEnum() {
+ final byte INVALID_BYTE = (byte) 0xAB;
+ final String INVALID_STRING = "Invalid";
+
+ try {
+ SecurityQueryErrorCode enumInvalid = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_BYTE);
+ assertNull("Invalid byte match didn't return null", enumInvalid);
+
+ enumInvalid = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, INVALID_STRING);
+ assertNull("Invalid byte match didn't return null", enumInvalid);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ public void testNullEnum() {
+ try {
+ SecurityQueryErrorCode enumNull = (SecurityQueryErrorCode) SecurityQueryErrorCode.get(list, null);
+ assertNull("Null lookup returns a value", enumNull);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ public void testListEnum() {
+ Vector<SecurityQueryErrorCode> enumTestList = new Vector<>();
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SUCCESS);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_INVALID_QUERY_SIZE);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_INVALID_QUERY_ID);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_NOT_SUPPORTED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SERVICE_ALREADY_PROTECTED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SERVICE_NOT_PROTECTED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_DECRYPTION_FAILED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_ENCRYPTION_FAILED);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_SSL_INVALID_DATA);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_HANDSHAKE_FAILED);
+ enumTestList.add(SecurityQueryErrorCode.INVALID_CERT);
+ enumTestList.add(SecurityQueryErrorCode.EXPIRED_CERT);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_INTERNAL);
+ enumTestList.add(SecurityQueryErrorCode.ERROR_UNKNOWN_INTERNAL_ERROR);
+
+ assertTrue("List does not match enum test list.",
+ list.containsAll(enumTestList) &&
+ enumTestList.containsAll(list));
+
+ SecurityQueryErrorCode[] enumValueArray = SecurityQueryErrorCode.values();
+ SecurityQueryErrorCode[] enumTestArray = {
+ SecurityQueryErrorCode.ERROR_SUCCESS,
+ SecurityQueryErrorCode.ERROR_INVALID_QUERY_SIZE,
+ SecurityQueryErrorCode.ERROR_INVALID_QUERY_ID,
+ SecurityQueryErrorCode.ERROR_NOT_SUPPORTED,
+ SecurityQueryErrorCode.ERROR_SERVICE_ALREADY_PROTECTED,
+ SecurityQueryErrorCode.ERROR_SERVICE_NOT_PROTECTED,
+ SecurityQueryErrorCode.ERROR_DECRYPTION_FAILED,
+ SecurityQueryErrorCode.ERROR_ENCRYPTION_FAILED,
+ SecurityQueryErrorCode.ERROR_SSL_INVALID_DATA,
+ SecurityQueryErrorCode.ERROR_HANDSHAKE_FAILED,
+ SecurityQueryErrorCode.INVALID_CERT,
+ SecurityQueryErrorCode.EXPIRED_CERT,
+ SecurityQueryErrorCode.ERROR_INTERNAL,
+ SecurityQueryErrorCode.ERROR_UNKNOWN_INTERNAL_ERROR
+ };
+ assertTrue("Array does not match enum values array.",
+ Validator.validateQueryErrorCodeArray(enumValueArray, enumTestArray));
+ }
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java
new file mode 100644
index 000000000..4f73f8139
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryIDTests.java
@@ -0,0 +1,91 @@
+package com.smartdevicelink.test.protocol.enums;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+public class SecurityQueryIDTests extends TestCase {
+
+ private Vector<SecurityQueryID> list = SecurityQueryID.getList();
+
+ public void testValidEnums() {
+ final byte[] SEND_HANDSHAKE_DATA_BYTES = {(byte) 0x00, (byte) 0x00, (byte) 0x01};
+ final String SEND_HANDSHAKE_DATA_STRING = "SEND_HANDSHAKE_DATA";
+
+ final byte[] SEND_INTERNAL_ERROR_BYTES = {(byte) 0x00, (byte) 0x00, (byte) 0x02};
+ final String SEND_INTERNAL_ERROR_STRING = "SEND_INTERNAL_ERROR";
+
+ final byte[] INVALID_QUERY_ID_BYTES = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
+ final String INVALID_QUERY_ID_STRING = "INVALID_QUERY_ID";
+
+ try {
+ assertNotNull("QueryID list returned null", list);
+
+ SecurityQueryID enumHandshakeData = (SecurityQueryID) SecurityQueryID.get(list, SEND_HANDSHAKE_DATA_BYTES);
+ SecurityQueryID enumInternalError = (SecurityQueryID) SecurityQueryID.get(list, SEND_INTERNAL_ERROR_BYTES);
+ SecurityQueryID enumInvalidSecurityQueryId = (SecurityQueryID) SecurityQueryID.get(list, INVALID_QUERY_ID_BYTES);
+
+ assertNotNull("Send Handshake Data byte match returned null", enumHandshakeData);
+ assertNotNull("Send Internal Error byte match returned null", enumInternalError);
+ assertNotNull("Send Invalid QueryID byte match returned null", enumInvalidSecurityQueryId);
+
+ enumHandshakeData = (SecurityQueryID) SecurityQueryID.get(list, SEND_HANDSHAKE_DATA_STRING);
+ enumInternalError = (SecurityQueryID) SecurityQueryID.get(list, SEND_INTERNAL_ERROR_STRING);
+ enumInvalidSecurityQueryId = (SecurityQueryID) SecurityQueryID.get(list, INVALID_QUERY_ID_STRING);
+
+ assertNotNull("Send Handshake Data string match returned null", enumHandshakeData);
+ assertNotNull("Send Internal Error string match returned null", enumInternalError);
+ assertNotNull("Send Invalid QueryID string match returned null", enumInvalidSecurityQueryId);
+ } catch(NullPointerException exception) {
+ fail("Null enum list throws NullPointerException.");
+ }
+ }
+
+ public void testInvalidEnum() {
+
+ final byte[] INVALID_BYTE_ARRAY = {(byte) 0xAB, (byte) 0xAB, (byte) 0xAB};
+ final String INVALID_STRING = "Invalid";
+
+ try {
+ SecurityQueryID enumInvalid = (SecurityQueryID) SecurityQueryID.get(list, INVALID_BYTE_ARRAY);
+ assertNull("Invalid byte[] match didn't return null", enumInvalid);
+
+ enumInvalid = (SecurityQueryID) SecurityQueryID.get(list, INVALID_STRING);
+ assertNull("Invalid string match didn't return null", enumInvalid);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ public void testNullEnum() {
+ try {
+ SecurityQueryID enumNull = (SecurityQueryID) SecurityQueryID.get(list, (String) null);
+ assertNull("Null lookup returns a null string value", enumNull);
+
+ enumNull = (SecurityQueryID) SecurityQueryID.get(list, (byte[]) null);
+ assertNull("Null lookup returns a null byte[] value", enumNull);
+ }catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ public void testListEnum() {
+ Vector<SecurityQueryID> enumTestList = new Vector<>();
+ enumTestList.add(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ enumTestList.add(SecurityQueryID.SEND_INTERNAL_ERROR);
+ enumTestList.add(SecurityQueryID.INVALID_QUERY_ID);
+
+ assertTrue("List does not match enum test list.",
+ list.containsAll(enumTestList) &&
+ enumTestList.containsAll(list));
+
+ SecurityQueryID[] enumValueArray = SecurityQueryID.values();
+ SecurityQueryID[] enumTestArray = {SecurityQueryID.SEND_HANDSHAKE_DATA, SecurityQueryID.SEND_INTERNAL_ERROR, SecurityQueryID.INVALID_QUERY_ID};
+ assertTrue("Array does not match enum values array.",
+ Validator.validateQueryIDArray(enumValueArray, enumTestArray));
+ }
+
+}
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java
new file mode 100644
index 000000000..6835da946
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/protocol/enums/SecurityQueryTypeTests.java
@@ -0,0 +1,97 @@
+package com.smartdevicelink.test.protocol.enums;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
+import com.smartdevicelink.test.Validator;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+public class SecurityQueryTypeTests extends TestCase {
+
+ private Vector<SecurityQueryType> list = SecurityQueryType.getList();
+
+ public void testValidEnums() {
+ final byte REQUEST_BYTE = (byte) 0x00;
+ final String REQUEST_STRING = "REQUEST";
+
+ final byte RESPONSE_BYTE = (byte) 0x10;
+ final String RESPONSE_STRING = "RESPONSE";
+
+ final byte NOTIFICATION_BYTE = (byte) 0x20;
+ final String NOTIFICATION_STRING = "NOTIFICATION";
+
+ final byte INVALID_QUERY_TYPE_BYTE = (byte) 0xFF;
+ final String INVALID_QUERY_TYPE_STRING = "INVALID_QUERY_TYPE";
+
+ try {
+ assertNotNull("QueryType list returned null", list);
+
+ SecurityQueryType enumRequest = (SecurityQueryType) SecurityQueryType.get(list, REQUEST_BYTE);
+ SecurityQueryType enumResponse = (SecurityQueryType) SecurityQueryType.get(list, RESPONSE_BYTE);
+ SecurityQueryType enumNotification = (SecurityQueryType) SecurityQueryType.get(list, NOTIFICATION_BYTE);
+ SecurityQueryType enumInvalidSecurityQueryType = (SecurityQueryType) SecurityQueryType.get(list, INVALID_QUERY_TYPE_BYTE);
+
+ assertNotNull("Request byte match returned null", enumRequest);
+ assertNotNull("Response byte match returned null", enumResponse);
+ assertNotNull("Notification byte match returned null", enumNotification);
+ assertNotNull("Invalid Query Type byte match returned null", enumInvalidSecurityQueryType);
+
+ enumRequest = (SecurityQueryType) SecurityQueryType.get(list, REQUEST_STRING);
+ enumResponse = (SecurityQueryType) SecurityQueryType.get(list, RESPONSE_STRING);
+ enumNotification = (SecurityQueryType) SecurityQueryType.get(list, NOTIFICATION_STRING);
+ enumInvalidSecurityQueryType = (SecurityQueryType) SecurityQueryType.get(list, INVALID_QUERY_TYPE_STRING);
+
+ assertNotNull("Request string match returned null", enumRequest);
+ assertNotNull("Response string match returned null", enumResponse);
+ assertNotNull("Notification string match returned null", enumNotification);
+ assertNotNull("Invalid Query string byte match returned null", enumInvalidSecurityQueryType);
+
+
+ }catch (NullPointerException exception) {
+ fail("Null enum list throws NullPointerException.");
+ }
+ }
+
+ public void testInvalidEnum() {
+
+ final byte INVALID_BYTE = (byte) 0xAB;
+ final String INVALID_STRING = "Invalid";
+
+ try {
+ SecurityQueryType enumInvalid = (SecurityQueryType) SecurityQueryType.get(list, INVALID_BYTE);
+ assertNull("Invalid byte match didn't return null", enumInvalid);
+
+ enumInvalid = (SecurityQueryType) SecurityQueryType.get(list, INVALID_STRING);
+ assertNull("Invalid string match didn't return null", enumInvalid);
+ } catch (IllegalArgumentException exception) {
+ fail("Invalid enum throws IllegalArgumentException.");
+ }
+ }
+
+ public void testNullEnum() {
+ try {
+ SecurityQueryType enumNull = (SecurityQueryType) SecurityQueryType.get(list, null);
+ assertNull("Null lookup returns a value", enumNull);
+ } catch (NullPointerException exception) {
+ fail("Null string throws NullPointerException.");
+ }
+ }
+
+ public void testListEnum() {
+ Vector<SecurityQueryType> enumTestList = new Vector<>();
+ enumTestList.add(SecurityQueryType.REQUEST);
+ enumTestList.add(SecurityQueryType.RESPONSE);
+ enumTestList.add(SecurityQueryType.NOTIFICATION);
+ enumTestList.add(SecurityQueryType.INVALID_QUERY_TYPE);
+
+ assertTrue("List does not match enum test list.",
+ list.containsAll(enumTestList) &&
+ enumTestList.containsAll(list));
+
+ SecurityQueryType[] enumValueArray = SecurityQueryType.values();
+ SecurityQueryType[] enumTestArray = {SecurityQueryType.REQUEST, SecurityQueryType.RESPONSE, SecurityQueryType.NOTIFICATION, SecurityQueryType.INVALID_QUERY_TYPE};
+ assertTrue("Array does not match enum values array.",
+ Validator.validateQueryTypeArray(enumValueArray, enumTestArray));
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/protocol/BaseSdlPacket.java b/base/src/main/java/com/smartdevicelink/protocol/BaseSdlPacket.java
index 9694d3f06..fdbba048d 100644
--- a/base/src/main/java/com/smartdevicelink/protocol/BaseSdlPacket.java
+++ b/base/src/main/java/com/smartdevicelink/protocol/BaseSdlPacket.java
@@ -264,10 +264,15 @@ class BaseSdlPacket {
this.priorityCoefficient = priority;
}
+ @Deprecated
public int getPrioirtyCoefficient() {
return this.priorityCoefficient;
}
+ public int getPriorityCoefficient() {
+ return this.priorityCoefficient;
+ }
+
public void setTransportRecord(TransportRecord transportRecord) {
this.transportRecord = transportRecord;
}
diff --git a/base/src/main/java/com/smartdevicelink/protocol/ProtocolMessage.java b/base/src/main/java/com/smartdevicelink/protocol/ProtocolMessage.java
index 8a1968f36..9e2ab38d0 100644
--- a/base/src/main/java/com/smartdevicelink/protocol/ProtocolMessage.java
+++ b/base/src/main/java/com/smartdevicelink/protocol/ProtocolMessage.java
@@ -182,7 +182,12 @@ public class ProtocolMessage {
this.priorityCoefficient = priority;
}
+ @Deprecated
public int getPrioirtyCoefficient() {
return this.priorityCoefficient;
}
+
+ public int getPriorityCoefficient() {
+ return this.priorityCoefficient;
+ }
} // end-class \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java b/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
index 14222a548..e80255d1b 100644
--- a/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
+++ b/base/src/main/java/com/smartdevicelink/protocol/SdlProtocolBase.java
@@ -572,11 +572,7 @@ public class SdlProtocolBase {
if (sessionType.eq(SessionType.CONTROL)) {
final byte[] secureData = protocolMsg.getData().clone();
data = new byte[headerSize + secureData.length];
-
- final BinaryFrameHeader binFrameHeader =
- SdlPacketFactory.createBinaryFrameHeader(protocolMsg.getRPCType(), protocolMsg.getFunctionID(), protocolMsg.getCorrID(), 0);
- System.arraycopy(binFrameHeader.assembleHeaderBytes(), 0, data, 0, headerSize);
- System.arraycopy(secureData, 0, data, headerSize, secureData.length);
+ System.arraycopy(secureData, 0, data, 0, secureData.length);
} else if (protocolMsg.getBulkData() != null) {
data = new byte[12 + protocolMsg.getJsonSize() + protocolMsg.getBulkData().length];
sessionType = SessionType.BULK_DATA;
diff --git a/base/src/main/java/com/smartdevicelink/protocol/SecurityQueryPayload.java b/base/src/main/java/com/smartdevicelink/protocol/SecurityQueryPayload.java
new file mode 100644
index 000000000..c7bc1326d
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/protocol/SecurityQueryPayload.java
@@ -0,0 +1,157 @@
+package com.smartdevicelink.protocol;
+
+import androidx.annotation.RestrictTo;
+
+import com.smartdevicelink.protocol.enums.SecurityQueryErrorCode;
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
+import com.smartdevicelink.util.BitConverter;
+import com.smartdevicelink.util.DebugTool;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SecurityQueryPayload {
+ private static final String TAG = "BinaryQueryHeader";
+
+ private SecurityQueryType _securityQueryType;
+ private SecurityQueryID _securityQueryID;
+ private int _correlationID;
+ private int _jsonSize;
+ private SecurityQueryErrorCode _errorCode;
+
+ private byte[] _jsonData = null;
+ private byte[] _bulkData = null;
+
+ private static final int SECURITY_QUERY_HEADER_SIZE = 12;
+
+ public SecurityQueryPayload() {
+ }
+
+ public static SecurityQueryPayload parseBinaryQueryHeader(byte[] binHeader) {
+ if (binHeader == null || binHeader.length < SECURITY_QUERY_HEADER_SIZE) {
+ DebugTool.logError(TAG, "Security Payload error: not enough data to form a Security Query Header. Data length: " + (binHeader != null ? binHeader.length : "null"));
+ return null;
+ }
+
+ SecurityQueryPayload msg = new SecurityQueryPayload();
+
+ //Set QueryType from the first 8 bits
+ byte QUERY_Type = (byte) (binHeader[0]);
+ msg.setQueryType(SecurityQueryType.valueOf(QUERY_Type));
+
+ //Set queryID from the last 24 bits of the first 32 bits
+ byte[] _queryID = new byte[3];
+ System.arraycopy(binHeader, 1, _queryID, 0, 3);
+ msg.setQueryID(SecurityQueryID.valueOf(_queryID));
+
+ //set correlationID from the 32 bits after the first 32 bits
+ int corrID = BitConverter.intFromByteArray(binHeader, 4);
+ msg.setCorrelationID(corrID);
+
+ //set jsonSize from the last 32 bits after the first 64 bits
+ int _jsonSize = BitConverter.intFromByteArray(binHeader, 8);
+ msg.setJsonSize(_jsonSize);
+
+ //If we get an error message we want the error code from the last 8 bits
+ if (msg.getQueryType() == SecurityQueryType.NOTIFICATION && msg.getQueryID() == SecurityQueryID.SEND_INTERNAL_ERROR) {
+ msg.setErrorCode(SecurityQueryErrorCode.valueOf(binHeader[binHeader.length - 1]));
+ }
+
+ try {
+ //Get the JsonData after the header (after 96 bits) based on the jsonData size
+ if (_jsonSize > 0 && _jsonSize <= (binHeader.length - SECURITY_QUERY_HEADER_SIZE)) {
+ byte[] _jsonData = new byte[_jsonSize];
+ System.arraycopy(binHeader, SECURITY_QUERY_HEADER_SIZE, _jsonData, 0, _jsonSize);
+ msg.setJsonData(_jsonData);
+ }
+
+ //Get the binaryData after the header (after 96 bits) and the jsonData size
+ if (binHeader.length - _jsonSize - SECURITY_QUERY_HEADER_SIZE > 0) {
+ byte[] _bulkData;
+ if (msg.getQueryType() == SecurityQueryType.NOTIFICATION && msg.getQueryID() == SecurityQueryID.SEND_INTERNAL_ERROR) {
+ _bulkData = new byte[binHeader.length - _jsonSize - SECURITY_QUERY_HEADER_SIZE - 1];
+ } else {
+ _bulkData = new byte[binHeader.length - _jsonSize - SECURITY_QUERY_HEADER_SIZE];
+ }
+ System.arraycopy(binHeader, SECURITY_QUERY_HEADER_SIZE + _jsonSize, _bulkData, 0, _bulkData.length);
+ msg.setBulkData(_bulkData);
+ }
+
+ } catch (OutOfMemoryError | ArrayIndexOutOfBoundsException e) {
+ DebugTool.logError(TAG, "Unable to process data to form header");
+ return null;
+ }
+
+ return msg;
+ }
+
+ public byte[] assembleHeaderBytes() {
+ // From the properties, create a data buffer
+ // Query Type - first 8 bits
+ // Query ID - next 24 bits
+ // Sequence Number - next 32 bits
+ // JSON size - next 32 bits
+ byte[] ret = new byte[SECURITY_QUERY_HEADER_SIZE];
+ ret[0] = _securityQueryType.getValue();
+ System.arraycopy(_securityQueryID.getValue(), 0, ret, 1, 3);
+ System.arraycopy(BitConverter.intToByteArray(_correlationID), 0, ret, 4, 4);
+ System.arraycopy(BitConverter.intToByteArray(_jsonSize), 0, ret, 8, 4);
+ return ret;
+ }
+
+ public SecurityQueryType getQueryType() {
+ return _securityQueryType;
+ }
+
+ public void setQueryType(SecurityQueryType _securityQueryType) {
+ this._securityQueryType = _securityQueryType;
+ }
+
+ public SecurityQueryID getQueryID() {
+ return _securityQueryID;
+ }
+
+ public void setQueryID(SecurityQueryID _securityQueryID) {
+ this._securityQueryID = _securityQueryID;
+ }
+
+ public int getCorrelationID() {
+ return _correlationID;
+ }
+
+ public void setCorrelationID(int _correlationID) {
+ this._correlationID = _correlationID;
+ }
+
+ public int getJsonSize() {
+ return _jsonSize;
+ }
+
+ public void setJsonSize(int _jsonSize) {
+ this._jsonSize = _jsonSize;
+ }
+
+ public SecurityQueryErrorCode getErrorCode() {
+ return _errorCode;
+ }
+
+ public void setErrorCode(SecurityQueryErrorCode _errorCode) {
+ this._errorCode = _errorCode;
+ }
+
+ public byte[] getJsonData() {
+ return _jsonData;
+ }
+
+ public void setJsonData(byte[] _jsonData) {
+ this._jsonData = new byte[this._jsonSize];
+ System.arraycopy(_jsonData, 0, this._jsonData, 0, _jsonSize);
+ }
+
+ public byte[] getBulkData() {
+ return _bulkData;
+ }
+
+ public void setBulkData(byte[] _bulkData) {
+ this._bulkData = _bulkData;
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryErrorCode.java b/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryErrorCode.java
new file mode 100644
index 000000000..5601271d3
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryErrorCode.java
@@ -0,0 +1,61 @@
+package com.smartdevicelink.protocol.enums;
+
+import androidx.annotation.RestrictTo;
+
+import com.smartdevicelink.util.ByteEnumer;
+
+import java.util.Vector;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SecurityQueryErrorCode extends ByteEnumer {
+
+ private static final Vector<SecurityQueryErrorCode> theList = new Vector<>();
+
+ public static Vector<SecurityQueryErrorCode> getList() {
+ return theList;
+ }
+
+ protected SecurityQueryErrorCode(byte value, String name) {
+ super(value, name);
+ }
+
+ public final static SecurityQueryErrorCode ERROR_SUCCESS = new SecurityQueryErrorCode((byte) 0x00, "ERROR_SUCCESS");
+ public final static SecurityQueryErrorCode ERROR_INVALID_QUERY_SIZE = new SecurityQueryErrorCode((byte) 0x01, "ERROR_INVALID_QUERY_SIZE");
+ public final static SecurityQueryErrorCode ERROR_INVALID_QUERY_ID = new SecurityQueryErrorCode((byte) 0x02, "ERROR_INVALID_QUERY_ID");
+ public final static SecurityQueryErrorCode ERROR_NOT_SUPPORTED = new SecurityQueryErrorCode((byte) 0x03, "ERROR_NOT_SUPPORTED");
+ public final static SecurityQueryErrorCode ERROR_SERVICE_ALREADY_PROTECTED = new SecurityQueryErrorCode((byte) 0x04, "ERROR_SERVICE_ALREADY_PROTECTED");
+ public final static SecurityQueryErrorCode ERROR_SERVICE_NOT_PROTECTED = new SecurityQueryErrorCode((byte) 0x05, "ERROR_SERVICE_NOT_PROTECTED");
+ public final static SecurityQueryErrorCode ERROR_DECRYPTION_FAILED = new SecurityQueryErrorCode((byte) 0x06, "ERROR_DECRYPTION_FAILED");
+ public final static SecurityQueryErrorCode ERROR_ENCRYPTION_FAILED = new SecurityQueryErrorCode((byte) 0x07, "ERROR_ENCRYPTION_FAILED");
+ public final static SecurityQueryErrorCode ERROR_SSL_INVALID_DATA = new SecurityQueryErrorCode((byte) 0x08, "ERROR_SSL_INVALID_DATA");
+ public final static SecurityQueryErrorCode ERROR_HANDSHAKE_FAILED = new SecurityQueryErrorCode((byte) 0x09, "ERROR_HANDSHAKE_FAILED");
+ public final static SecurityQueryErrorCode INVALID_CERT = new SecurityQueryErrorCode((byte) 0x0A, "INVALID_CERT");
+ public final static SecurityQueryErrorCode EXPIRED_CERT = new SecurityQueryErrorCode((byte) 0x0B, "EXPIRED_CERT");
+ public final static SecurityQueryErrorCode ERROR_INTERNAL = new SecurityQueryErrorCode((byte) 0xFF, "ERROR_INTERNAL");
+ public final static SecurityQueryErrorCode ERROR_UNKNOWN_INTERNAL_ERROR = new SecurityQueryErrorCode((byte) 0xFE, "ERROR_UNKNOWN_INTERNAL_ERROR");
+
+ static {
+ theList.addElement(ERROR_SUCCESS);
+ theList.addElement(ERROR_INVALID_QUERY_SIZE);
+ theList.addElement(ERROR_INVALID_QUERY_ID);
+ theList.addElement(ERROR_NOT_SUPPORTED);
+ theList.addElement(ERROR_SERVICE_ALREADY_PROTECTED);
+ theList.addElement(ERROR_SERVICE_NOT_PROTECTED);
+ theList.addElement(ERROR_DECRYPTION_FAILED);
+ theList.addElement(ERROR_ENCRYPTION_FAILED);
+ theList.addElement(ERROR_SSL_INVALID_DATA);
+ theList.addElement(ERROR_HANDSHAKE_FAILED);
+ theList.addElement(INVALID_CERT);
+ theList.addElement(EXPIRED_CERT);
+ theList.addElement(ERROR_INTERNAL);
+ theList.addElement(ERROR_UNKNOWN_INTERNAL_ERROR);
+ }
+
+ public static SecurityQueryErrorCode valueOf(byte passedByte) {
+ return (SecurityQueryErrorCode) get(theList, passedByte);
+ }
+
+ public static SecurityQueryErrorCode[] values() {
+ return theList.toArray(new SecurityQueryErrorCode[theList.size()]);
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryID.java b/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryID.java
new file mode 100644
index 000000000..c1b799ec9
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryID.java
@@ -0,0 +1,105 @@
+package com.smartdevicelink.protocol.enums;
+
+import androidx.annotation.RestrictTo;
+
+import com.smartdevicelink.util.BitConverter;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Objects;
+import java.util.Vector;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SecurityQueryID {
+
+ private static final Vector<SecurityQueryID> theList = new Vector<>();
+
+ public static Vector<SecurityQueryID> getList() {
+ return theList;
+ }
+
+ private static final byte[] sendHandshakeDataByteArray = {(byte) 0x00, (byte) 0x00, (byte) 0x01};
+ private static final byte[] sendInternalErrorByteArray = {(byte) 0x00, (byte) 0x00, (byte) 0x02};
+ private static final byte[] invalidQueryIdByteArray = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
+ public final static SecurityQueryID SEND_HANDSHAKE_DATA = new SecurityQueryID(sendHandshakeDataByteArray, "SEND_HANDSHAKE_DATA");
+ public final static SecurityQueryID SEND_INTERNAL_ERROR = new SecurityQueryID(sendInternalErrorByteArray, "SEND_INTERNAL_ERROR");
+ public final static SecurityQueryID INVALID_QUERY_ID = new SecurityQueryID(invalidQueryIdByteArray, "INVALID_QUERY_ID");
+
+ static {
+ theList.addElement(SEND_HANDSHAKE_DATA);
+ theList.addElement(SEND_INTERNAL_ERROR);
+ theList.addElement(INVALID_QUERY_ID);
+ }
+
+ protected SecurityQueryID(byte[] value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ private final byte[] value;
+ private final String name;
+
+ public byte[] getValue() {
+ return value;
+ }
+
+ public int getIntValue() {
+ byte[] copy = new byte[4];
+ System.arraycopy(value, 0, copy, 1, 3);
+ return BitConverter.intFromByteArray(copy, 0);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean equals(SecurityQueryID other) {
+ return Objects.equals(name, other.getName());
+ }
+
+ public boolean eq(SecurityQueryID other) {
+ return equals(other);
+ }
+
+ public byte[] value() {
+ return value;
+ }
+
+ public static SecurityQueryID get(Vector<?> theList, byte[] value) {
+ Enumeration<?> enumer = theList.elements();
+ while (enumer.hasMoreElements()) {
+ try {
+ SecurityQueryID current = (SecurityQueryID) enumer.nextElement();
+ if (Arrays.equals(current.getValue(), value)) {
+ return current;
+ }
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public static SecurityQueryID get(Vector<?> theList, String name) {
+ Enumeration<?> enumer = theList.elements();
+ while (enumer.hasMoreElements()) {
+ try {
+ SecurityQueryID current = (SecurityQueryID) enumer.nextElement();
+ if (current.getName().equals(name)) {
+ return current;
+ }
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public static SecurityQueryID valueOf(byte[] passedByteArray) {
+ return (SecurityQueryID) get(theList, passedByteArray);
+ }
+
+ public static SecurityQueryID[] values() {
+ return theList.toArray(new SecurityQueryID[theList.size()]);
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryType.java b/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryType.java
new file mode 100644
index 000000000..bb021e79c
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/protocol/enums/SecurityQueryType.java
@@ -0,0 +1,41 @@
+package com.smartdevicelink.protocol.enums;
+
+import androidx.annotation.RestrictTo;
+
+import com.smartdevicelink.util.ByteEnumer;
+
+import java.util.Vector;
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SecurityQueryType extends ByteEnumer {
+
+ private static final Vector<SecurityQueryType> theList = new Vector<>();
+
+ public static Vector<SecurityQueryType> getList() {
+ return theList;
+ }
+
+ protected SecurityQueryType(byte value, String name) {
+ super(value, name);
+ }
+
+ public final static SecurityQueryType REQUEST = new SecurityQueryType((byte) 0x00, "REQUEST");
+ public final static SecurityQueryType RESPONSE = new SecurityQueryType((byte) 0x10, "RESPONSE");
+ public final static SecurityQueryType NOTIFICATION = new SecurityQueryType((byte) 0x20, "NOTIFICATION");
+ public final static SecurityQueryType INVALID_QUERY_TYPE = new SecurityQueryType((byte) 0xFF, "INVALID_QUERY_TYPE");
+
+ static {
+ theList.addElement(REQUEST);
+ theList.addElement(RESPONSE);
+ theList.addElement(NOTIFICATION);
+ theList.addElement(INVALID_QUERY_TYPE);
+ }
+
+ public static SecurityQueryType valueOf(byte passedByte) {
+ return (SecurityQueryType) get(theList, passedByte);
+ }
+
+ public static SecurityQueryType[] values() {
+ return theList.toArray(new SecurityQueryType[theList.size()]);
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java b/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java
index 73c6bf0b3..d68e9cd20 100644
--- a/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java
+++ b/base/src/main/java/com/smartdevicelink/session/BaseSdlSession.java
@@ -37,12 +37,15 @@ import androidx.annotation.RestrictTo;
import com.smartdevicelink.exception.SdlException;
import com.smartdevicelink.managers.lifecycle.RpcConverter;
+import com.smartdevicelink.protocol.SecurityQueryPayload;
import com.smartdevicelink.protocol.ISdlProtocol;
import com.smartdevicelink.protocol.ISdlServiceListener;
import com.smartdevicelink.protocol.ProtocolMessage;
import com.smartdevicelink.protocol.SdlPacket;
import com.smartdevicelink.protocol.SdlProtocolBase;
import com.smartdevicelink.protocol.enums.ControlFrameTags;
+import com.smartdevicelink.protocol.enums.SecurityQueryID;
+import com.smartdevicelink.protocol.enums.SecurityQueryType;
import com.smartdevicelink.protocol.enums.SessionType;
import com.smartdevicelink.proxy.RPCMessage;
import com.smartdevicelink.proxy.rpc.VehicleType;
@@ -188,21 +191,73 @@ public abstract class BaseSdlSession implements ISdlProtocol, ISecurityInitializ
protected void processControlService(ProtocolMessage msg) {
- if (sdlSecurity == null)
+ if (sdlSecurity == null || msg.getData() == null)
return;
+
+
+ if (msg.getData().length < 12) {
+ DebugTool.logError(TAG, "Security message is malformed, less than 12 bytes. It does not have a security payload header.");
+ }
+ // Check the client's message header for any internal errors
+ // NOTE: Before Core v8.0.0, all these messages will be notifications. In Core v8.0.0 and later, received messages will have the proper query type. Therefore, we cannot do things based only on the query type being request or response.
+ SecurityQueryPayload receivedHeader = SecurityQueryPayload.parseBinaryQueryHeader(msg.getData().clone());
+ if (receivedHeader == null) {
+ DebugTool.logError(TAG, "Module Security Query could not convert to object.");
+ return;
+ }
+
int iLen = msg.getData().length - 12;
byte[] data = new byte[iLen];
System.arraycopy(msg.getData(), 12, data, 0, iLen);
byte[] dataToRead = new byte[4096];
- Integer iNumBytes = sdlSecurity.runHandshake(data, dataToRead);
+ Integer iNumBytes = null;
- if (iNumBytes == null || iNumBytes <= 0)
+ // If the query is of type `Notification` and the id represents a client internal error, we abort the response message and the encryptionManager will not be in state ready.
+ if (receivedHeader.getQueryID() == SecurityQueryID.SEND_INTERNAL_ERROR
+ && receivedHeader.getQueryType() == SecurityQueryType.NOTIFICATION) {
+ if (receivedHeader.getErrorCode() != null) {
+ DebugTool.logError(TAG, "Security Query module internal error: " + receivedHeader.getErrorCode().getName());
+ } else {
+ DebugTool.logError(TAG, "Security Query module error: No information provided");
+ }
return;
+ }
+
+ if (receivedHeader.getQueryID() != SecurityQueryID.SEND_HANDSHAKE_DATA) {
+ DebugTool.logError(TAG, "Security Query module error: Message is not a SEND_HANDSHAKE_DATA REQUEST");
+ return;
+ }
+
+ if (receivedHeader.getQueryType() == SecurityQueryType.RESPONSE) {
+ DebugTool.logError(TAG, "Security Query module error: Message is a response, which is not supported");
+ return;
+ }
+
+ iNumBytes = sdlSecurity.runHandshake(data, dataToRead);
+
+ // Assemble a security query payload header for our response
+ SecurityQueryPayload responseHeader = new SecurityQueryPayload();
+
+ if (iNumBytes == null || iNumBytes <= 0) {
+ DebugTool.logError(TAG, "Internal Error processing control service");
+
+ responseHeader.setQueryID(SecurityQueryID.SEND_INTERNAL_ERROR);
+ responseHeader.setQueryType(SecurityQueryType.NOTIFICATION);
+ responseHeader.setCorrelationID(msg.getCorrID());
+ responseHeader.setJsonSize(0);
+ } else {
+ responseHeader.setQueryID(SecurityQueryID.SEND_HANDSHAKE_DATA);
+ responseHeader.setQueryType(SecurityQueryType.RESPONSE);
+ responseHeader.setCorrelationID(msg.getCorrID());
+ responseHeader.setJsonSize(0);
+ }
+
+ byte[] returnBytes = new byte[iNumBytes + 12];
+ System.arraycopy(responseHeader.assembleHeaderBytes(), 0, returnBytes, 0, 12);
+ System.arraycopy(dataToRead, 0, returnBytes, 12, iNumBytes);
- byte[] returnBytes = new byte[iNumBytes];
- System.arraycopy(dataToRead, 0, returnBytes, 0, iNumBytes);
ProtocolMessage protocolMessage = new ProtocolMessage();
protocolMessage.setSessionType(SessionType.CONTROL);
protocolMessage.setData(returnBytes);