import { Parser } from 'binary-parser-encoder'; import { CertificateChain } from './bcert'; import ECCKey from './ecc_key'; import * as fs from 'fs'; type RawDeviceV2 = { signature: string; version: number; group_certificate_length: number; group_certificate: Buffer; encryption_key: Buffer; signing_key: Buffer; }; class DeviceStructs { static magic = 'PRD'; static v1 = new Parser() .string('signature', { length: 3, assert: DeviceStructs.magic }) .uint8('version') .uint32('group_key_length') .buffer('group_key', { length: 'group_key_length' }) .uint32('group_certificate_length') .buffer('group_certificate', { length: 'group_certificate_length' }); static v2 = new Parser() .string('signature', { length: 3, assert: DeviceStructs.magic }) .uint8('version') .uint32('group_certificate_length') .buffer('group_certificate', { length: 'group_certificate_length' }) .buffer('encryption_key', { length: 96 }) .buffer('signing_key', { length: 96 }); static v3 = new Parser() .string('signature', { length: 3, assert: DeviceStructs.magic }) .uint8('version') .buffer('group_key', { length: 96 }) .buffer('encryption_key', { length: 96 }) .buffer('signing_key', { length: 96 }) .uint32('group_certificate_length') .buffer('group_certificate', { length: 'group_certificate_length' }); } export class Device { static CURRENT_STRUCT = DeviceStructs.v3; group_certificate: CertificateChain; encryption_key: ECCKey; signing_key: ECCKey; security_level: number; constructor(parsedData: RawDeviceV2) { this.group_certificate = CertificateChain.loads( parsedData.group_certificate ); this.encryption_key = ECCKey.loads(parsedData.encryption_key); this.signing_key = ECCKey.loads(parsedData.signing_key); this.security_level = this.group_certificate.get_security_level(); } static loads(data: Buffer): Device { const parsedData = Device.CURRENT_STRUCT.parse(data); return new Device(parsedData); } static load(filePath: string): Device { const data = fs.readFileSync(filePath); return Device.loads(data); } dumps(): Buffer { const groupCertBytes = this.group_certificate.dumps(); const encryptionKeyBytes = this.encryption_key.dumps(); const signingKeyBytes = this.signing_key.dumps(); const buildData = { signature: DeviceStructs.magic, version: 2, group_certificate_length: groupCertBytes.length, group_certificate: groupCertBytes, encryption_key: encryptionKeyBytes, signing_key: signingKeyBytes, }; return Device.CURRENT_STRUCT.encode(buildData); } dump(filePath: string): void { const data = this.dumps(); fs.writeFileSync(filePath, data); } get_name(): string { const name = `${this.group_certificate.get_name()}_sl${ this.security_level }`; return name.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase(); } } // Device V2 disabled because unstable provisioning // export class Device { // group_certificate: CertificateChain // encryption_key: ECCKey // signing_key: ECCKey // security_level: number // constructor(group_certificate: Buffer, group_key: Buffer) { // this.group_certificate = CertificateChain.loads(group_certificate) // this.encryption_key = ECCKey.generate() // this.signing_key = ECCKey.generate() // this.security_level = this.group_certificate.get_security_level() // const new_certificate = Certificate.new_key_cert( // randomBytes(16), // this.group_certificate.get_security_level(), // randomBytes(16), // this.signing_key, // this.encryption_key, // ECCKey.loads(group_key), // this.group_certificate // ) // this.group_certificate.prepend(new_certificate) // } // }