resedit-cli
Version:
Command-line tool for editing Windows Resource data in executable binaries
108 lines (107 loc) • 4.03 kB
JavaScript
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));
}