@zwave-js/cc 14.1.0 → 14.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/cc/AlarmSensorCC.js.map +2 -2
- package/build/cjs/cc/AssociationCC.d.ts +2 -0
- package/build/cjs/cc/AssociationCC.js +5 -0
- package/build/cjs/cc/AssociationCC.js.map +2 -2
- package/build/cjs/cc/AssociationGroupInfoCC.js.map +2 -2
- package/build/cjs/cc/BarrierOperatorCC.js.map +2 -2
- package/build/cjs/cc/BasicCC.js.map +2 -2
- package/build/cjs/cc/BatteryCC.js.map +2 -2
- package/build/cjs/cc/BinarySensorCC.js.map +2 -2
- package/build/cjs/cc/BinarySwitchCC.js.map +2 -2
- package/build/cjs/cc/CRC16CC.d.ts +4 -0
- package/build/cjs/cc/CRC16CC.js +23 -0
- package/build/cjs/cc/CRC16CC.js.map +2 -2
- package/build/cjs/cc/CentralSceneCC.js.map +2 -2
- package/build/cjs/cc/ClimateControlScheduleCC.js.map +2 -2
- package/build/cjs/cc/ClockCC.js.map +2 -2
- package/build/cjs/cc/ColorSwitchCC.js.map +2 -2
- package/build/cjs/cc/ConfigurationCC.d.ts +4 -0
- package/build/cjs/cc/ConfigurationCC.js +10 -0
- package/build/cjs/cc/ConfigurationCC.js.map +2 -2
- package/build/cjs/cc/DoorLockCC.js.map +2 -2
- package/build/cjs/cc/DoorLockLoggingCC.js.map +2 -2
- package/build/cjs/cc/EnergyProductionCC.js.map +2 -2
- package/build/cjs/cc/EntryControlCC.js.map +2 -2
- package/build/cjs/cc/FirmwareUpdateMetaDataCC.js.map +2 -2
- package/build/cjs/cc/HumidityControlModeCC.js.map +2 -2
- package/build/cjs/cc/HumidityControlSetpointCC.js.map +2 -2
- package/build/cjs/cc/InclusionControllerCC.js.map +2 -2
- package/build/cjs/cc/IndicatorCC.js.map +2 -2
- package/build/cjs/cc/IrrigationCC.js.map +2 -2
- package/build/cjs/cc/LanguageCC.js.map +2 -2
- package/build/cjs/cc/LockCC.js.map +2 -2
- package/build/cjs/cc/ManufacturerProprietaryCC.js.map +2 -2
- package/build/cjs/cc/ManufacturerSpecificCC.js.map +2 -2
- package/build/cjs/cc/MeterCC.js.map +2 -2
- package/build/cjs/cc/MultiChannelAssociationCC.d.ts +2 -0
- package/build/cjs/cc/MultiChannelAssociationCC.js +6 -0
- package/build/cjs/cc/MultiChannelAssociationCC.js.map +2 -2
- package/build/cjs/cc/MultiChannelCC.d.ts +10 -0
- package/build/cjs/cc/MultiChannelCC.js +65 -0
- package/build/cjs/cc/MultiChannelCC.js.map +2 -2
- package/build/cjs/cc/MultiCommandCC.d.ts +4 -0
- package/build/cjs/cc/MultiCommandCC.js +34 -1
- package/build/cjs/cc/MultiCommandCC.js.map +2 -2
- package/build/cjs/cc/MultilevelSensorCC.js.map +2 -2
- package/build/cjs/cc/MultilevelSwitchCC.js.map +2 -2
- package/build/cjs/cc/NodeNamingCC.js.map +2 -2
- package/build/cjs/cc/NotificationCC.js.map +2 -2
- package/build/cjs/cc/PowerlevelCC.js.map +2 -2
- package/build/cjs/cc/ProtectionCC.js.map +2 -2
- package/build/cjs/cc/SceneActivationCC.js.map +2 -2
- package/build/cjs/cc/SceneActuatorConfigurationCC.js.map +2 -2
- package/build/cjs/cc/SceneControllerConfigurationCC.js.map +2 -2
- package/build/cjs/cc/ScheduleEntryLockCC.js.map +2 -2
- package/build/cjs/cc/Security2CC.d.ts +7 -1
- package/build/cjs/cc/Security2CC.js +383 -52
- package/build/cjs/cc/Security2CC.js.map +2 -2
- package/build/cjs/cc/SecurityCC.d.ts +7 -0
- package/build/cjs/cc/SecurityCC.js +101 -6
- package/build/cjs/cc/SecurityCC.js.map +2 -2
- package/build/cjs/cc/SoundSwitchCC.js.map +2 -2
- package/build/cjs/cc/SupervisionCC.d.ts +4 -0
- package/build/cjs/cc/SupervisionCC.js +25 -0
- package/build/cjs/cc/SupervisionCC.js.map +2 -2
- package/build/cjs/cc/ThermostatFanModeCC.js.map +2 -2
- package/build/cjs/cc/ThermostatModeCC.js.map +2 -2
- package/build/cjs/cc/ThermostatSetbackCC.js.map +2 -2
- package/build/cjs/cc/ThermostatSetpointCC.js.map +2 -2
- package/build/cjs/cc/TimeCC.js.map +2 -2
- package/build/cjs/cc/TimeParametersCC.js.map +2 -2
- package/build/cjs/cc/TransportServiceCC.d.ts +5 -0
- package/build/cjs/cc/TransportServiceCC.js +13 -0
- package/build/cjs/cc/TransportServiceCC.js.map +2 -2
- package/build/cjs/cc/UserCodeCC.js.map +2 -2
- package/build/cjs/cc/VersionCC.js.map +2 -2
- package/build/cjs/cc/WakeUpCC.js.map +2 -2
- package/build/cjs/cc/WindowCoveringCC.js.map +2 -2
- package/build/cjs/cc/ZWavePlusCC.js.map +2 -2
- package/build/cjs/cc/ZWaveProtocolCC.js.map +2 -2
- package/build/cjs/cc/manufacturerProprietary/Decorators.js +6 -5
- package/build/cjs/cc/manufacturerProprietary/Decorators.js.map +2 -2
- package/build/cjs/cc/manufacturerProprietary/FibaroCC.js.map +2 -2
- package/build/cjs/lib/CommandClass.d.ts +15 -1
- package/build/cjs/lib/CommandClass.js +56 -1
- package/build/cjs/lib/CommandClass.js.map +2 -2
- package/build/cjs/lib/CommandClassDecorators.js +7 -6
- package/build/cjs/lib/CommandClassDecorators.js.map +2 -2
- package/build/cjs/lib/Security2/Extension.js +2 -2
- package/build/cjs/lib/Security2/Extension.js.map +2 -2
- package/build/esm/cc/AlarmSensorCC.d.ts.map +1 -1
- package/build/esm/cc/AlarmSensorCC.js +1 -0
- package/build/esm/cc/AlarmSensorCC.js.map +1 -1
- package/build/esm/cc/AssociationCC.d.ts +2 -0
- package/build/esm/cc/AssociationCC.d.ts.map +1 -1
- package/build/esm/cc/AssociationCC.js +14 -0
- package/build/esm/cc/AssociationCC.js.map +1 -1
- package/build/esm/cc/AssociationGroupInfoCC.d.ts.map +1 -1
- package/build/esm/cc/AssociationGroupInfoCC.js +6 -0
- package/build/esm/cc/AssociationGroupInfoCC.js.map +1 -1
- package/build/esm/cc/BarrierOperatorCC.d.ts.map +1 -1
- package/build/esm/cc/BarrierOperatorCC.js +3 -0
- package/build/esm/cc/BarrierOperatorCC.js.map +1 -1
- package/build/esm/cc/BasicCC.d.ts.map +1 -1
- package/build/esm/cc/BasicCC.js +2 -0
- package/build/esm/cc/BasicCC.js.map +1 -1
- package/build/esm/cc/BatteryCC.d.ts.map +1 -1
- package/build/esm/cc/BatteryCC.js +1 -0
- package/build/esm/cc/BatteryCC.js.map +1 -1
- package/build/esm/cc/BinarySensorCC.d.ts.map +1 -1
- package/build/esm/cc/BinarySensorCC.js +3 -0
- package/build/esm/cc/BinarySensorCC.js.map +1 -1
- package/build/esm/cc/BinarySwitchCC.d.ts.map +1 -1
- package/build/esm/cc/BinarySwitchCC.js +2 -0
- package/build/esm/cc/BinarySwitchCC.js.map +1 -1
- package/build/esm/cc/CRC16CC.d.ts +4 -0
- package/build/esm/cc/CRC16CC.d.ts.map +1 -1
- package/build/esm/cc/CRC16CC.js +30 -0
- package/build/esm/cc/CRC16CC.js.map +1 -1
- package/build/esm/cc/CentralSceneCC.d.ts.map +1 -1
- package/build/esm/cc/CentralSceneCC.js +1 -0
- package/build/esm/cc/CentralSceneCC.js.map +1 -1
- package/build/esm/cc/ClimateControlScheduleCC.d.ts.map +1 -1
- package/build/esm/cc/ClimateControlScheduleCC.js +3 -0
- package/build/esm/cc/ClimateControlScheduleCC.js.map +1 -1
- package/build/esm/cc/ClockCC.d.ts.map +1 -1
- package/build/esm/cc/ClockCC.js +1 -0
- package/build/esm/cc/ClockCC.js.map +1 -1
- package/build/esm/cc/ColorSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/ColorSwitchCC.js +6 -0
- package/build/esm/cc/ColorSwitchCC.js.map +1 -1
- package/build/esm/cc/ConfigurationCC.d.ts +4 -0
- package/build/esm/cc/ConfigurationCC.d.ts.map +1 -1
- package/build/esm/cc/ConfigurationCC.js +27 -0
- package/build/esm/cc/ConfigurationCC.js.map +1 -1
- package/build/esm/cc/DoorLockCC.d.ts.map +1 -1
- package/build/esm/cc/DoorLockCC.js +2 -0
- package/build/esm/cc/DoorLockCC.js.map +1 -1
- package/build/esm/cc/DoorLockLoggingCC.d.ts.map +1 -1
- package/build/esm/cc/DoorLockLoggingCC.js +1 -0
- package/build/esm/cc/DoorLockLoggingCC.js.map +1 -1
- package/build/esm/cc/EnergyProductionCC.d.ts.map +1 -1
- package/build/esm/cc/EnergyProductionCC.js +2 -0
- package/build/esm/cc/EnergyProductionCC.js.map +1 -1
- package/build/esm/cc/EntryControlCC.d.ts.map +1 -1
- package/build/esm/cc/EntryControlCC.js +1 -0
- package/build/esm/cc/EntryControlCC.js.map +1 -1
- package/build/esm/cc/FirmwareUpdateMetaDataCC.d.ts.map +1 -1
- package/build/esm/cc/FirmwareUpdateMetaDataCC.js +5 -0
- package/build/esm/cc/FirmwareUpdateMetaDataCC.js.map +1 -1
- package/build/esm/cc/HumidityControlModeCC.d.ts.map +1 -1
- package/build/esm/cc/HumidityControlModeCC.js +1 -0
- package/build/esm/cc/HumidityControlModeCC.js.map +1 -1
- package/build/esm/cc/HumidityControlSetpointCC.d.ts.map +1 -1
- package/build/esm/cc/HumidityControlSetpointCC.js +4 -0
- package/build/esm/cc/HumidityControlSetpointCC.js.map +1 -1
- package/build/esm/cc/InclusionControllerCC.d.ts.map +1 -1
- package/build/esm/cc/InclusionControllerCC.js +2 -0
- package/build/esm/cc/InclusionControllerCC.js.map +1 -1
- package/build/esm/cc/IndicatorCC.d.ts.map +1 -1
- package/build/esm/cc/IndicatorCC.js +7 -0
- package/build/esm/cc/IndicatorCC.js.map +1 -1
- package/build/esm/cc/IrrigationCC.d.ts.map +1 -1
- package/build/esm/cc/IrrigationCC.js +9 -0
- package/build/esm/cc/IrrigationCC.js.map +1 -1
- package/build/esm/cc/LanguageCC.d.ts.map +1 -1
- package/build/esm/cc/LanguageCC.js +1 -0
- package/build/esm/cc/LanguageCC.js.map +1 -1
- package/build/esm/cc/LockCC.d.ts.map +1 -1
- package/build/esm/cc/LockCC.js +1 -0
- package/build/esm/cc/LockCC.js.map +1 -1
- package/build/esm/cc/ManufacturerProprietaryCC.d.ts.map +1 -1
- package/build/esm/cc/ManufacturerProprietaryCC.js +2 -0
- package/build/esm/cc/ManufacturerProprietaryCC.js.map +1 -1
- package/build/esm/cc/ManufacturerSpecificCC.d.ts.map +1 -1
- package/build/esm/cc/ManufacturerSpecificCC.js +2 -0
- package/build/esm/cc/ManufacturerSpecificCC.js.map +1 -1
- package/build/esm/cc/MeterCC.d.ts.map +1 -1
- package/build/esm/cc/MeterCC.js +4 -0
- package/build/esm/cc/MeterCC.js.map +1 -1
- package/build/esm/cc/MultiChannelAssociationCC.d.ts +2 -0
- package/build/esm/cc/MultiChannelAssociationCC.d.ts.map +1 -1
- package/build/esm/cc/MultiChannelAssociationCC.js +17 -0
- package/build/esm/cc/MultiChannelAssociationCC.js.map +1 -1
- package/build/esm/cc/MultiChannelCC.d.ts +10 -0
- package/build/esm/cc/MultiChannelCC.d.ts.map +1 -1
- package/build/esm/cc/MultiChannelCC.js +94 -0
- package/build/esm/cc/MultiChannelCC.js.map +1 -1
- package/build/esm/cc/MultiCommandCC.d.ts +4 -0
- package/build/esm/cc/MultiCommandCC.d.ts.map +1 -1
- package/build/esm/cc/MultiCommandCC.js +35 -1
- package/build/esm/cc/MultiCommandCC.js.map +1 -1
- package/build/esm/cc/MultilevelSensorCC.d.ts.map +1 -1
- package/build/esm/cc/MultilevelSensorCC.js +5 -0
- package/build/esm/cc/MultilevelSensorCC.js.map +1 -1
- package/build/esm/cc/MultilevelSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/MultilevelSwitchCC.js +4 -0
- package/build/esm/cc/MultilevelSwitchCC.js.map +1 -1
- package/build/esm/cc/NodeNamingCC.d.ts.map +1 -1
- package/build/esm/cc/NodeNamingCC.js +2 -0
- package/build/esm/cc/NodeNamingCC.js.map +1 -1
- package/build/esm/cc/NotificationCC.d.ts.map +1 -1
- package/build/esm/cc/NotificationCC.js +9 -0
- package/build/esm/cc/NotificationCC.js.map +1 -1
- package/build/esm/cc/PowerlevelCC.d.ts.map +1 -1
- package/build/esm/cc/PowerlevelCC.js +4 -0
- package/build/esm/cc/PowerlevelCC.js.map +1 -1
- package/build/esm/cc/ProtectionCC.d.ts.map +1 -1
- package/build/esm/cc/ProtectionCC.js +3 -0
- package/build/esm/cc/ProtectionCC.js.map +1 -1
- package/build/esm/cc/SceneActivationCC.d.ts.map +1 -1
- package/build/esm/cc/SceneActivationCC.js +1 -0
- package/build/esm/cc/SceneActivationCC.js.map +1 -1
- package/build/esm/cc/SceneActuatorConfigurationCC.d.ts.map +1 -1
- package/build/esm/cc/SceneActuatorConfigurationCC.js +2 -0
- package/build/esm/cc/SceneActuatorConfigurationCC.js.map +1 -1
- package/build/esm/cc/SceneControllerConfigurationCC.d.ts.map +1 -1
- package/build/esm/cc/SceneControllerConfigurationCC.js +2 -0
- package/build/esm/cc/SceneControllerConfigurationCC.js.map +1 -1
- package/build/esm/cc/ScheduleEntryLockCC.d.ts.map +1 -1
- package/build/esm/cc/ScheduleEntryLockCC.js +14 -0
- package/build/esm/cc/ScheduleEntryLockCC.js.map +1 -1
- package/build/esm/cc/Security2CC.d.ts +7 -1
- package/build/esm/cc/Security2CC.d.ts.map +1 -1
- package/build/esm/cc/Security2CC.js +534 -68
- package/build/esm/cc/Security2CC.js.map +1 -1
- package/build/esm/cc/SecurityCC.d.ts +7 -0
- package/build/esm/cc/SecurityCC.d.ts.map +1 -1
- package/build/esm/cc/SecurityCC.js +133 -7
- package/build/esm/cc/SecurityCC.js.map +1 -1
- package/build/esm/cc/SoundSwitchCC.d.ts.map +1 -1
- package/build/esm/cc/SoundSwitchCC.js +7 -0
- package/build/esm/cc/SoundSwitchCC.js.map +1 -1
- package/build/esm/cc/SupervisionCC.d.ts +4 -0
- package/build/esm/cc/SupervisionCC.d.ts.map +1 -1
- package/build/esm/cc/SupervisionCC.js +30 -0
- package/build/esm/cc/SupervisionCC.js.map +1 -1
- package/build/esm/cc/ThermostatFanModeCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatFanModeCC.js +1 -0
- package/build/esm/cc/ThermostatFanModeCC.js.map +1 -1
- package/build/esm/cc/ThermostatModeCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatModeCC.js +3 -0
- package/build/esm/cc/ThermostatModeCC.js.map +1 -1
- package/build/esm/cc/ThermostatSetbackCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatSetbackCC.js +2 -0
- package/build/esm/cc/ThermostatSetbackCC.js.map +1 -1
- package/build/esm/cc/ThermostatSetpointCC.d.ts.map +1 -1
- package/build/esm/cc/ThermostatSetpointCC.js +6 -0
- package/build/esm/cc/ThermostatSetpointCC.js.map +1 -1
- package/build/esm/cc/TimeCC.d.ts.map +1 -1
- package/build/esm/cc/TimeCC.js +4 -0
- package/build/esm/cc/TimeCC.js.map +1 -1
- package/build/esm/cc/TimeParametersCC.d.ts.map +1 -1
- package/build/esm/cc/TimeParametersCC.js +1 -0
- package/build/esm/cc/TimeParametersCC.js.map +1 -1
- package/build/esm/cc/TransportServiceCC.d.ts +5 -0
- package/build/esm/cc/TransportServiceCC.d.ts.map +1 -1
- package/build/esm/cc/TransportServiceCC.js +24 -0
- package/build/esm/cc/TransportServiceCC.js.map +1 -1
- package/build/esm/cc/UserCodeCC.d.ts.map +1 -1
- package/build/esm/cc/UserCodeCC.js +12 -0
- package/build/esm/cc/UserCodeCC.js.map +1 -1
- package/build/esm/cc/VersionCC.d.ts.map +1 -1
- package/build/esm/cc/VersionCC.js +4 -0
- package/build/esm/cc/VersionCC.js.map +1 -1
- package/build/esm/cc/WakeUpCC.d.ts.map +1 -1
- package/build/esm/cc/WakeUpCC.js +1 -0
- package/build/esm/cc/WakeUpCC.js.map +1 -1
- package/build/esm/cc/WindowCoveringCC.d.ts.map +1 -1
- package/build/esm/cc/WindowCoveringCC.js +5 -0
- package/build/esm/cc/WindowCoveringCC.js.map +1 -1
- package/build/esm/cc/ZWavePlusCC.d.ts.map +1 -1
- package/build/esm/cc/ZWavePlusCC.js +1 -0
- package/build/esm/cc/ZWavePlusCC.js.map +1 -1
- package/build/esm/cc/ZWaveProtocolCC.d.ts.map +1 -1
- package/build/esm/cc/ZWaveProtocolCC.js +27 -0
- package/build/esm/cc/ZWaveProtocolCC.js.map +1 -1
- package/build/esm/cc/manufacturerProprietary/Decorators.d.ts.map +1 -1
- package/build/esm/cc/manufacturerProprietary/Decorators.js +2 -1
- package/build/esm/cc/manufacturerProprietary/Decorators.js.map +1 -1
- package/build/esm/cc/manufacturerProprietary/FibaroCC.d.ts.map +1 -1
- package/build/esm/cc/manufacturerProprietary/FibaroCC.js +3 -0
- package/build/esm/cc/manufacturerProprietary/FibaroCC.js.map +1 -1
- package/build/esm/lib/CommandClass.d.ts +15 -1
- package/build/esm/lib/CommandClass.d.ts.map +1 -1
- package/build/esm/lib/CommandClass.js +94 -1
- package/build/esm/lib/CommandClass.js.map +1 -1
- package/build/esm/lib/CommandClassDecorators.d.ts.map +1 -1
- package/build/esm/lib/CommandClassDecorators.js +2 -1
- package/build/esm/lib/CommandClassDecorators.js.map +1 -1
- package/build/esm/lib/Security2/Extension.js +1 -1
- package/build/esm/lib/Security2/Extension.js.map +1 -1
- package/package.json +6 -6
|
@@ -99,6 +99,7 @@ function bitMaskToSecurityClass(buffer, offset) {
|
|
|
99
99
|
(0, import_core.validatePayload)(keys.length === 1);
|
|
100
100
|
return keys[0];
|
|
101
101
|
}
|
|
102
|
+
const SECURITY_S2_AUTH_TAG_LENGTH = 8;
|
|
102
103
|
function getAuthenticationData(sendingNodeId, destination, homeId, commandLength, unencryptedPayload) {
|
|
103
104
|
const nodeIdSize = (0, import_core.isLongRangeNodeId)(sendingNodeId) || (0, import_core.isLongRangeNodeId)(destination) ? 2 : 1;
|
|
104
105
|
const ret = new import_safe2.Bytes(2 * nodeIdSize + 6 + unencryptedPayload.length);
|
|
@@ -145,14 +146,15 @@ function assertSecurityTX(ctx, destination) {
|
|
|
145
146
|
}
|
|
146
147
|
return ret;
|
|
147
148
|
}
|
|
148
|
-
function
|
|
149
|
+
function decryptSinglecastSync(ctx, securityManager, sendingNodeId, curSequenceNumber, prevSequenceNumber, ciphertext, authData, authTag, spanState, extensions) {
|
|
149
150
|
const decryptWithNonce = (nonce) => {
|
|
150
151
|
const { keyCCM: key } = securityManager.getKeysForNode(sendingNodeId);
|
|
151
152
|
const iv = nonce;
|
|
152
153
|
return {
|
|
153
154
|
key,
|
|
154
155
|
iv,
|
|
155
|
-
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
157
|
+
...(0, import_core.decryptAES128CCMSync)(key, iv, ciphertext, authData, authTag)
|
|
156
158
|
};
|
|
157
159
|
};
|
|
158
160
|
const getNonceAndDecrypt = () => {
|
|
@@ -223,17 +225,150 @@ function decryptSinglecast(ctx, securityManager, sendingNodeId, curSequenceNumbe
|
|
|
223
225
|
securityClass: void 0
|
|
224
226
|
};
|
|
225
227
|
}
|
|
226
|
-
function
|
|
228
|
+
async function decryptSinglecastAsync(ctx, securityManager, sendingNodeId, curSequenceNumber, prevSequenceNumber, ciphertext, authData, authTag, spanState, extensions) {
|
|
229
|
+
const decryptWithNonce = async (nonce) => {
|
|
230
|
+
const { keyCCM: key } = securityManager.getKeysForNode(sendingNodeId);
|
|
231
|
+
const iv = nonce;
|
|
232
|
+
return {
|
|
233
|
+
key,
|
|
234
|
+
iv,
|
|
235
|
+
...await (0, import_core.decryptAES128CCMAsync)(ciphertext, key, iv, authData, authTag)
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
const getNonceAndDecrypt = async () => {
|
|
239
|
+
const iv = await securityManager.nextNonceAsync(sendingNodeId);
|
|
240
|
+
return decryptWithNonce(iv);
|
|
241
|
+
};
|
|
242
|
+
if (spanState.type === import_core.SPANState.SPAN) {
|
|
243
|
+
if (
|
|
244
|
+
// The previous SPAN is still known, i.e. the node didn't send another command that was successfully decrypted
|
|
245
|
+
!!spanState.currentSPAN && spanState.currentSPAN.expires > (0, import_core.highResTimestamp)() && prevSequenceNumber != void 0 && curSequenceNumber === (prevSequenceNumber + 1 & 255) && !ctx.__internalIsMockNode
|
|
246
|
+
) {
|
|
247
|
+
const nonce = spanState.currentSPAN.nonce;
|
|
248
|
+
spanState.currentSPAN = void 0;
|
|
249
|
+
const result = await decryptWithNonce(nonce);
|
|
250
|
+
if (result.authOK) {
|
|
251
|
+
return {
|
|
252
|
+
...result,
|
|
253
|
+
securityClass: spanState.securityClass
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
spanState.currentSPAN = void 0;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
...await getNonceAndDecrypt(),
|
|
261
|
+
securityClass: spanState.securityClass
|
|
262
|
+
};
|
|
263
|
+
} else if (spanState.type === import_core.SPANState.LocalEI) {
|
|
264
|
+
const senderEI = getSenderEI(extensions);
|
|
265
|
+
if (!senderEI)
|
|
266
|
+
failNoSPAN();
|
|
267
|
+
const receiverEI = spanState.receiverEI;
|
|
268
|
+
const isBootstrappingNode = securityManager.tempKeys.has(sendingNodeId);
|
|
269
|
+
if (isBootstrappingNode) {
|
|
270
|
+
await securityManager.initializeTempSPANAsync(sendingNodeId, senderEI, receiverEI);
|
|
271
|
+
const ret = await getNonceAndDecrypt();
|
|
272
|
+
if (ret.authOK) {
|
|
273
|
+
return {
|
|
274
|
+
...ret,
|
|
275
|
+
securityClass: import_core.SecurityClass.Temporary
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
securityManager.setSPANState(sendingNodeId, spanState);
|
|
279
|
+
}
|
|
280
|
+
const possibleSecurityClasses = isBootstrappingNode ? [ctx.getHighestSecurityClass(sendingNodeId)] : import_core.securityClassOrder.filter((s) => ctx.hasSecurityClass(sendingNodeId, s) !== false);
|
|
281
|
+
for (const secClass of possibleSecurityClasses) {
|
|
282
|
+
if (!securityManager.hasKeysForSecurityClass(secClass)) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
await securityManager.initializeSPANAsync(sendingNodeId, secClass, senderEI, receiverEI);
|
|
286
|
+
const ret = await getNonceAndDecrypt();
|
|
287
|
+
if (ret.authOK) {
|
|
288
|
+
if (ctx.hasSecurityClass(sendingNodeId, secClass) === void 0) {
|
|
289
|
+
ctx.setSecurityClass(sendingNodeId, secClass, true);
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
...ret,
|
|
293
|
+
securityClass: secClass
|
|
294
|
+
};
|
|
295
|
+
} else {
|
|
296
|
+
securityManager.setSPANState(sendingNodeId, spanState);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
plaintext: new Uint8Array(),
|
|
302
|
+
authOK: false,
|
|
303
|
+
securityClass: void 0
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function decryptMulticastSync(sendingNodeId, securityManager, groupId, ciphertext, authData, authTag) {
|
|
227
307
|
const iv = securityManager.nextPeerMPAN(sendingNodeId, groupId);
|
|
228
308
|
const { keyCCM: key } = securityManager.getKeysForNode(sendingNodeId);
|
|
229
309
|
return {
|
|
230
310
|
key,
|
|
231
311
|
iv,
|
|
232
|
-
|
|
312
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
313
|
+
...(0, import_core.decryptAES128CCMSync)(key, iv, ciphertext, authData, authTag),
|
|
314
|
+
// The security class is irrelevant when decrypting multicast commands
|
|
315
|
+
securityClass: void 0
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async function decryptMulticastAsync(sendingNodeId, securityManager, groupId, ciphertext, authData, authTag) {
|
|
319
|
+
const iv = await securityManager.nextPeerMPANAsync(sendingNodeId, groupId);
|
|
320
|
+
const { keyCCM: key } = securityManager.getKeysForNode(sendingNodeId);
|
|
321
|
+
return {
|
|
322
|
+
key,
|
|
323
|
+
iv,
|
|
324
|
+
...await (0, import_core.decryptAES128CCMAsync)(ciphertext, key, iv, authData, authTag),
|
|
233
325
|
// The security class is irrelevant when decrypting multicast commands
|
|
234
326
|
securityClass: void 0
|
|
235
327
|
};
|
|
236
328
|
}
|
|
329
|
+
function parseExtensions(buffer, wasEncrypted) {
|
|
330
|
+
const extensions = [];
|
|
331
|
+
let mustDiscardCommand = false;
|
|
332
|
+
let offset = 0;
|
|
333
|
+
parsing: while (true) {
|
|
334
|
+
if (buffer.length < offset + 2) {
|
|
335
|
+
mustDiscardCommand = true;
|
|
336
|
+
break parsing;
|
|
337
|
+
}
|
|
338
|
+
const { actual: actualLength, expected: expectedLength } = import_Extension.Security2Extension.getExtensionLength(buffer.subarray(offset));
|
|
339
|
+
const extensionLength = expectedLength ?? actualLength;
|
|
340
|
+
if (extensionLength < 2) {
|
|
341
|
+
mustDiscardCommand = true;
|
|
342
|
+
break parsing;
|
|
343
|
+
} else if (extensionLength > buffer.length - offset - (wasEncrypted ? 0 : SECURITY_S2_AUTH_TAG_LENGTH)) {
|
|
344
|
+
mustDiscardCommand = true;
|
|
345
|
+
break parsing;
|
|
346
|
+
}
|
|
347
|
+
const extensionData = buffer.subarray(offset, offset + extensionLength);
|
|
348
|
+
offset += extensionLength;
|
|
349
|
+
const ext = import_Extension.Security2Extension.parse(extensionData);
|
|
350
|
+
switch ((0, import_Extension.validateS2Extension)(ext, wasEncrypted)) {
|
|
351
|
+
case import_Extension.ValidateS2ExtensionResult.OK:
|
|
352
|
+
if (expectedLength != void 0 && actualLength !== expectedLength) {
|
|
353
|
+
} else {
|
|
354
|
+
extensions.push(ext);
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
case import_Extension.ValidateS2ExtensionResult.DiscardExtension:
|
|
358
|
+
break;
|
|
359
|
+
case import_Extension.ValidateS2ExtensionResult.DiscardCommand:
|
|
360
|
+
mustDiscardCommand = true;
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
if (!ext.moreToFollow)
|
|
364
|
+
break parsing;
|
|
365
|
+
}
|
|
366
|
+
return {
|
|
367
|
+
extensions,
|
|
368
|
+
mustDiscardCommand,
|
|
369
|
+
bytesRead: offset
|
|
370
|
+
};
|
|
371
|
+
}
|
|
237
372
|
function getDestinationIDTX() {
|
|
238
373
|
if (this.isSinglecast())
|
|
239
374
|
return this.nodeId;
|
|
@@ -292,7 +427,7 @@ let Security2CCAPI = (() => {
|
|
|
292
427
|
if (!securityManager) {
|
|
293
428
|
throw new import_core.ZWaveError(`Nonces can only be sent if secure communication is set up!`, import_core.ZWaveErrorCodes.Driver_NoSecurity);
|
|
294
429
|
}
|
|
295
|
-
const receiverEI = securityManager.
|
|
430
|
+
const receiverEI = await securityManager.generateNonceAsync(this.endpoint.nodeId);
|
|
296
431
|
const cc = new Security2CCNonceReport({
|
|
297
432
|
nodeId: this.endpoint.nodeId,
|
|
298
433
|
endpointIndex: this.endpoint.index,
|
|
@@ -832,6 +967,7 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
832
967
|
throw new import_core.ZWaveError("Multicast Security S2 encapsulation requires the MGRP extension", import_core.ZWaveErrorCodes.Security2CC_MissingExtension);
|
|
833
968
|
}
|
|
834
969
|
}
|
|
970
|
+
/** @deprecated Use {@link fromAsync} instead */
|
|
835
971
|
static from(raw, ctx) {
|
|
836
972
|
const securityManager = assertSecurityRX(ctx);
|
|
837
973
|
(0, import_core.validatePayload)(raw.payload.length >= 2);
|
|
@@ -842,43 +978,12 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
842
978
|
let offset = 2;
|
|
843
979
|
const extensions = [];
|
|
844
980
|
let mustDiscardCommand = false;
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
const { actual: actualLength, expected: expectedLength } = import_Extension.Security2Extension.getExtensionLength(buffer.subarray(offset));
|
|
852
|
-
const extensionLength = expectedLength ?? actualLength;
|
|
853
|
-
if (extensionLength < 2) {
|
|
854
|
-
mustDiscardCommand = true;
|
|
855
|
-
return;
|
|
856
|
-
} else if (extensionLength > buffer.length - offset - (wasEncrypted ? 0 : import_core.SECURITY_S2_AUTH_TAG_LENGTH)) {
|
|
857
|
-
mustDiscardCommand = true;
|
|
858
|
-
return;
|
|
859
|
-
}
|
|
860
|
-
const extensionData = buffer.subarray(offset, offset + extensionLength);
|
|
861
|
-
offset += extensionLength;
|
|
862
|
-
const ext = import_Extension.Security2Extension.parse(extensionData);
|
|
863
|
-
switch ((0, import_Extension.validateS2Extension)(ext, wasEncrypted)) {
|
|
864
|
-
case import_Extension.ValidateS2ExtensionResult.OK:
|
|
865
|
-
if (expectedLength != void 0 && actualLength !== expectedLength) {
|
|
866
|
-
} else {
|
|
867
|
-
extensions.push(ext);
|
|
868
|
-
}
|
|
869
|
-
break;
|
|
870
|
-
case import_Extension.ValidateS2ExtensionResult.DiscardExtension:
|
|
871
|
-
break;
|
|
872
|
-
case import_Extension.ValidateS2ExtensionResult.DiscardCommand:
|
|
873
|
-
mustDiscardCommand = true;
|
|
874
|
-
break;
|
|
875
|
-
}
|
|
876
|
-
if (!ext.moreToFollow)
|
|
877
|
-
break;
|
|
878
|
-
}
|
|
879
|
-
};
|
|
880
|
-
if (hasExtensions)
|
|
881
|
-
parseExtensions(raw.payload, false);
|
|
981
|
+
if (hasExtensions) {
|
|
982
|
+
const parseResult = parseExtensions(raw.payload.subarray(offset), false);
|
|
983
|
+
extensions.push(...parseResult.extensions);
|
|
984
|
+
offset += parseResult.bytesRead;
|
|
985
|
+
mustDiscardCommand = parseResult.mustDiscardCommand;
|
|
986
|
+
}
|
|
882
987
|
const mcctx = (() => {
|
|
883
988
|
const multicastGroupId = getMulticastGroupId(extensions);
|
|
884
989
|
if (ctx.frameType === "multicast" || ctx.frameType === "broadcast") {
|
|
@@ -912,8 +1017,8 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
912
1017
|
}
|
|
913
1018
|
}
|
|
914
1019
|
const unencryptedPayload = raw.payload.subarray(0, offset);
|
|
915
|
-
const ciphertext = raw.payload.subarray(offset, -
|
|
916
|
-
const authTag = raw.payload.subarray(-
|
|
1020
|
+
const ciphertext = raw.payload.subarray(offset, -SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1021
|
+
const authTag = raw.payload.subarray(-SECURITY_S2_AUTH_TAG_LENGTH);
|
|
917
1022
|
const messageLength = 2 + raw.payload.length;
|
|
918
1023
|
const authData = getAuthenticationData(ctx.sourceNodeId, getDestinationIDRX(ctx, extensions), ctx.homeId, messageLength, unencryptedPayload);
|
|
919
1024
|
let decrypt;
|
|
@@ -922,7 +1027,10 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
922
1027
|
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: import_core.MPANState.OutOfSync });
|
|
923
1028
|
failNoMPAN();
|
|
924
1029
|
}
|
|
925
|
-
decrypt = () =>
|
|
1030
|
+
decrypt = () => (
|
|
1031
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1032
|
+
decryptMulticastSync(ctx.sourceNodeId, securityManager, mcctx.groupId, ciphertext, authData, authTag)
|
|
1033
|
+
);
|
|
926
1034
|
} else {
|
|
927
1035
|
const spanState = securityManager.getSPANState(ctx.sourceNodeId);
|
|
928
1036
|
if (spanState.type === import_core.SPANState.None) {
|
|
@@ -930,7 +1038,10 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
930
1038
|
} else if (spanState.type === import_core.SPANState.RemoteEI) {
|
|
931
1039
|
failNoSPAN();
|
|
932
1040
|
}
|
|
933
|
-
decrypt = () =>
|
|
1041
|
+
decrypt = () => (
|
|
1042
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1043
|
+
decryptSinglecastSync(ctx, securityManager, ctx.sourceNodeId, sequenceNumber, prevSequenceNumber, ciphertext, authData, authTag, spanState, extensions)
|
|
1044
|
+
);
|
|
934
1045
|
}
|
|
935
1046
|
let plaintext;
|
|
936
1047
|
let authOK = false;
|
|
@@ -963,8 +1074,12 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
963
1074
|
}
|
|
964
1075
|
const securityClass = decryptionSecurityClass;
|
|
965
1076
|
offset = 0;
|
|
966
|
-
if (hasEncryptedExtensions)
|
|
967
|
-
parseExtensions(plaintext, true);
|
|
1077
|
+
if (hasEncryptedExtensions) {
|
|
1078
|
+
const parseResult = parseExtensions(plaintext, true);
|
|
1079
|
+
extensions.push(...parseResult.extensions);
|
|
1080
|
+
offset += parseResult.bytesRead;
|
|
1081
|
+
mustDiscardCommand = parseResult.mustDiscardCommand;
|
|
1082
|
+
}
|
|
968
1083
|
if (mustDiscardCommand) {
|
|
969
1084
|
import_core.validatePayload.fail("Invalid extension");
|
|
970
1085
|
}
|
|
@@ -997,6 +1112,144 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
997
1112
|
ret.plaintext = decryptedCCBytes;
|
|
998
1113
|
return ret;
|
|
999
1114
|
}
|
|
1115
|
+
static async fromAsync(raw, ctx) {
|
|
1116
|
+
const securityManager = assertSecurityRX(ctx);
|
|
1117
|
+
(0, import_core.validatePayload)(raw.payload.length >= 2);
|
|
1118
|
+
const sequenceNumber = raw.payload[0];
|
|
1119
|
+
import_core.validatePayload.withReason("No security class granted")(ctx.getHighestSecurityClass(ctx.sourceNodeId) !== import_core.SecurityClass.None);
|
|
1120
|
+
const hasExtensions = !!(raw.payload[1] & 1);
|
|
1121
|
+
const hasEncryptedExtensions = !!(raw.payload[1] & 2);
|
|
1122
|
+
let offset = 2;
|
|
1123
|
+
const extensions = [];
|
|
1124
|
+
let mustDiscardCommand = false;
|
|
1125
|
+
if (hasExtensions) {
|
|
1126
|
+
const parseResult = parseExtensions(raw.payload.subarray(offset), false);
|
|
1127
|
+
extensions.push(...parseResult.extensions);
|
|
1128
|
+
offset += parseResult.bytesRead;
|
|
1129
|
+
mustDiscardCommand = parseResult.mustDiscardCommand;
|
|
1130
|
+
}
|
|
1131
|
+
const mcctx = (() => {
|
|
1132
|
+
const multicastGroupId = getMulticastGroupId(extensions);
|
|
1133
|
+
if (ctx.frameType === "multicast" || ctx.frameType === "broadcast") {
|
|
1134
|
+
if (multicastGroupId == void 0) {
|
|
1135
|
+
import_core.validatePayload.fail("Multicast frames without MGRP extension");
|
|
1136
|
+
}
|
|
1137
|
+
return {
|
|
1138
|
+
isMulticast: true,
|
|
1139
|
+
groupId: multicastGroupId
|
|
1140
|
+
};
|
|
1141
|
+
} else {
|
|
1142
|
+
return { isMulticast: false, groupId: multicastGroupId };
|
|
1143
|
+
}
|
|
1144
|
+
})();
|
|
1145
|
+
if (mustDiscardCommand) {
|
|
1146
|
+
if (mcctx.isMulticast) {
|
|
1147
|
+
await securityManager.nextPeerMPANAsync(ctx.sourceNodeId, mcctx.groupId);
|
|
1148
|
+
} else {
|
|
1149
|
+
await securityManager.nextNonceAsync(ctx.sourceNodeId);
|
|
1150
|
+
}
|
|
1151
|
+
import_core.validatePayload.fail("Invalid S2 extension");
|
|
1152
|
+
}
|
|
1153
|
+
let prevSequenceNumber;
|
|
1154
|
+
let mpanState;
|
|
1155
|
+
if (mcctx.isMulticast) {
|
|
1156
|
+
mpanState = securityManager.getPeerMPAN(ctx.sourceNodeId, mcctx.groupId);
|
|
1157
|
+
} else {
|
|
1158
|
+
prevSequenceNumber = validateSequenceNumber(securityManager, ctx.sourceNodeId, sequenceNumber);
|
|
1159
|
+
if (mcctx.groupId == void 0) {
|
|
1160
|
+
securityManager.resetOutOfSyncMPANs(ctx.sourceNodeId);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
const unencryptedPayload = raw.payload.subarray(0, offset);
|
|
1164
|
+
const ciphertext = raw.payload.subarray(offset, -SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1165
|
+
const authTag = raw.payload.subarray(-SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1166
|
+
const messageLength = 2 + raw.payload.length;
|
|
1167
|
+
const authData = getAuthenticationData(ctx.sourceNodeId, getDestinationIDRX(ctx, extensions), ctx.homeId, messageLength, unencryptedPayload);
|
|
1168
|
+
let decrypt;
|
|
1169
|
+
if (mcctx.isMulticast) {
|
|
1170
|
+
if (mpanState?.type !== import_core.MPANState.MPAN) {
|
|
1171
|
+
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: import_core.MPANState.OutOfSync });
|
|
1172
|
+
failNoMPAN();
|
|
1173
|
+
}
|
|
1174
|
+
decrypt = () => decryptMulticastAsync(ctx.sourceNodeId, securityManager, mcctx.groupId, ciphertext, authData, authTag);
|
|
1175
|
+
} else {
|
|
1176
|
+
const spanState = securityManager.getSPANState(ctx.sourceNodeId);
|
|
1177
|
+
if (spanState.type === import_core.SPANState.None) {
|
|
1178
|
+
failNoSPAN();
|
|
1179
|
+
} else if (spanState.type === import_core.SPANState.RemoteEI) {
|
|
1180
|
+
failNoSPAN();
|
|
1181
|
+
}
|
|
1182
|
+
decrypt = () => decryptSinglecastAsync(ctx, securityManager, ctx.sourceNodeId, sequenceNumber, prevSequenceNumber, ciphertext, authData, authTag, spanState, extensions);
|
|
1183
|
+
}
|
|
1184
|
+
let plaintext;
|
|
1185
|
+
let authOK = false;
|
|
1186
|
+
let key;
|
|
1187
|
+
let iv;
|
|
1188
|
+
let decryptionSecurityClass;
|
|
1189
|
+
const decryptAttempts = mcctx.isMulticast ? MAX_DECRYPT_ATTEMPTS_MULTICAST : mcctx.groupId != void 0 ? MAX_DECRYPT_ATTEMPTS_SC_FOLLOWUP : MAX_DECRYPT_ATTEMPTS_SINGLECAST;
|
|
1190
|
+
for (let i = 0; i < decryptAttempts; i++) {
|
|
1191
|
+
({
|
|
1192
|
+
plaintext,
|
|
1193
|
+
authOK,
|
|
1194
|
+
key,
|
|
1195
|
+
iv,
|
|
1196
|
+
securityClass: decryptionSecurityClass
|
|
1197
|
+
} = await decrypt());
|
|
1198
|
+
if (!!authOK && !!plaintext)
|
|
1199
|
+
break;
|
|
1200
|
+
if (!!getSenderEI(extensions))
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
if (!authOK || !plaintext) {
|
|
1204
|
+
if (mcctx.isMulticast) {
|
|
1205
|
+
securityManager.storePeerMPAN(ctx.sourceNodeId, mcctx.groupId, { type: import_core.MPANState.OutOfSync });
|
|
1206
|
+
import_core.validatePayload.fail(import_core.ZWaveErrorCodes.Security2CC_CannotDecodeMulticast);
|
|
1207
|
+
} else {
|
|
1208
|
+
import_core.validatePayload.fail(import_core.ZWaveErrorCodes.Security2CC_CannotDecode);
|
|
1209
|
+
}
|
|
1210
|
+
} else if (!mcctx.isMulticast && mcctx.groupId != void 0) {
|
|
1211
|
+
securityManager.tryIncrementPeerMPAN(ctx.sourceNodeId, mcctx.groupId);
|
|
1212
|
+
}
|
|
1213
|
+
const securityClass = decryptionSecurityClass;
|
|
1214
|
+
offset = 0;
|
|
1215
|
+
if (hasEncryptedExtensions) {
|
|
1216
|
+
const parseResult = parseExtensions(plaintext, true);
|
|
1217
|
+
extensions.push(...parseResult.extensions);
|
|
1218
|
+
offset += parseResult.bytesRead;
|
|
1219
|
+
mustDiscardCommand = parseResult.mustDiscardCommand;
|
|
1220
|
+
}
|
|
1221
|
+
if (mustDiscardCommand) {
|
|
1222
|
+
import_core.validatePayload.fail("Invalid extension");
|
|
1223
|
+
}
|
|
1224
|
+
if (!mcctx.isMulticast) {
|
|
1225
|
+
const mpanExtension = extensions.find((e) => e instanceof import_Extension.MPANExtension);
|
|
1226
|
+
if (mpanExtension) {
|
|
1227
|
+
securityManager.storePeerMPAN(ctx.sourceNodeId, mpanExtension.groupId, {
|
|
1228
|
+
type: import_core.MPANState.MPAN,
|
|
1229
|
+
currentMPAN: mpanExtension.innerMPANState
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
const decryptedCCBytes = plaintext.subarray(offset);
|
|
1234
|
+
let encapsulated;
|
|
1235
|
+
if (decryptedCCBytes.length > 0) {
|
|
1236
|
+
(0, import_core.validatePayload)(decryptedCCBytes.length >= 2);
|
|
1237
|
+
encapsulated = await import_CommandClass.CommandClass.parseAsync(decryptedCCBytes, ctx);
|
|
1238
|
+
}
|
|
1239
|
+
const ret = new Security2CCMessageEncapsulation2({
|
|
1240
|
+
nodeId: ctx.sourceNodeId,
|
|
1241
|
+
sequenceNumber,
|
|
1242
|
+
securityClass,
|
|
1243
|
+
extensions,
|
|
1244
|
+
encapsulated
|
|
1245
|
+
});
|
|
1246
|
+
ret.key = key;
|
|
1247
|
+
ret.iv = iv;
|
|
1248
|
+
ret.authData = authData;
|
|
1249
|
+
ret.authTag = authTag;
|
|
1250
|
+
ret.plaintext = decryptedCCBytes;
|
|
1251
|
+
return ret;
|
|
1252
|
+
}
|
|
1000
1253
|
securityClass;
|
|
1001
1254
|
// Only used for testing/debugging purposes
|
|
1002
1255
|
key;
|
|
@@ -1034,7 +1287,8 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
1034
1287
|
getMulticastGroupId() {
|
|
1035
1288
|
return getMulticastGroupId(this.extensions);
|
|
1036
1289
|
}
|
|
1037
|
-
|
|
1290
|
+
/** @deprecated Use {@link maybeAddSPANExtensionAsync} instead */
|
|
1291
|
+
maybeAddSPANExtensionSync(ctx, securityManager) {
|
|
1038
1292
|
if (!this.isSinglecast())
|
|
1039
1293
|
return;
|
|
1040
1294
|
const receiverNodeId = this.nodeId;
|
|
@@ -1062,10 +1316,39 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
1062
1316
|
}
|
|
1063
1317
|
}
|
|
1064
1318
|
}
|
|
1319
|
+
async maybeAddSPANExtensionAsync(ctx, securityManager) {
|
|
1320
|
+
if (!this.isSinglecast())
|
|
1321
|
+
return;
|
|
1322
|
+
const receiverNodeId = this.nodeId;
|
|
1323
|
+
const spanState = securityManager.getSPANState(receiverNodeId);
|
|
1324
|
+
if (spanState.type === import_core.SPANState.None || spanState.type === import_core.SPANState.LocalEI) {
|
|
1325
|
+
throw new import_core.ZWaveError(`Security S2 CC requires the receiver's nonce to be sent!`, import_core.ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
1326
|
+
} else if (spanState.type === import_core.SPANState.RemoteEI) {
|
|
1327
|
+
const senderEI = await securityManager.generateNonceAsync(void 0);
|
|
1328
|
+
const receiverEI = spanState.receiverEI;
|
|
1329
|
+
if (this.securityClass == void 0 && securityManager.tempKeys.has(receiverNodeId)) {
|
|
1330
|
+
await securityManager.initializeTempSPANAsync(receiverNodeId, senderEI, receiverEI);
|
|
1331
|
+
} else {
|
|
1332
|
+
const securityClass = this.securityClass ?? ctx.getHighestSecurityClass(receiverNodeId);
|
|
1333
|
+
if (securityClass == void 0) {
|
|
1334
|
+
throw new import_core.ZWaveError("No security class defined for this command!", import_core.ZWaveErrorCodes.Security2CC_NoSPAN);
|
|
1335
|
+
}
|
|
1336
|
+
await securityManager.initializeSPANAsync(receiverNodeId, securityClass, senderEI, receiverEI);
|
|
1337
|
+
}
|
|
1338
|
+
let spanExtension = this.extensions.find((e) => e instanceof import_Extension.SPANExtension);
|
|
1339
|
+
if (spanExtension) {
|
|
1340
|
+
spanExtension.senderEI = senderEI;
|
|
1341
|
+
} else {
|
|
1342
|
+
spanExtension = new import_Extension.SPANExtension({ senderEI });
|
|
1343
|
+
this.extensions.push(spanExtension);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
/** @deprecated Use {@link serializeAsync} instead */
|
|
1065
1348
|
serialize(ctx) {
|
|
1066
1349
|
const securityManager = assertSecurityTX(ctx, this.nodeId);
|
|
1067
1350
|
this.ensureSequenceNumber(securityManager);
|
|
1068
|
-
this.
|
|
1351
|
+
this.maybeAddSPANExtensionSync(ctx, securityManager);
|
|
1069
1352
|
const unencryptedExtensions = this.extensions.filter((e) => !e.isEncrypted());
|
|
1070
1353
|
const encryptedExtensions = this.extensions.filter((e) => e.isEncrypted());
|
|
1071
1354
|
const unencryptedPayload = import_safe2.Bytes.concat([
|
|
@@ -1097,7 +1380,7 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
1097
1380
|
key = keyAndIV.key;
|
|
1098
1381
|
iv = keyAndIV.iv;
|
|
1099
1382
|
}
|
|
1100
|
-
const { ciphertext: ciphertextPayload, authTag } = (0, import_core.
|
|
1383
|
+
const { ciphertext: ciphertextPayload, authTag } = (0, import_core.encryptAES128CCMSync)(key, iv, plaintextPayload, authData, SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1101
1384
|
this.key = key;
|
|
1102
1385
|
this.iv = iv;
|
|
1103
1386
|
this.authData = authData;
|
|
@@ -1110,9 +1393,57 @@ let Security2CCMessageEncapsulation = (() => {
|
|
|
1110
1393
|
]);
|
|
1111
1394
|
return super.serialize(ctx);
|
|
1112
1395
|
}
|
|
1396
|
+
async serializeAsync(ctx) {
|
|
1397
|
+
const securityManager = assertSecurityTX(ctx, this.nodeId);
|
|
1398
|
+
this.ensureSequenceNumber(securityManager);
|
|
1399
|
+
await this.maybeAddSPANExtensionAsync(ctx, securityManager);
|
|
1400
|
+
const unencryptedExtensions = this.extensions.filter((e) => !e.isEncrypted());
|
|
1401
|
+
const encryptedExtensions = this.extensions.filter((e) => e.isEncrypted());
|
|
1402
|
+
const unencryptedPayload = import_safe2.Bytes.concat([
|
|
1403
|
+
import_safe2.Bytes.from([
|
|
1404
|
+
this.sequenceNumber,
|
|
1405
|
+
(encryptedExtensions.length > 0 ? 2 : 0) | (unencryptedExtensions.length > 0 ? 1 : 0)
|
|
1406
|
+
]),
|
|
1407
|
+
...unencryptedExtensions.map((e, index) => e.serialize(index < unencryptedExtensions.length - 1))
|
|
1408
|
+
]);
|
|
1409
|
+
const serializedCC = await this.encapsulated?.serializeAsync(ctx) ?? new import_safe2.Bytes();
|
|
1410
|
+
const plaintextPayload = import_safe2.Bytes.concat([
|
|
1411
|
+
...encryptedExtensions.map((e, index) => e.serialize(index < encryptedExtensions.length - 1)),
|
|
1412
|
+
serializedCC
|
|
1413
|
+
]);
|
|
1414
|
+
const destinationTag = getDestinationIDTX.call(this);
|
|
1415
|
+
const messageLength = this.computeEncapsulationOverhead() + serializedCC.length;
|
|
1416
|
+
const authData = getAuthenticationData(ctx.ownNodeId, destinationTag, ctx.homeId, messageLength, unencryptedPayload);
|
|
1417
|
+
let key;
|
|
1418
|
+
let iv;
|
|
1419
|
+
if (this.isSinglecast()) {
|
|
1420
|
+
iv = await securityManager.nextNonceAsync(this.nodeId, true);
|
|
1421
|
+
const { keyCCM } = (
|
|
1422
|
+
// Prefer the overridden security class if it was given
|
|
1423
|
+
this.securityClass != void 0 ? securityManager.getKeysForSecurityClass(this.securityClass) : securityManager.getKeysForNode(this.nodeId)
|
|
1424
|
+
);
|
|
1425
|
+
key = keyCCM;
|
|
1426
|
+
} else {
|
|
1427
|
+
const keyAndIV = await securityManager.getMulticastKeyAndIVAsync(destinationTag);
|
|
1428
|
+
key = keyAndIV.key;
|
|
1429
|
+
iv = keyAndIV.iv;
|
|
1430
|
+
}
|
|
1431
|
+
const { ciphertext: ciphertextPayload, authTag } = await (0, import_core.encryptAES128CCMAsync)(plaintextPayload, key, iv, authData, SECURITY_S2_AUTH_TAG_LENGTH);
|
|
1432
|
+
this.key = key;
|
|
1433
|
+
this.iv = iv;
|
|
1434
|
+
this.authData = authData;
|
|
1435
|
+
this.authTag = authTag;
|
|
1436
|
+
this.ciphertext = ciphertextPayload;
|
|
1437
|
+
this.payload = import_safe2.Bytes.concat([
|
|
1438
|
+
unencryptedPayload,
|
|
1439
|
+
ciphertextPayload,
|
|
1440
|
+
authTag
|
|
1441
|
+
]);
|
|
1442
|
+
return super.serializeAsync(ctx);
|
|
1443
|
+
}
|
|
1113
1444
|
computeEncapsulationOverhead() {
|
|
1114
1445
|
const extensionBytes = this.extensions.map((e) => e.computeLength()).reduce((a, b) => a + b, 0);
|
|
1115
|
-
return super.computeEncapsulationOverhead() + 2 +
|
|
1446
|
+
return super.computeEncapsulationOverhead() + 2 + SECURITY_S2_AUTH_TAG_LENGTH + extensionBytes;
|
|
1116
1447
|
}
|
|
1117
1448
|
toLogEntry(ctx) {
|
|
1118
1449
|
const message = {
|