]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
feat(ocpp): auto-derive signing method from EC public key curve
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 7 Apr 2026 20:08:55 +0000 (22:08 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 7 Apr 2026 20:08:55 +0000 (22:08 +0200)
- 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

tests/charging-station/ChargingStationTestConstants.ts
tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts
tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts

index 4560d1d25436bb6ebea4af4a2139a06c3bf55b37..35bef79c5ee7e11b7489f1ef1909a089d0e7641c 100644 (file)
@@ -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'
index 37011e1f8b7c57b6a9a33aed7988ab3f732bf8c7..91f33e59bb32a3e754991e596363cdcb54d178ef 100644 (file)
@@ -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 => {
index 404dcf1c4cbb6fd9d6e700d2b5cc7307e54eadce..be06caa6ef94218363661ae2c7490216fa0138b4 100644 (file)
@@ -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(