From: Jérôme Benoit Date: Tue, 7 Apr 2026 19:30:56 +0000 (+0200) Subject: fix(ocpp): conform signingMethod to OCA spec and fix template curve mismatch X-Git-Tag: ocpp-server@v4.4.0~7 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=b5f45a446f19687b1a38f92ac07da9a8a14224fd;p=e-mobility-charging-stations-simulator.git fix(ocpp): conform signingMethod to OCA spec and fix template curve mismatch - Set signingMethod to empty string when using OCMF encoding per OCA Application Note Table 11: SA field already in signedMeterData - Add FiscalMetering.SigningMethod=ECDSA-secp256k1-SHA256 to keba-ocpp2-signed template to match the secp256k1 public key from OCA spec §5.3 example - Update tests to expect empty signingMethod for OCMF payloads - Remove unused SigningMethodEnumType imports from test files --- diff --git a/src/assets/station-templates/keba-ocpp2-signed.station-template.json b/src/assets/station-templates/keba-ocpp2-signed.station-template.json index 7d078a58..51fb5319 100644 --- a/src/assets/station-templates/keba-ocpp2-signed.station-template.json +++ b/src/assets/station-templates/keba-ocpp2-signed.station-template.json @@ -105,6 +105,11 @@ "key": "FiscalMetering.PublicKey", "readonly": true, "value": "3056301006072a8648ce3d020106052b8104000a03420004460a02ba2766d9c44f023ecc0e4e58644a87add1aadd6317e5fe4dccdb29b163a01d8a6297c84bc530f86431e92f8d46ab37830247c05cbd92fac252929e7f61" + }, + { + "key": "FiscalMetering.SigningMethod", + "readonly": true, + "value": "ECDSA-secp256k1-SHA256" } ] }, diff --git a/src/charging-station/ocpp/OCPPSignedMeterDataGenerator.ts b/src/charging-station/ocpp/OCPPSignedMeterDataGenerator.ts index bb09b3df..cd49afa6 100644 --- a/src/charging-station/ocpp/OCPPSignedMeterDataGenerator.ts +++ b/src/charging-station/ocpp/OCPPSignedMeterDataGenerator.ts @@ -13,7 +13,7 @@ export interface SignedMeterData extends JsonObject { encodingMethod: EncodingMethodEnumType publicKey: string signedMeterData: string - signingMethod: SigningMethodEnumType + signingMethod: '' | SigningMethodEnumType } export interface SignedMeterDataParams { @@ -76,12 +76,15 @@ export const generateSignedMeterData = ( const simulatedSignature = createHash('sha256').update(JSON.stringify(ocmfPayload)).digest('hex') + // OCMF includes the signing algorithm in the SA field of signedMeterData. + // Per OCA Application Note Table 11: "If it is already included in the + // signedMeterData, then this SHALL be an empty string." const ocmfString = `OCMF|${JSON.stringify(ocmfPayload)}|{"SA":"${resolvedSigningMethod}","SD":"${simulatedSignature}"}` return { encodingMethod: DEFAULT_ENCODING_METHOD, publicKey: publicKeyHex != null ? buildPublicKeyValue(publicKeyHex) : '', signedMeterData: Buffer.from(ocmfString).toString('base64'), - signingMethod: resolvedSigningMethod, + signingMethod: '', } } 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 22620b32..37011e1f 100644 --- a/tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts +++ b/tests/charging-station/ocpp/1.6/OCPP16ServiceUtils-SignedMeterValues.test.ts @@ -24,7 +24,6 @@ import { type OCPP16SignedMeterValue, OCPP16VendorParametersKey, OCPPVersion, - SigningMethodEnumType, } from '../../../../src/types/index.js' import { standardCleanup, withMockTimers } from '../../../helpers/TestLifecycleHelpers.js' import { createMockChargingStation } from '../../ChargingStationTestUtils.js' @@ -298,7 +297,7 @@ await describe('OCPP 1.6 — Signed MeterValues', async () => { assert.strictEqual(typeof parsed.signedMeterData, 'string') assert.strictEqual(typeof parsed.publicKey, 'string') assert.strictEqual(parsed.encodingMethod, EncodingMethodEnumType.OCMF) - assert.strictEqual(parsed.signingMethod, SigningMethodEnumType.ECDSA_secp256r1_SHA256) + assert.strictEqual(parsed.signingMethod, '') }) }) 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 08ceddd4..404dcf1c 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20RequestBuilders-SignedMeterValues.test.ts @@ -22,7 +22,6 @@ import { OCPPVersion, PublicKeyWithSignedMeterValueEnumType, type SampledValueTemplate, - SigningMethodEnumType, } from '../../../../src/types/index.js' import { Constants } from '../../../../src/utils/index.js' import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js' @@ -65,10 +64,7 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { ) assert.ok(sampledValue.signedMeterValue != null) - assert.strictEqual( - sampledValue.signedMeterValue.signingMethod, - SigningMethodEnumType.ECDSA_secp256r1_SHA256 - ) + assert.strictEqual(sampledValue.signedMeterValue.signingMethod, '') assert.strictEqual(sampledValue.signedMeterValue.encodingMethod, EncodingMethodEnumType.OCMF) }) @@ -243,10 +239,7 @@ await describe('OCPP 2.0 Signed Meter Values', async () => { ) as OCPP20SampledValue | undefined assert.notStrictEqual(energySampledValue, undefined) assert.ok(energySampledValue?.signedMeterValue != null) - assert.strictEqual( - energySampledValue.signedMeterValue.signingMethod, - SigningMethodEnumType.ECDSA_secp256r1_SHA256 - ) + assert.strictEqual(energySampledValue.signedMeterValue.signingMethod, '') assert.strictEqual( energySampledValue.signedMeterValue.encodingMethod, EncodingMethodEnumType.OCMF diff --git a/tests/charging-station/ocpp/OCPPSignedMeterDataGenerator.test.ts b/tests/charging-station/ocpp/OCPPSignedMeterDataGenerator.test.ts index ad0309d3..d724701e 100644 --- a/tests/charging-station/ocpp/OCPPSignedMeterDataGenerator.test.ts +++ b/tests/charging-station/ocpp/OCPPSignedMeterDataGenerator.test.ts @@ -23,7 +23,6 @@ import { EncodingMethodEnumType, MeterValueContext, MeterValueUnit, - SigningMethodEnumType, } from '../../../src/types/index.js' const DEFAULT_PARAMS: SignedMeterDataParams = { @@ -60,10 +59,10 @@ await describe('SignedMeterDataGenerator', async () => { assert.ok(decoded.startsWith('OCMF|')) }) - await it('should set signingMethod to ECDSA-secp256r1-SHA256', () => { + await it('should set signingMethod to empty string per OCA spec when using OCMF', () => { const result = generateSignedMeterData(DEFAULT_PARAMS) - assert.strictEqual(result.signingMethod, SigningMethodEnumType.ECDSA_secp256r1_SHA256) + assert.strictEqual(result.signingMethod, '') }) await it('should set encodingMethod to OCMF', () => {