From: Jérôme Benoit Date: Tue, 7 Apr 2026 20:08:55 +0000 (+0200) Subject: feat(ocpp): auto-derive signing method from EC public key curve X-Git-Tag: ocpp-server@v4.4.0~6 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=9a630bd9d6ba7a3d84014aa6ba6f885377803c79;p=e-mobility-charging-stations-simulator.git feat(ocpp): auto-derive signing method from EC public key curve - Add deriveSigningMethodFromPublicKeyHex that extracts EC curve OID from ASN.1 DER public key and maps to SigningMethodEnumType - Add validateSigningPrerequisites that validates public key presence, curve detection, and config consistency — returns enabled/disabled with reason - Integrate validation in OCPP 2.0 (OCPPServiceUtils.buildMeterValue) and OCPP 1.6 (readSigningConfigForConnector) signing paths - On validation failure: log error and gracefully fallback to unsigned meter values instead of producing invalid signed data - Move TEST_PUBLIC_KEY_HEX to ChargingStationTestConstants for reuse - Update test fixtures to use valid secp256k1 ASN.1 EC public key --- diff --git a/tests/charging-station/ChargingStationTestConstants.ts b/tests/charging-station/ChargingStationTestConstants.ts index 4560d1d2..35bef79c 100644 --- a/tests/charging-station/ChargingStationTestConstants.ts +++ b/tests/charging-station/ChargingStationTestConstants.ts @@ -102,3 +102,10 @@ export const TEST_RESERVATION_EXPIRY_MS = TEST_ONE_HOUR_MS */ export const TEST_VALUE_SIZE_LIMIT = 120 export const TEST_CONFIGURATION_VALUE_SIZE = 60 + +/** + * Fiscal Metering / Signed Meter Values + * secp256k1 EC public key from OCA Application Note §5.3 + */ +export const TEST_PUBLIC_KEY_HEX = + '3056301006072a8648ce3d020106052b8104000a03420004460a02ba2766d9c44f023ecc0e4e58644a87add1aadd6317e5fe4dccdb29b163a01d8a6297c84bc530f86431e92f8d46ab37830247c05cbd92fac252929e7f61' diff --git a/tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts b/tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts index 37011e1f..91f33e59 100644 --- a/tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts +++ b/tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts @@ -26,6 +26,7 @@ import { OCPPVersion, } from '../../../../src/types/index.js' import { standardCleanup, withMockTimers } from '../../../helpers/TestLifecycleHelpers.js' +import { TEST_PUBLIC_KEY_HEX } from '../../ChargingStationTestConstants.js' import { createMockChargingStation } from '../../ChargingStationTestUtils.js' import { createMeterValuesTemplate, upsertConfigurationKey } from './OCPP16TestUtils.js' @@ -169,6 +170,11 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { OCPP16VendorParametersKey.SampledDataSignStartedReadings, 'true' ) + upsertConfigurationKey( + station, + `${OCPP16VendorParametersKey.MeterPublicKey}1`, + TEST_PUBLIC_KEY_HEX + ) upsertConfigurationKey( station, OCPP16VendorParametersKey.PublicKeyWithSignedMeterValue, @@ -217,7 +223,11 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { OCPP16VendorParametersKey.PublicKeyWithSignedMeterValue, 'OncePerTransaction' ) - upsertConfigurationKey(station, `${OCPP16VendorParametersKey.MeterPublicKey}1`, 'abcd1234') + upsertConfigurationKey( + station, + `${OCPP16VendorParametersKey.MeterPublicKey}1`, + TEST_PUBLIC_KEY_HEX + ) OCPP16ServiceUtils.buildTransactionBeginMeterValue(station, 1, 0) @@ -267,6 +277,11 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { } upsertConfigurationKey(station, OCPP16VendorParametersKey.SampledDataSignReadings, 'true') + upsertConfigurationKey( + station, + `${OCPP16VendorParametersKey.MeterPublicKey}1`, + TEST_PUBLIC_KEY_HEX + ) const meterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(station, 1, 50000) @@ -284,6 +299,11 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { } upsertConfigurationKey(station, OCPP16VendorParametersKey.SampledDataSignReadings, 'true') + upsertConfigurationKey( + station, + `${OCPP16VendorParametersKey.MeterPublicKey}1`, + TEST_PUBLIC_KEY_HEX + ) const meterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(station, 1, 25000) const signedSamples = meterValue.sampledValue.filter( @@ -327,6 +347,11 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { } upsertConfigurationKey(station, OCPP16VendorParametersKey.SampledDataSignReadings, 'true') + upsertConfigurationKey( + station, + `${OCPP16VendorParametersKey.MeterPublicKey}1`, + TEST_PUBLIC_KEY_HEX + ) }) await it('should not sign non-energy measurands even when signing is enabled', () => { @@ -414,6 +439,11 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { } upsertConfigurationKey(station, OCPP16VendorParametersKey.SampledDataSignReadings, 'true') + upsertConfigurationKey( + station, + `${OCPP16VendorParametersKey.MeterPublicKey}1`, + TEST_PUBLIC_KEY_HEX + ) }) await it('should include signed SampledValue in periodic meter values when SampledDataSignUpdatedReadings=true', async t => { diff --git a/tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts b/tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts index 404dcf1c..be06caa6 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts @@ -27,6 +27,7 @@ import { Constants } from '../../../../src/utils/index.js' import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js' import { TEST_CHARGING_STATION_BASE_NAME, + TEST_PUBLIC_KEY_HEX, TEST_TRANSACTION_ID_STRING, } from '../../ChargingStationTestConstants.js' import { createMockChargingStation } from '../../ChargingStationTestUtils.js' @@ -230,6 +231,11 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { buildConfigKey(OCPP20ComponentName.OCPPCommCtrlr, 'PublicKeyWithSignedMeterValue'), PublicKeyWithSignedMeterValueEnumType.Never ) + addConfigurationKey( + station, + buildConfigKey(OCPP20ComponentName.FiscalMetering, 'PublicKey'), + TEST_PUBLIC_KEY_HEX + ) const meterValue = buildMeterValue(station, TEST_TRANSACTION_ID_STRING, 0) @@ -324,7 +330,7 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { addConfigurationKey( station, buildConfigKey(OCPP20ComponentName.FiscalMetering, 'PublicKey'), - 'abcdef1234567890' + TEST_PUBLIC_KEY_HEX ) const connectorStatus = station.getConnectorStatus(1) @@ -389,7 +395,7 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { addConfigurationKey( station, buildConfigKey(OCPP20ComponentName.FiscalMetering, 'PublicKey'), - 'abcdef1234567890' + TEST_PUBLIC_KEY_HEX ) const meterValue = buildMeterValue( @@ -463,7 +469,7 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { addConfigurationKey( station, buildConfigKey(OCPP20ComponentName.FiscalMetering, 'PublicKey'), - 'abcdef1234567890' + TEST_PUBLIC_KEY_HEX ) const meterValue = buildMeterValue( @@ -507,7 +513,7 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { addConfigurationKey( station, buildConfigKey(OCPP20ComponentName.FiscalMetering, 'PublicKey'), - 'abcdef1234567890' + TEST_PUBLIC_KEY_HEX ) const meterValue = buildMeterValue(