Skip to content

Commit

Permalink
Validate binary provided to enable protection
Browse files Browse the repository at this point in the history
  • Loading branch information
keeramis committed Jun 28, 2024
1 parent df4af0e commit 45c117a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/cli/binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = ({ commandProcessor, root }) => {
params: '<filename>',
handler: (args) => {
const BinaryCommand = require('../cmd/binary');
return new BinaryCommand().inspectBinary(args.params.filename);
return new BinaryCommand().inspectApplicationBinary(args.params.filename);
},
examples: {
'$0 $command firmware.bin': 'Describe contents of firmware.bin'
Expand Down
55 changes: 51 additions & 4 deletions src/cmd/binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,37 @@ const fs = require('fs-extra');
const path = require('path');
const VError = require('verror');
const chalk = require('chalk');
const { HalModuleParser: Parser, unpackApplicationAndAssetBundle, isAssetValid, createProtectedModule } = require('binary-version-reader');
const { HalModuleParser: Parser, unpackApplicationAndAssetBundle, isAssetValid, createProtectedModule, ModuleInfo } = require('binary-version-reader');
const utilities = require('../lib/utilities');
const ensureError = utilities.ensureError;

const INVALID_SUFFIX_SIZE = 65535;
const DEFAULT_PRODUCT_ID = 65535;
const DEFAULT_PRODUCT_VERSION = 65535;

const PROTECTED_MINIMUM_VERSION = '6.0.0';
const PROTECTED_MINIMUM_BOOTLOADER_VERSION = 3000;

class BinaryCommand {
async inspectBinary(file) {
async inspectApplicationBinary(file) {
await this._checkFile(file);
const extractedFiles = await this._extractFiles(file);
const extractedFiles = await this._extractApplicationFiles(file);
const parsedAppInfo = await this._parseApplicationBinary(extractedFiles.application);
const assets = extractedFiles.assets;
await this._verifyBundle(parsedAppInfo, assets);
}

async inspectBinary(file) {
await this._checkFile(file);
const extractedFiles = await this._extractFile(file);
const parsedInfo = await this._parseBinary(extractedFiles.application);
return parsedInfo;
}

async createProtectedBinary({ saveTo, file, verbose }) {
await this._checkFile(file);
const binaryModule = this.inspectBinary(file);
this._validateProtectedBinary(binaryModule);
let resBinaryName;

if (saveTo) {
Expand All @@ -69,6 +81,21 @@ class BinaryCommand {
return resBinaryPath;
}

_validateProtectedBinary(module) {
const { moduleFunction, moduleVersion, moduleIndex } = module.prefixInfo;
if (moduleFunction !== ModuleInfo.FunctionType.BOOTLOADER) {
throw new Error('Device Protection can only be enabled on bootloaders. The file provided is not a bootloader.');
}

if (moduleIndex !== 0) {
throw new Error('Device Protection can only be enabled on bootloaders with module index 0. Please use the correct bootloader file.');
}

if (moduleVersion < PROTECTED_MINIMUM_BOOTLOADER_VERSION) {
throw new Error(`Device Protection can only be enabled on bootloader for device-os version ${PROTECTED_MINIMUM_VERSION} and later. The provided file is an older version.`);
}
}


async _checkFile(file) {
try {
Expand All @@ -79,7 +106,7 @@ class BinaryCommand {
return true;
}

async _extractFiles(file) {
async _extractApplicationFiles(file) {
if (utilities.getFilenameExt(file) === '.zip') {
return unpackApplicationAndAssetBundle(file);
} else if (utilities.getFilenameExt(file) === '.bin') {
Expand All @@ -90,6 +117,15 @@ class BinaryCommand {
}
}

async _extractFile(file) {
if (utilities.getFilenameExt(file) === '.bin') {
const data = await fs.readFile(file);
return { name: path.basename(file), data };
} else {
throw new VError(`File must be a .bin: ${file}`);
}
}

async _parseApplicationBinary(applicationBinary) {
const parser = new Parser();
let fileInfo;
Expand All @@ -110,6 +146,17 @@ class BinaryCommand {
return fileInfo;
}

async _parseBinary(binary) {
const parser = new Parser();
let fileInfo;
try {
fileInfo = await parser.parseBuffer({ filename: binary.name, fileBuffer: binary.data });
return fileInfo;
} catch (err) {
throw new VError(ensureError(err), `Could not parse ${binary.name}`);
}
}

async _verifyBundle(appInfo, assets) {
const appAssets = appInfo.assets;
if (appAssets && assets.length > 0) {
Expand Down

0 comments on commit 45c117a

Please sign in to comment.