UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

245 lines (222 loc) 6.36 kB
import * as crypto from "crypto"; import { ZWaveErrorCodes } from "../error/ZWaveError"; import { assertZWaveError } from "../test/assertZWaveError"; import { SecurityManager2 } from "./Manager2"; import { SecurityClass } from "./SecurityClass"; describe("lib/security/Manager2", () => { // beforeAll(() => { // jest.useFakeTimers(); // }); // afterAll(() => { // jest.clearAllTimers(); // jest.useRealTimers(); // }); function dummyInit( man: SecurityManager2, options: { keys?: boolean; nodeId?: number; secClass?: SecurityClass; multicastGroup?: number; } = {}, ): void { if (options.keys !== false) { man.setKey(SecurityClass.S0_Legacy, crypto.randomBytes(16)); man.setKey(SecurityClass.S2_AccessControl, crypto.randomBytes(16)); man.setKey(SecurityClass.S2_Authenticated, crypto.randomBytes(16)); man.setKey( SecurityClass.S2_Unauthenticated, crypto.randomBytes(16), ); } if (options.nodeId) { man.initializeSPAN( options.nodeId, options.secClass ?? SecurityClass.S2_Authenticated, crypto.randomBytes(16), crypto.randomBytes(16), ); } if (options.multicastGroup) { man.assignSecurityClassMulticast( options.multicastGroup, options.secClass ?? SecurityClass.S2_Authenticated, ); man.initializeMPAN(options.multicastGroup); } } describe("nextNonce", () => { it("should throw if the PRNG for the given receiver node has not been initialized", () => { const man = new SecurityManager2(); assertZWaveError(() => man.nextNonce(2), { errorCode: ZWaveErrorCodes.Security2CC_NotInitialized, messageMatches: "initialized", }); }); it("should generate a 13-byte nonce otherwise", () => { const man = new SecurityManager2(); dummyInit(man, { nodeId: 2, secClass: SecurityClass.S2_AccessControl, }); const ret = man.nextNonce(2); expect(Buffer.isBuffer(ret)).toBeTrue(); expect(ret.length).toBe(13); }); it("two nonces should be different", () => { const man = new SecurityManager2(); dummyInit(man, { nodeId: 2, secClass: SecurityClass.S2_AccessControl, }); const nonce1 = man.nextNonce(2); const nonce2 = man.nextNonce(2); expect(nonce1).not.toEqual(nonce2); }); }); describe("initializeSPAN", () => { it("should throw if either entropy input does not have length 16", () => { const man = new SecurityManager2(); const nodeId = 2; assertZWaveError( () => man.initializeSPAN( nodeId, SecurityClass.S2_Authenticated, Buffer.alloc(15), Buffer.alloc(16), ), { errorCode: ZWaveErrorCodes.Argument_Invalid, messageMatches: "16 bytes", }, ); assertZWaveError( () => man.initializeSPAN( nodeId, SecurityClass.S2_Authenticated, Buffer.alloc(16), Buffer.alloc(1), ), { errorCode: ZWaveErrorCodes.Argument_Invalid, messageMatches: "16 bytes", }, ); }); it("should throw if the node has not been assigned a security class", () => { const man = new SecurityManager2(); const nodeId = 2; assertZWaveError( () => man.initializeSPAN( nodeId, SecurityClass.S2_Authenticated, Buffer.alloc(16), Buffer.alloc(16), ), { errorCode: ZWaveErrorCodes.Security2CC_NotInitialized, messageMatches: "security class", }, ); }); it("should throw if the keys for the node's security class have not been set up", () => { const man = new SecurityManager2(); const nodeId = 2; assertZWaveError( () => man.initializeSPAN( nodeId, SecurityClass.S2_Authenticated, Buffer.alloc(16), Buffer.alloc(16), ), { errorCode: ZWaveErrorCodes.Security2CC_NotInitialized, messageMatches: "network key", }, ); }); it("should not throw otherwise", () => { const man = new SecurityManager2(); const nodeId = 2; dummyInit(man, { nodeId, secClass: SecurityClass.S2_Authenticated, }); expect(() => man.initializeSPAN( nodeId, SecurityClass.S2_Authenticated, Buffer.alloc(16), Buffer.alloc(16), ), ).not.toThrow(); }); }); describe("setKeys", () => { it("throws if the network key does not have length 16", () => { const man = new SecurityManager2(); assertZWaveError( () => man.setKey( SecurityClass.S2_Authenticated, Buffer.alloc(15), ), { errorCode: ZWaveErrorCodes.Argument_Invalid, messageMatches: "16 bytes", }, ); }); it("throws if the security class is not valid", () => { const man = new SecurityManager2(); assertZWaveError(() => man.setKey(-1 as any, Buffer.alloc(16)), { errorCode: ZWaveErrorCodes.Argument_Invalid, messageMatches: "security class", }); }); }); describe("nextMPAN", () => { it("should throw if the MPAN state for the given multicast group has not been initialized", () => { const man = new SecurityManager2(); assertZWaveError(() => man.nextMPAN(1), { errorCode: ZWaveErrorCodes.Security2CC_NotInitialized, messageMatches: "initialized", }); }); it("should throw if the multicast group has not been assigned to a security class", () => { const man = new SecurityManager2(); man.initializeMPAN(1); assertZWaveError(() => man.nextMPAN(1), { errorCode: ZWaveErrorCodes.Security2CC_NotInitialized, messageMatches: "security class", }); }); it("should throw if the keys for the group's security class have not been set up", () => { const man = new SecurityManager2(); man.assignSecurityClassMulticast(1, SecurityClass.S2_Authenticated); man.initializeMPAN(1); assertZWaveError(() => man.nextMPAN(1), { errorCode: ZWaveErrorCodes.Security2CC_NotInitialized, messageMatches: "network key", }); }); it("should generate a 16-byte buffer otherwise", () => { const man = new SecurityManager2(); dummyInit(man, { multicastGroup: 1 }); const ret = man.nextMPAN(1); expect(Buffer.isBuffer(ret)).toBeTrue(); expect(ret.length).toBe(16); }); it("two nonces should be different", () => { const man = new SecurityManager2(); dummyInit(man, { multicastGroup: 2 }); const nonce1 = man.nextMPAN(2); const nonce2 = man.nextMPAN(2); expect(nonce1).not.toEqual(nonce2); }); }); });