UNPKG

resedit-cli

Version:

Command-line tool for editing Windows Resource data in executable binaries

108 lines (107 loc) 4.03 kB
import * as crypto from 'crypto'; import * as ResEdit from 'resedit'; import { readFile } from '../fs.js'; import * as log from '../log.js'; import requestTimestamp from './requestTimestamp.js'; import { getCertificatesFromPem, pickKeysFromP12File, pickPrivateKeyFromPem, verifyDERCertificates, } from './signUtil.js'; class MySignerObject { constructor(privateKeyPem, isRSA, certificates, digestAlgorithm, timestampServer) { this.privateKeyPem = privateKeyPem; this.isRSA = isRSA; this.certificates = certificates; this.digestAlgorithm = digestAlgorithm; if (timestampServer !== undefined) { this.timestampData = (reqData) => requestTimestamp(timestampServer, reqData); } } getDigestAlgorithm() { return this.digestAlgorithm; } getEncryptionAlgorithm() { return this.isRSA ? 'rsa' : 'dsa'; } getCertificateData() { return this.certificates; } async digestData(dataIterator) { const hash = crypto.createHash(this.digestAlgorithm); while (true) { const it = dataIterator.next(); if (it.done) { break; } hash.update(Buffer.from(it.value)); } return hash.digest(); } async encryptData(dataIterator) { const pkey = { key: this.privateKeyPem, }; const binArray = []; let totalLength = 0; while (true) { const it = dataIterator.next(); if (it.done) { break; } binArray.push(Buffer.from(it.value)); totalLength += it.value.byteLength; } return crypto.privateEncrypt(pkey, Buffer.concat(binArray, totalLength)); } } export async function prepareForSigningByP12(p12File, password, certSelect) { const p12Data = await readFile(p12File); try { return pickKeysFromP12File(p12Data, certSelect, password); } catch (e) { throw new Error(`Invalid or unsupported p12/pfx file '${p12File}' (detail: ${String(e == null ? '' : typeof e === 'object' && 'message' in e ? String(e.message) : e)})`); } } export async function prepareForSigning(privateKeyFile, certificateFile, password, certSelect) { const [pkeyFile, certFile] = await Promise.all([ readFile(privateKeyFile, 'utf8'), readFile(certificateFile), ]); const keys = pickPrivateKeyFromPem(pkeyFile); if (!keys.length) { throw new Error(`Invalid or unsupported private key file '${privateKeyFile}'.`); } const [isRSA, privatePem] = keys[0]; let certs; try { certs = [verifyDERCertificates(certFile, certSelect)]; } catch (_a) { try { certs = getCertificatesFromPem(certFile.toString('utf8'), certSelect); } catch (_b) { throw new Error(`Invalid or unsupported certificate file '${certificateFile}'.`); } } return { certs, privatePem, isRSA, password, }; } export async function prepare(defData) { if ('p12File' in defData) { return await prepareForSigningByP12(defData.p12File, defData.password, defData.certSelect); } else { return await prepareForSigning(defData.privateKeyFile, defData.certificateFile, defData.password, defData.certSelect); } } export function doSign(nt, data, digestAlgorithm, timestampServer) { log.debug(`[sign] isRSA = ${data.isRSA ? 'true' : 'false'}, cert count = ${data.certs.length}, digest algorithm = ${digestAlgorithm}, timestamp server = ${timestampServer !== null && timestampServer !== void 0 ? timestampServer : '(not use)'}`); return ResEdit.generateExecutableWithSign(nt, new MySignerObject(data.privatePem, data.isRSA, data.certs, digestAlgorithm, timestampServer)); }