From c7e692d9343dfe51ece2a87ba3e59fa2a0f4aed9 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Tue, 23 Jan 2024 13:45:02 +0100 Subject: [PATCH 01/12] FDP-1815: Added hash validation Signed-off-by: Luciano Favoroso --- application/build.gradle.kts | 2 + .../configuration/CoapClientConfiguration.kt | 3 +- .../configuration/SimulatorProperties.kt | 1 + .../simulator/data/entity/PreSharedKey.kt | 2 +- .../simulator/response/PskKeyExtractor.kt | 8 ++-- .../simulator/response/ResponseHandler.kt | 28 ++--------- .../response/command/PskCommandHandler.kt | 47 +++++++++++++++++++ .../exception/PskHashNotValidException.kt | 7 +++ .../src/main/resources/application-dev.yaml | 1 + .../resources/db/migration/V2__secret.sql | 5 ++ settings.gradle.kts | 2 + 11 files changed, 76 insertions(+), 30 deletions(-) create mode 100644 application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt create mode 100644 application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt create mode 100644 application/src/main/resources/db/migration/V2__secret.sql diff --git a/application/build.gradle.kts b/application/build.gradle.kts index df55c59..f204f77 100644 --- a/application/build.gradle.kts +++ b/application/build.gradle.kts @@ -17,6 +17,8 @@ dependencies { implementation(libs.bundles.data) implementation(libs.logging) + implementation(libs.commonsCodec) + implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor") implementation("jakarta.xml.bind:jakarta.xml.bind-api") diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CoapClientConfiguration.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CoapClientConfiguration.kt index 6ebe814..ff0538f 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CoapClientConfiguration.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CoapClientConfiguration.kt @@ -4,7 +4,6 @@ package org.gxf.crestdevicesimulator.configuration -import org.eclipse.californium.elements.config.Configuration import org.gxf.crestdevicesimulator.simulator.data.entity.PreSharedKey import org.gxf.crestdevicesimulator.simulator.data.repository.PskRepository import org.springframework.context.annotation.Bean @@ -19,7 +18,7 @@ class CoapClientConfiguration(private val simulatorProperties: SimulatorProperti val savedKey = pskRepository.findById(simulatorProperties.pskIdentity) if (savedKey.isEmpty) { - val initialPreSharedKey = PreSharedKey(simulatorProperties.pskIdentity, simulatorProperties.pskKey) + val initialPreSharedKey = PreSharedKey(simulatorProperties.pskIdentity, simulatorProperties.pskKey, simulatorProperties.pskSecret) pskRepository.save(initialPreSharedKey) store.key = simulatorProperties.pskKey } else { diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/SimulatorProperties.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/SimulatorProperties.kt index 9778390..57da455 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/SimulatorProperties.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/SimulatorProperties.kt @@ -12,6 +12,7 @@ class SimulatorProperties( val uri: URI, val pskIdentity: String, val pskKey: String, + val pskSecret: String, val messagePath: String, val produceValidCbor: Boolean, ) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/data/entity/PreSharedKey.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/data/entity/PreSharedKey.kt index 28b87e1..a7203bf 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/data/entity/PreSharedKey.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/data/entity/PreSharedKey.kt @@ -8,4 +8,4 @@ import jakarta.persistence.Entity import jakarta.persistence.Id @Entity -class PreSharedKey(@Id val identity: String, var preSharedKey: String) +class PreSharedKey(@Id val identity: String, var preSharedKey: String, var secret: String) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt index 0e213af..164ae27 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt @@ -9,10 +9,12 @@ import org.springframework.stereotype.Component @Component class PskKeyExtractor { - private val pskCommandVerificationRegex = "PSK:[a-zA-Z0-9]{16};PSK:[a-zA-Z0-9]{16}SET".toRegex() - private val pskExtractorRegex = "(?<=PSK:)[a-zA-Z0-9]{16}".toRegex() + private val pskCommandVerificationRegex = "PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64};PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64}SET!".toRegex() + private val pskKeyHashSplitterRegex = "(?<=PSK:)([a-zA-Z0-9]{16})[a-zA-Z0-9]{64}".toRegex() fun hasPskCommand(command: String) = pskCommandVerificationRegex.matches(command) - fun extractKeyFromCommand(command: String) = pskExtractorRegex.findAll(command).first().value + fun extractKeyFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).first().value + + fun extractHashFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).last().value } diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt index 0837b79..c5811ff 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt @@ -4,39 +4,19 @@ package org.gxf.crestdevicesimulator.simulator.response -import io.github.oshai.kotlinlogging.KotlinLogging import org.eclipse.californium.core.CoapResponse -import org.gxf.crestdevicesimulator.configuration.AdvancedSingleIdentityPskStore -import org.gxf.crestdevicesimulator.configuration.SimulatorProperties -import org.gxf.crestdevicesimulator.simulator.data.repository.PskRepository +import org.gxf.crestdevicesimulator.simulator.response.command.PskCommandHandler import org.springframework.stereotype.Component @Component -class ResponseHandler(private val simulatorProperties: SimulatorProperties, - private val pskRepository: PskRepository, - private val pskKeyExtractor: PskKeyExtractor, - private val pskStore: AdvancedSingleIdentityPskStore) { - - private val logger = KotlinLogging.logger {} +class ResponseHandler(private val pskCommandHandler: PskCommandHandler, + private val pskKeyExtractor: PskKeyExtractor) { fun handleResponse(response: CoapResponse) { val body = String(response.payload) if (pskKeyExtractor.hasPskCommand(body)) { - val newPsk = pskKeyExtractor.extractKeyFromCommand(body) - handlePskChange(newPsk) - } - } - - private fun handlePskChange(newPsk: String) { - val current = pskRepository.findById(simulatorProperties.pskIdentity) - if (current.isEmpty) { - logger.error { "No psk for identity: ${simulatorProperties.pskIdentity}" } + pskCommandHandler.handlePskChange(body) } - - logger.info { "Setting psk $newPsk for ${simulatorProperties.pskIdentity}" } - - pskRepository.save(current.get().apply { preSharedKey = newPsk }) - pskStore.key = newPsk } } diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt new file mode 100644 index 0000000..d28b418 --- /dev/null +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Contributors to the GXF project +// +// SPDX-License-Identifier: Apache-2.0 + +package org.gxf.crestdevicesimulator.simulator.response.command + +import io.github.oshai.kotlinlogging.KotlinLogging +import org.apache.commons.codec.digest.DigestUtils +import org.gxf.crestdevicesimulator.configuration.AdvancedSingleIdentityPskStore +import org.gxf.crestdevicesimulator.configuration.SimulatorProperties +import org.gxf.crestdevicesimulator.simulator.data.repository.PskRepository +import org.gxf.crestdevicesimulator.simulator.response.PskKeyExtractor +import org.gxf.crestdevicesimulator.simulator.response.command.exception.PskHashNotValidException +import org.springframework.stereotype.Service + +@Service +class PskCommandHandler(private val pskRepository: PskRepository, + private val simulatorProperties: SimulatorProperties, + private val pskKeyExtractor: PskKeyExtractor, + private val pskStore: AdvancedSingleIdentityPskStore) { + + private val logger = KotlinLogging.logger {} + + fun handlePskChange(body: String) { + val newPsk = pskKeyExtractor.extractKeyFromCommand(body) + val hash = pskKeyExtractor.extractHashFromCommand(body) + + val preSharedKeyOptional = pskRepository.findById(simulatorProperties.pskIdentity) + + if (preSharedKeyOptional.isEmpty) { + logger.error { "No psk for identity: ${simulatorProperties.pskIdentity}" } + } + + logger.info { "Validating hash for identity: ${simulatorProperties.pskIdentity}" } + + val preSharedKey = preSharedKeyOptional.get() + val secret = preSharedKey.secret + val expectedHash = DigestUtils.sha256Hex("${secret}${newPsk}") + + if (expectedHash != hash) { + throw PskHashNotValidException() + } + + pskRepository.save(preSharedKey.apply { this.preSharedKey = newPsk }) + pskStore.key = newPsk + } +} diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt new file mode 100644 index 0000000..33be120 --- /dev/null +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: Contributors to the GXF project +// +// SPDX-License-Identifier: Apache-2.0 + +package org.gxf.crestdevicesimulator.simulator.response.command.exception + +class PskHashNotValidException : Exception() \ No newline at end of file diff --git a/application/src/main/resources/application-dev.yaml b/application/src/main/resources/application-dev.yaml index 6bde69f..44c9cde 100644 --- a/application/src/main/resources/application-dev.yaml +++ b/application/src/main/resources/application-dev.yaml @@ -20,3 +20,4 @@ simulator: # pskKey: coaps_secret_key psk-identity: 867787050253370 psk-key: ABCDEFGHIJKLMNOP + psk-secret: "123456" diff --git a/application/src/main/resources/db/migration/V2__secret.sql b/application/src/main/resources/db/migration/V2__secret.sql new file mode 100644 index 0000000..13dfd0a --- /dev/null +++ b/application/src/main/resources/db/migration/V2__secret.sql @@ -0,0 +1,5 @@ +-- No production data was set before this change so we can drop all existing data +delete from pre_shared_key; + +alter table pre_shared_key + add column secret varchar(255) not null; diff --git a/settings.gradle.kts b/settings.gradle.kts index c89542e..0bf366b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,6 +19,8 @@ dependencyResolutionManagement { bundle("data", listOf("postgresql", "flyway")) library("logging", "io.github.oshai", "kotlin-logging-jvm").version("6.0.1") + + library("commonsCodec", "commons-codec", "commons-codec").version("1.16.0") } create("integrationTestLibs") { library("h2", "com.h2database", "h2").version("2.2.224") From ffe342241d91691123fb6dfe1dbd57ecc0e38b3b Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Thu, 25 Jan 2024 14:11:08 +0100 Subject: [PATCH 02/12] FDP-1815: changed hash validation Signed-off-by: Luciano Favoroso --- .../simulator/response/PskKeyExtractor.kt | 13 ++++++++++--- .../src/test/kotlin/PreSharedKeyKeyExtractorTest.kt | 7 ++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt index 164ae27..6dbc0e4 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt @@ -10,11 +10,18 @@ import org.springframework.stereotype.Component class PskKeyExtractor { private val pskCommandVerificationRegex = "PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64};PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64}SET!".toRegex() - private val pskKeyHashSplitterRegex = "(?<=PSK:)([a-zA-Z0-9]{16})[a-zA-Z0-9]{64}".toRegex() + + /** + * Regex to split a valid PSK set command in 3 groups + * Group 0 containing everything after PSK: this includes the key and hash + * Group 1 containing the next 16 chars after PSK: this is only the key + * Group 2 containing the next 64 chars after the key this is only the hash + */ + private val pskKeyHashSplitterRegex = "(?<=PSK:)([a-zA-Z0-9]{16})([a-zA-Z0-9]{64})".toRegex() fun hasPskCommand(command: String) = pskCommandVerificationRegex.matches(command) - fun extractKeyFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).first().value + fun extractKeyFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).first().groups[1]!!.value - fun extractHashFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).last().value + fun extractHashFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).first().groups[2]!!.value } diff --git a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt b/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt index 358bd69..7531d7f 100644 --- a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt +++ b/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt @@ -5,10 +5,11 @@ import org.junit.jupiter.api.Test class PreSharedKeyKeyExtractorTest { private val pskKeyExtractor = PskKeyExtractor() + private val testHash = "1234567890123456123456789012345612345678901234561234567890123456" - private val validPskCommand = "PSK:1234567891234567;PSK:1234567891234567SET" - private val validPskCommandWithKeyWordsInKey = "PSK:PSKaSET1PSKd2SET;PSK:PSKaSET1PSKd2SETSET" - private val invalidKeySizePskCommand = "PSK:1234;PSK:1234SET" + private val validPskCommand = "PSK:1234567891234567${testHash};PSK:1234567891234567${testHash}SET!" + private val validPskCommandWithKeyWordsInKey = "PSK:PSKaSET1PSKd2SET${testHash};PSK:PSKaSET1PSKd2SET${testHash}SET!" + private val invalidKeySizePskCommand = "PSK:1234${testHash};PSK:1234${testHash}SET!" private val notPskCommand = "NoPskCommandInThisString" From 0299bd086a90aae6c14364a2283787daa78f8300 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Thu, 25 Jan 2024 14:16:35 +0100 Subject: [PATCH 03/12] FDP-1815: newline Signed-off-by: Luciano Favoroso --- .../response/command/exception/PskHashNotValidException.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt index 33be120..3d56845 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt @@ -4,4 +4,4 @@ package org.gxf.crestdevicesimulator.simulator.response.command.exception -class PskHashNotValidException : Exception() \ No newline at end of file +class PskHashNotValidException : Exception() From 89ce72ddb76b548d9bdf3e12cf6dfad840c9d5c4 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Thu, 25 Jan 2024 16:07:19 +0100 Subject: [PATCH 04/12] FDP-1815: fix test Signed-off-by: Luciano Favoroso --- application/src/integrationTest/resources/application.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/integrationTest/resources/application.yaml b/application/src/integrationTest/resources/application.yaml index 7c92dbb..f4a839e 100644 --- a/application/src/integrationTest/resources/application.yaml +++ b/application/src/integrationTest/resources/application.yaml @@ -23,3 +23,4 @@ simulator: # pskKey: coaps_secret_key psk-identity: 867787050253370 psk-key: ABCDEFGHIJKLMNOP + psk-secret: "123456" From 4a07c27ae176708d8eaabf692e93de24f11b7781 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Thu, 25 Jan 2024 16:33:15 +0100 Subject: [PATCH 05/12] FDP-1815: clean up Signed-off-by: Luciano Favoroso --- .../simulator/response/PskKeyExtractor.kt | 2 +- application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt index 6dbc0e4..3301291 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component @Component class PskKeyExtractor { - private val pskCommandVerificationRegex = "PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64};PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64}SET!".toRegex() + private val pskCommandVerificationRegex = "!PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64};PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64}SET".toRegex() /** * Regex to split a valid PSK set command in 3 groups diff --git a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt b/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt index 7531d7f..2e189ef 100644 --- a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt +++ b/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt @@ -7,9 +7,9 @@ class PreSharedKeyKeyExtractorTest { private val pskKeyExtractor = PskKeyExtractor() private val testHash = "1234567890123456123456789012345612345678901234561234567890123456" - private val validPskCommand = "PSK:1234567891234567${testHash};PSK:1234567891234567${testHash}SET!" - private val validPskCommandWithKeyWordsInKey = "PSK:PSKaSET1PSKd2SET${testHash};PSK:PSKaSET1PSKd2SET${testHash}SET!" - private val invalidKeySizePskCommand = "PSK:1234${testHash};PSK:1234${testHash}SET!" + private val validPskCommand = "!PSK:1234567891234567${testHash};PSK:1234567891234567${testHash}SET" + private val validPskCommandWithKeyWordsInKey = "!PSK:PSKaSET1PSKd2SET${testHash};PSK:PSKaSET1PSKd2SET${testHash}SET" + private val invalidKeySizePskCommand = "!PSK:1234${testHash};PSK:1234${testHash}SET" private val notPskCommand = "NoPskCommandInThisString" From b4ec47cb39eb6d4fa55ead26796d1bd2ca7c91c4 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Fri, 26 Jan 2024 10:07:12 +0100 Subject: [PATCH 06/12] FDP-1815: comments and chiper change Signed-off-by: Luciano Favoroso --- .../configuration/CaliforniumConfiguration.kt | 3 ++- .../simulator/coap/CoapClientService.kt | 2 +- .../simulator/response/PskKeyExtractor.kt | 11 +++-------- .../simulator/response/ResponseHandler.kt | 5 ++--- .../simulator/response/command/PskCommandHandler.kt | 11 +++++------ .../command/exception/PskHashNotValidException.kt | 2 +- .../src/test/kotlin/PreSharedKeyKeyExtractorTest.kt | 13 ++++++------- 7 files changed, 20 insertions(+), 27 deletions(-) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CaliforniumConfiguration.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CaliforniumConfiguration.kt index 19b4c2c..604f968 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CaliforniumConfiguration.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/configuration/CaliforniumConfiguration.kt @@ -29,6 +29,7 @@ class CaliforniumConfiguration(private val simulatorProperties: SimulatorPropert .set(CoapConfig.COAP_PORT, simulatorProperties.uri.port) .set(CoapConfig.COAP_SECURE_PORT, simulatorProperties.uri.port) .set(DtlsConfig.DTLS_ROLE, DtlsRole.CLIENT_ONLY) - .set(DtlsConfig.DTLS_CIPHER_SUITES, listOf(CipherSuite.TLS_PSK_WITH_AES_256_CCM_8)) + .set(DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, false) + .set(DtlsConfig.DTLS_CIPHER_SUITES, listOf(CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256)) } } diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/coap/CoapClientService.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/coap/CoapClientService.kt index 03d9a21..9314cbe 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/coap/CoapClientService.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/coap/CoapClientService.kt @@ -37,7 +37,7 @@ class CoapClientService( } return coapClient } - + private fun createDtlsConnector(advancedSingleIdentityPskStore: AdvancedSingleIdentityPskStore): DTLSConnector { val address = InetSocketAddress(0) val dtlsBuilder = DtlsConnectorConfig.builder(configuration) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt index 3301291..c32d4f2 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt @@ -4,12 +4,7 @@ package org.gxf.crestdevicesimulator.simulator.response -import org.springframework.stereotype.Component - -@Component -class PskKeyExtractor { - - private val pskCommandVerificationRegex = "!PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64};PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64}SET".toRegex() +object PskKeyExtractor { /** * Regex to split a valid PSK set command in 3 groups @@ -17,9 +12,9 @@ class PskKeyExtractor { * Group 1 containing the next 16 chars after PSK: this is only the key * Group 2 containing the next 64 chars after the key this is only the hash */ - private val pskKeyHashSplitterRegex = "(?<=PSK:)([a-zA-Z0-9]{16})([a-zA-Z0-9]{64})".toRegex() + private val pskKeyHashSplitterRegex = "!PSK:([a-zA-Z0-9]{16})([a-zA-Z0-9]{64});PSK:([a-zA-Z0-9]{16})([a-zA-Z0-9]{64})SET".toRegex() - fun hasPskCommand(command: String) = pskCommandVerificationRegex.matches(command) + fun hasPskCommand(command: String) = pskKeyHashSplitterRegex.matches(command) fun extractKeyFromCommand(command: String) = pskKeyHashSplitterRegex.findAll(command).first().groups[1]!!.value diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt index c5811ff..2a8f1b1 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt @@ -9,13 +9,12 @@ import org.gxf.crestdevicesimulator.simulator.response.command.PskCommandHandler import org.springframework.stereotype.Component @Component -class ResponseHandler(private val pskCommandHandler: PskCommandHandler, - private val pskKeyExtractor: PskKeyExtractor) { +class ResponseHandler(private val pskCommandHandler: PskCommandHandler) { fun handleResponse(response: CoapResponse) { val body = String(response.payload) - if (pskKeyExtractor.hasPskCommand(body)) { + if (PskKeyExtractor.hasPskCommand(body)) { pskCommandHandler.handlePskChange(body) } } diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt index d28b418..ca4cd20 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt @@ -16,14 +16,13 @@ import org.springframework.stereotype.Service @Service class PskCommandHandler(private val pskRepository: PskRepository, private val simulatorProperties: SimulatorProperties, - private val pskKeyExtractor: PskKeyExtractor, private val pskStore: AdvancedSingleIdentityPskStore) { private val logger = KotlinLogging.logger {} fun handlePskChange(body: String) { - val newPsk = pskKeyExtractor.extractKeyFromCommand(body) - val hash = pskKeyExtractor.extractHashFromCommand(body) + val newPsk = PskKeyExtractor.extractKeyFromCommand(body) + val hash = PskKeyExtractor.extractHashFromCommand(body) val preSharedKeyOptional = pskRepository.findById(simulatorProperties.pskIdentity) @@ -32,13 +31,13 @@ class PskCommandHandler(private val pskRepository: PskRepository, } logger.info { "Validating hash for identity: ${simulatorProperties.pskIdentity}" } - + val preSharedKey = preSharedKeyOptional.get() val secret = preSharedKey.secret - val expectedHash = DigestUtils.sha256Hex("${secret}${newPsk}") + val expectedHash = DigestUtils.sha256Hex("$secret$newPsk") if (expectedHash != hash) { - throw PskHashNotValidException() + throw PskHashNotValidException("PSK set Hash for Identity ${simulatorProperties.pskIdentity} did not match") } pskRepository.save(preSharedKey.apply { this.preSharedKey = newPsk }) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt index 3d56845..55443ca 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt @@ -4,4 +4,4 @@ package org.gxf.crestdevicesimulator.simulator.response.command.exception -class PskHashNotValidException : Exception() +class PskHashNotValidException(override val message: String) : Exception() diff --git a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt b/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt index 2e189ef..7bca80e 100644 --- a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt +++ b/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Test class PreSharedKeyKeyExtractorTest { - private val pskKeyExtractor = PskKeyExtractor() private val testHash = "1234567890123456123456789012345612345678901234561234567890123456" private val validPskCommand = "!PSK:1234567891234567${testHash};PSK:1234567891234567${testHash}SET" @@ -15,10 +14,10 @@ class PreSharedKeyKeyExtractorTest { @Test fun shouldReturnTrueWhenThereIsAPskCommandInString() { - val resultValid = pskKeyExtractor.hasPskCommand(validPskCommand) - val resultValidWithKeyWords = pskKeyExtractor.hasPskCommand(validPskCommandWithKeyWordsInKey) - val resultInvalidKeySize = pskKeyExtractor.hasPskCommand(invalidKeySizePskCommand) - val resultNoPskCommand = pskKeyExtractor.hasPskCommand(notPskCommand) + val resultValid = PskKeyExtractor.hasPskCommand(validPskCommand) + val resultValidWithKeyWords = PskKeyExtractor.hasPskCommand(validPskCommandWithKeyWordsInKey) + val resultInvalidKeySize = PskKeyExtractor.hasPskCommand(invalidKeySizePskCommand) + val resultNoPskCommand = PskKeyExtractor.hasPskCommand(notPskCommand) assertTrue(resultValid) assertTrue(resultValidWithKeyWords) @@ -28,8 +27,8 @@ class PreSharedKeyKeyExtractorTest { @Test fun shouldReturnPskKeyFromValidPskCommand() { - val resultValid = pskKeyExtractor.extractKeyFromCommand(validPskCommand) - val resultValidWithKeyWords = pskKeyExtractor.extractKeyFromCommand(validPskCommandWithKeyWordsInKey) + val resultValid = PskKeyExtractor.extractKeyFromCommand(validPskCommand) + val resultValidWithKeyWords = PskKeyExtractor.extractKeyFromCommand(validPskCommandWithKeyWordsInKey) assertEquals("1234567891234567", resultValid) assertEquals("PSKaSET1PSKd2SET", resultValidWithKeyWords) From 2cc7a3d54aba9a893b9893ebf93a3fd824341a5d Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Mon, 29 Jan 2024 13:26:20 +0100 Subject: [PATCH 07/12] FDP-1815: Comments Sander Signed-off-by: Luciano Favoroso --- .../simulator/response/PskKeyExtractor.kt | 4 ++-- .../response/command/exception/PskHashNotValidException.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt index c32d4f2..2d8da8d 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt @@ -8,11 +8,11 @@ object PskKeyExtractor { /** * Regex to split a valid PSK set command in 3 groups - * Group 0 containing everything after PSK: this includes the key and hash + * Group 0 containing everything * Group 1 containing the next 16 chars after PSK: this is only the key * Group 2 containing the next 64 chars after the key this is only the hash */ - private val pskKeyHashSplitterRegex = "!PSK:([a-zA-Z0-9]{16})([a-zA-Z0-9]{64});PSK:([a-zA-Z0-9]{16})([a-zA-Z0-9]{64})SET".toRegex() + private val pskKeyHashSplitterRegex = "!PSK:([a-zA-Z0-9]{16})([a-zA-Z0-9]{64});PSK:[a-zA-Z0-9]{16}[a-zA-Z0-9]{64}SET".toRegex() fun hasPskCommand(command: String) = pskKeyHashSplitterRegex.matches(command) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt index 55443ca..f47265f 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt @@ -4,4 +4,4 @@ package org.gxf.crestdevicesimulator.simulator.response.command.exception -class PskHashNotValidException(override val message: String) : Exception() +class PskHashNotValidException(message: String) : Exception(message) From 2eed19df7823804d79b42c1db28e05b7b4338cb8 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Mon, 29 Jan 2024 13:38:24 +0100 Subject: [PATCH 08/12] FDP-1815: Comments Sander Signed-off-by: Luciano Favoroso --- .../gxf/crestdevicesimulator/simulator}/SimulatorTests.kt | 4 ++-- .../simulator/response/PskKeyExtractorTest.kt} | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) rename application/src/test/kotlin/{ => org/gxf/crestdevicesimulator/simulator}/SimulatorTests.kt (95%) rename application/src/test/kotlin/{PreSharedKeyKeyExtractorTest.kt => org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt} (93%) diff --git a/application/src/test/kotlin/SimulatorTests.kt b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/SimulatorTests.kt similarity index 95% rename from application/src/test/kotlin/SimulatorTests.kt rename to application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/SimulatorTests.kt index e584da2..c82d504 100644 --- a/application/src/test/kotlin/SimulatorTests.kt +++ b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/SimulatorTests.kt @@ -1,11 +1,11 @@ +package org.gxf.crestdevicesimulator.simulator + import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.cbor.databind.CBORMapper import org.eclipse.californium.core.CoapClient import org.eclipse.californium.core.CoapResponse import org.eclipse.californium.core.coap.Request import org.gxf.crestdevicesimulator.configuration.SimulatorProperties -import org.gxf.crestdevicesimulator.simulator.CborFactory -import org.gxf.crestdevicesimulator.simulator.Simulator import org.gxf.crestdevicesimulator.simulator.coap.CoapClientService import org.gxf.crestdevicesimulator.simulator.response.ResponseHandler import org.junit.jupiter.api.Assertions.assertArrayEquals diff --git a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt similarity index 93% rename from application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt rename to application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt index 7bca80e..8c94c19 100644 --- a/application/src/test/kotlin/PreSharedKeyKeyExtractorTest.kt +++ b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt @@ -1,8 +1,9 @@ -import org.gxf.crestdevicesimulator.simulator.response.PskKeyExtractor +package org.gxf.crestdevicesimulator.simulator.response + import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test -class PreSharedKeyKeyExtractorTest { +class PskKeyExtractorTest { private val testHash = "1234567890123456123456789012345612345678901234561234567890123456" From 15b27cf8972ffcaeefd0b6dc46614ab046232e0b Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Mon, 29 Jan 2024 13:42:22 +0100 Subject: [PATCH 09/12] FDP-1815: Comments Sander Signed-off-by: Luciano Favoroso --- .../{PskKeyExtractor.kt => PskExtractor.kt} | 2 +- .../simulator/response/ResponseHandler.kt | 2 +- .../response/command/PskCommandHandler.kt | 6 +++--- ...{PskKeyExtractorTest.kt => PskExtractorTest.kt} | 14 +++++++------- 4 files changed, 12 insertions(+), 12 deletions(-) rename application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/{PskKeyExtractor.kt => PskExtractor.kt} (97%) rename application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/{PskKeyExtractorTest.kt => PskExtractorTest.kt} (64%) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractor.kt similarity index 97% rename from application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt rename to application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractor.kt index 2d8da8d..0e0add3 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractor.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractor.kt @@ -4,7 +4,7 @@ package org.gxf.crestdevicesimulator.simulator.response -object PskKeyExtractor { +object PskExtractor { /** * Regex to split a valid PSK set command in 3 groups diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt index 2a8f1b1..bd6f229 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/ResponseHandler.kt @@ -14,7 +14,7 @@ class ResponseHandler(private val pskCommandHandler: PskCommandHandler) { fun handleResponse(response: CoapResponse) { val body = String(response.payload) - if (PskKeyExtractor.hasPskCommand(body)) { + if (PskExtractor.hasPskCommand(body)) { pskCommandHandler.handlePskChange(body) } } diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt index ca4cd20..d8f2780 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt @@ -9,7 +9,7 @@ import org.apache.commons.codec.digest.DigestUtils import org.gxf.crestdevicesimulator.configuration.AdvancedSingleIdentityPskStore import org.gxf.crestdevicesimulator.configuration.SimulatorProperties import org.gxf.crestdevicesimulator.simulator.data.repository.PskRepository -import org.gxf.crestdevicesimulator.simulator.response.PskKeyExtractor +import org.gxf.crestdevicesimulator.simulator.response.PskExtractor import org.gxf.crestdevicesimulator.simulator.response.command.exception.PskHashNotValidException import org.springframework.stereotype.Service @@ -21,8 +21,8 @@ class PskCommandHandler(private val pskRepository: PskRepository, private val logger = KotlinLogging.logger {} fun handlePskChange(body: String) { - val newPsk = PskKeyExtractor.extractKeyFromCommand(body) - val hash = PskKeyExtractor.extractHashFromCommand(body) + val newPsk = PskExtractor.extractKeyFromCommand(body) + val hash = PskExtractor.extractHashFromCommand(body) val preSharedKeyOptional = pskRepository.findById(simulatorProperties.pskIdentity) diff --git a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt similarity index 64% rename from application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt rename to application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt index 8c94c19..9cd0df0 100644 --- a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskKeyExtractorTest.kt +++ b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt @@ -3,7 +3,7 @@ package org.gxf.crestdevicesimulator.simulator.response import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test -class PskKeyExtractorTest { +class PskExtractorTest { private val testHash = "1234567890123456123456789012345612345678901234561234567890123456" @@ -15,10 +15,10 @@ class PskKeyExtractorTest { @Test fun shouldReturnTrueWhenThereIsAPskCommandInString() { - val resultValid = PskKeyExtractor.hasPskCommand(validPskCommand) - val resultValidWithKeyWords = PskKeyExtractor.hasPskCommand(validPskCommandWithKeyWordsInKey) - val resultInvalidKeySize = PskKeyExtractor.hasPskCommand(invalidKeySizePskCommand) - val resultNoPskCommand = PskKeyExtractor.hasPskCommand(notPskCommand) + val resultValid = PskExtractor.hasPskCommand(validPskCommand) + val resultValidWithKeyWords = PskExtractor.hasPskCommand(validPskCommandWithKeyWordsInKey) + val resultInvalidKeySize = PskExtractor.hasPskCommand(invalidKeySizePskCommand) + val resultNoPskCommand = PskExtractor.hasPskCommand(notPskCommand) assertTrue(resultValid) assertTrue(resultValidWithKeyWords) @@ -28,8 +28,8 @@ class PskKeyExtractorTest { @Test fun shouldReturnPskKeyFromValidPskCommand() { - val resultValid = PskKeyExtractor.extractKeyFromCommand(validPskCommand) - val resultValidWithKeyWords = PskKeyExtractor.extractKeyFromCommand(validPskCommandWithKeyWordsInKey) + val resultValid = PskExtractor.extractKeyFromCommand(validPskCommand) + val resultValidWithKeyWords = PskExtractor.extractKeyFromCommand(validPskCommandWithKeyWordsInKey) assertEquals("1234567891234567", resultValid) assertEquals("PSKaSET1PSKd2SET", resultValidWithKeyWords) From 014e4b377640b69817f0940279d23bcdc8f39ecd Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Tue, 30 Jan 2024 11:48:45 +0100 Subject: [PATCH 10/12] FDP-1815: Comments Sander Signed-off-by: Luciano Favoroso --- .../response/command/PskCommandHandler.kt | 4 +- ...xception.kt => InvalidPskHashException.kt} | 2 +- .../resources/db/migration/V2__secret.sql | 6 +- .../simulator/response/PskExtractorTest.kt | 65 +++++++++++------ .../response/command/PskCommandHandlerTest.kt | 71 +++++++++++++++++++ 5 files changed, 121 insertions(+), 27 deletions(-) rename application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/{PskHashNotValidException.kt => InvalidPskHashException.kt} (71%) create mode 100644 application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt index d8f2780..c07899c 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandler.kt @@ -10,7 +10,7 @@ import org.gxf.crestdevicesimulator.configuration.AdvancedSingleIdentityPskStore import org.gxf.crestdevicesimulator.configuration.SimulatorProperties import org.gxf.crestdevicesimulator.simulator.data.repository.PskRepository import org.gxf.crestdevicesimulator.simulator.response.PskExtractor -import org.gxf.crestdevicesimulator.simulator.response.command.exception.PskHashNotValidException +import org.gxf.crestdevicesimulator.simulator.response.command.exception.InvalidPskHashException import org.springframework.stereotype.Service @Service @@ -37,7 +37,7 @@ class PskCommandHandler(private val pskRepository: PskRepository, val expectedHash = DigestUtils.sha256Hex("$secret$newPsk") if (expectedHash != hash) { - throw PskHashNotValidException("PSK set Hash for Identity ${simulatorProperties.pskIdentity} did not match") + throw InvalidPskHashException("PSK set Hash for Identity ${simulatorProperties.pskIdentity} did not match") } pskRepository.save(preSharedKey.apply { this.preSharedKey = newPsk }) diff --git a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/InvalidPskHashException.kt similarity index 71% rename from application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt rename to application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/InvalidPskHashException.kt index f47265f..6663db9 100644 --- a/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/PskHashNotValidException.kt +++ b/application/src/main/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/exception/InvalidPskHashException.kt @@ -4,4 +4,4 @@ package org.gxf.crestdevicesimulator.simulator.response.command.exception -class PskHashNotValidException(message: String) : Exception(message) +class InvalidPskHashException(message: String) : Exception(message) diff --git a/application/src/main/resources/db/migration/V2__secret.sql b/application/src/main/resources/db/migration/V2__secret.sql index 13dfd0a..eb6483f 100644 --- a/application/src/main/resources/db/migration/V2__secret.sql +++ b/application/src/main/resources/db/migration/V2__secret.sql @@ -1,5 +1,9 @@ +-- SPDX-FileCopyrightText: Contributors to the GXF project +-- +-- SPDX-License-Identifier: Apache-2.0 -- No production data was set before this change so we can drop all existing data -delete from pre_shared_key; +delete +from pre_shared_key; alter table pre_shared_key add column secret varchar(255) not null; diff --git a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt index 9cd0df0..efa148f 100644 --- a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt +++ b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/PskExtractorTest.kt @@ -1,37 +1,56 @@ +// SPDX-FileCopyrightText: Contributors to the GXF project +// +// SPDX-License-Identifier: Apache-2.0 package org.gxf.crestdevicesimulator.simulator.response -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource + class PskExtractorTest { - private val testHash = "1234567890123456123456789012345612345678901234561234567890123456" + companion object { + private const val testHash = "1234567890123456123456789012345612345678901234561234567890123456" + + private const val validPskCommand = "!PSK:1234567891234567${testHash};PSK:1234567891234567${testHash}SET" + private const val validPskCommandWithKeyWordsInKey = "!PSK:PSKaSET1PSKd2SET${testHash};PSK:PSKaSET1PSKd2SET${testHash}SET" + private const val invalidKeySizePskCommand = "!PSK:1234${testHash};PSK:1234${testHash}SET" + private const val notPskCommand = "NoPskCommandInThisString" + } - private val validPskCommand = "!PSK:1234567891234567${testHash};PSK:1234567891234567${testHash}SET" - private val validPskCommandWithKeyWordsInKey = "!PSK:PSKaSET1PSKd2SET${testHash};PSK:PSKaSET1PSKd2SET${testHash}SET" - private val invalidKeySizePskCommand = "!PSK:1234${testHash};PSK:1234${testHash}SET" - private val notPskCommand = "NoPskCommandInThisString" + @ParameterizedTest + @CsvSource( + "$validPskCommand, true", + "$validPskCommandWithKeyWordsInKey, true", + "$invalidKeySizePskCommand, false", + "$notPskCommand, false" + ) + fun shouldReturnTrueWhenThereIsAPskCommandInString(pskCommand: String, isValid: Boolean) { + val result = PskExtractor.hasPskCommand(pskCommand) + assertThat(result).isEqualTo(isValid) + } - @Test - fun shouldReturnTrueWhenThereIsAPskCommandInString() { - val resultValid = PskExtractor.hasPskCommand(validPskCommand) - val resultValidWithKeyWords = PskExtractor.hasPskCommand(validPskCommandWithKeyWordsInKey) - val resultInvalidKeySize = PskExtractor.hasPskCommand(invalidKeySizePskCommand) - val resultNoPskCommand = PskExtractor.hasPskCommand(notPskCommand) + @ParameterizedTest + @CsvSource( + "$validPskCommand, 1234567891234567", + "$validPskCommandWithKeyWordsInKey, PSKaSET1PSKd2SET" + ) + fun shouldReturnPskKeyFromValidPskCommand(pskCommand: String, expectedKey: String) { + val result = PskExtractor.extractKeyFromCommand(pskCommand) - assertTrue(resultValid) - assertTrue(resultValidWithKeyWords) - assertFalse(resultInvalidKeySize) - assertFalse(resultNoPskCommand) + assertThat(result).isEqualTo(expectedKey) } - @Test - fun shouldReturnPskKeyFromValidPskCommand() { - val resultValid = PskExtractor.extractKeyFromCommand(validPskCommand) - val resultValidWithKeyWords = PskExtractor.extractKeyFromCommand(validPskCommandWithKeyWordsInKey) + @ParameterizedTest + @CsvSource( + "$validPskCommand, $testHash", + "$validPskCommandWithKeyWordsInKey, $testHash" + ) + fun shouldReturnHashFromValidPskCommand(pskCommand: String, expectedHash: String) { + val result = PskExtractor.extractHashFromCommand(pskCommand) - assertEquals("1234567891234567", resultValid) - assertEquals("PSKaSET1PSKd2SET", resultValidWithKeyWords) + assertThat(result).isEqualTo(expectedHash) } } diff --git a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt new file mode 100644 index 0000000..fb73c51 --- /dev/null +++ b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Contributors to the GXF project +// +// SPDX-License-Identifier: Apache-2.0 +package org.gxf.crestdevicesimulator.simulator.response.command + +import org.apache.commons.codec.digest.DigestUtils +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.gxf.crestdevicesimulator.configuration.AdvancedSingleIdentityPskStore +import org.gxf.crestdevicesimulator.configuration.SimulatorProperties +import org.gxf.crestdevicesimulator.simulator.data.entity.PreSharedKey +import org.gxf.crestdevicesimulator.simulator.data.repository.PskRepository +import org.gxf.crestdevicesimulator.simulator.response.command.exception.InvalidPskHashException +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Answers +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.`when` +import org.mockito.junit.jupiter.MockitoExtension +import java.util.* + +@ExtendWith(MockitoExtension::class) +class PskCommandHandlerTest { + + @Mock + private lateinit var pskRepository: PskRepository + + @Mock + private lateinit var simulatorProperties: SimulatorProperties + + @Mock(answer = Answers.CALLS_REAL_METHODS) + private lateinit var pskStore: AdvancedSingleIdentityPskStore + + @InjectMocks + private lateinit var pskCommandHandler: PskCommandHandler + + private val key = "1234567891234567" + + private val secret = "secret" + + private val identity = "1234" + + @BeforeEach + fun setup() { + `when`(simulatorProperties.pskIdentity).thenReturn(identity) + `when`(pskRepository.findById(any())).thenReturn(Optional.of(PreSharedKey(identity, key, secret))) + } + + @Test + fun shouldSetNewPskInStoreWhenTheKeyIsValid() { + val expectedHash = DigestUtils.sha256Hex("$secret$key") + val pskCommand = "!PSK:$key$expectedHash;PSK:$key${expectedHash}SET" + + pskCommandHandler.handlePskChange(pskCommand) + + assertThat(pskStore.key).isEqualTo("1234567891234567") + } + + @Test + fun shouldThrowErrorWhenHashDoesNotMatch() { + val invalidHash = DigestUtils.sha256Hex("invalid") + val pskCommand = "!PSK:$key$invalidHash;PSK:$key${invalidHash}SET" + + assertThatExceptionOfType(InvalidPskHashException::class.java).isThrownBy { + pskCommandHandler.handlePskChange(pskCommand) + } + } +} \ No newline at end of file From c9189a7ebbd590f31f2c0d9f4280ee0896285877 Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Tue, 30 Jan 2024 11:49:29 +0100 Subject: [PATCH 11/12] FDP-1815: formatting Signed-off-by: Luciano Favoroso --- application/src/main/resources/db/migration/V2__secret.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/resources/db/migration/V2__secret.sql b/application/src/main/resources/db/migration/V2__secret.sql index eb6483f..c99bac5 100644 --- a/application/src/main/resources/db/migration/V2__secret.sql +++ b/application/src/main/resources/db/migration/V2__secret.sql @@ -2,8 +2,7 @@ -- -- SPDX-License-Identifier: Apache-2.0 -- No production data was set before this change so we can drop all existing data -delete -from pre_shared_key; +delete from pre_shared_key; alter table pre_shared_key add column secret varchar(255) not null; From 9417ae3140c44f28871d627df4dc6c258844c34c Mon Sep 17 00:00:00 2001 From: Luciano Favoroso Date: Wed, 31 Jan 2024 09:42:37 +0100 Subject: [PATCH 12/12] FDP-1815: comments Sander Signed-off-by: Luciano Favoroso --- .../response/command/PskCommandHandlerTest.kt | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt index fb73c51..5a6ce47 100644 --- a/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt +++ b/application/src/test/kotlin/org/gxf/crestdevicesimulator/simulator/response/command/PskCommandHandlerTest.kt @@ -5,7 +5,7 @@ package org.gxf.crestdevicesimulator.simulator.response.command import org.apache.commons.codec.digest.DigestUtils import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.catchException import org.gxf.crestdevicesimulator.configuration.AdvancedSingleIdentityPskStore import org.gxf.crestdevicesimulator.configuration.SimulatorProperties import org.gxf.crestdevicesimulator.simulator.data.entity.PreSharedKey @@ -17,8 +17,7 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Answers import org.mockito.InjectMocks import org.mockito.Mock -import org.mockito.Mockito.any -import org.mockito.Mockito.`when` +import org.mockito.Mockito.* import org.mockito.junit.jupiter.MockitoExtension import java.util.* @@ -37,7 +36,9 @@ class PskCommandHandlerTest { @InjectMocks private lateinit var pskCommandHandler: PskCommandHandler - private val key = "1234567891234567" + private val newKey = "7654321987654321" + + private val oldKey = "1234567891234567" private val secret = "secret" @@ -46,26 +47,31 @@ class PskCommandHandlerTest { @BeforeEach fun setup() { `when`(simulatorProperties.pskIdentity).thenReturn(identity) - `when`(pskRepository.findById(any())).thenReturn(Optional.of(PreSharedKey(identity, key, secret))) + `when`(pskRepository.findById(any())).thenReturn(Optional.of(PreSharedKey(identity, oldKey, secret))) + pskStore.key = oldKey } @Test fun shouldSetNewPskInStoreWhenTheKeyIsValid() { - val expectedHash = DigestUtils.sha256Hex("$secret$key") - val pskCommand = "!PSK:$key$expectedHash;PSK:$key${expectedHash}SET" + val expectedHash = DigestUtils.sha256Hex("$secret$newKey") + val pskCommand = "!PSK:$newKey$expectedHash;PSK:$newKey${expectedHash}SET" pskCommandHandler.handlePskChange(pskCommand) - assertThat(pskStore.key).isEqualTo("1234567891234567") + assertThat(pskStore.key).isEqualTo(newKey) } @Test fun shouldThrowErrorWhenHashDoesNotMatch() { val invalidHash = DigestUtils.sha256Hex("invalid") - val pskCommand = "!PSK:$key$invalidHash;PSK:$key${invalidHash}SET" + val pskCommand = "!PSK:$oldKey$invalidHash;PSK:$oldKey${invalidHash}SET" - assertThatExceptionOfType(InvalidPskHashException::class.java).isThrownBy { + val thrownException = catchException { pskCommandHandler.handlePskChange(pskCommand) } + + assertThat(thrownException).isInstanceOf(InvalidPskHashException::class.java) + verify(pskRepository, never()).save(any()) + assertThat(pskStore.key).isEqualTo(oldKey) } -} \ No newline at end of file +}