UNPKG

resedit-cli

Version:

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

295 lines (294 loc) 9.91 kB
import { createRequire } from 'module'; import { CertificateSelectMode } from '../definitions/DefinitionData.js'; const require = createRequire(import.meta.url); const forge = require('node-forge'); export function makeChainList(list) { const map = new Map(); list.forEach((d) => { let c; if ('cert' in d && d.cert) { c = d.cert; } else if ('issuer' in d) { c = d; } else { return; } let me = map.get(c.subject.hash); if (!me) { me = { bag: d, subject: c.subject, children: [], }; map.set(me.subject.hash, me); } else { if (!me.bag) { me.bag = d; } } if (c.subject.hash !== c.issuer.hash) { let parent = map.get(c.issuer.hash); if (!parent) { parent = { subject: c.issuer, children: [me], }; map.set(parent.subject.hash, parent); } else { parent.children.push(me); } me.parent = parent; } }); const chainRoots = []; for (const temp of map.values()) { if (!temp.bag) { continue; } if (temp.parent) { if (temp.parent.bag) { delete temp.parent; continue; } delete temp.parent; } chainRoots.push(temp); } return chainRoots; } export function filterAndSortCertListByChain(list, certSelect) { const concatChainData = (prev, d) => { return prev .concat(d.bag) .concat(d.children.reduce(concatChainData, [])); }; let sortedCertLists = makeChainList(list).map((d) => concatChainData([], d).reverse()); switch (certSelect) { case CertificateSelectMode.NoRoot: sortedCertLists = sortedCertLists.map((a) => { return a.filter((elem) => { return 'cert' in elem ? elem.cert.subject.hash !== elem.cert.issuer.hash : elem.subject.hash !== elem.issuer.hash; }); }); break; case CertificateSelectMode.All: break; case CertificateSelectMode.Leaf: default: sortedCertLists = sortedCertLists.map((a) => a.slice(0, 1)); break; } return sortedCertLists.reduce((prev, list) => prev.concat(list), []); } function splitCertsFromPem(pemData) { const ret = []; let inSection = false; let tempText = ''; pemData.split(/\r\n|\n/g).forEach((line) => { if (/^-----BEGIN CERTIFICATE-----$/.test(line)) { inSection = true; tempText = line + '\n'; } else if (/^-----END CERTIFICATE-----$/.test(line)) { if (inSection) { inSection = false; ret.push(tempText + line + '\n'); } } else { if (inSection) { tempText += line + '\n'; } } }); return ret; } export function getCertificatesFromPem(pemData, certSelect) { const pems = splitCertsFromPem(pemData); if (pems.length === 0) { throw new Error('No certificates in PEM data'); } const sortedList = filterAndSortCertListByChain(pems.map((onePemData) => { return forge.pki.certificateFromPem(onePemData); }), certSelect); return sortedList.map((cert) => { const asn1 = forge.pki.certificateToAsn1(cert); return Buffer.from(forge.asn1.toDer(asn1).getBytes(), 'binary'); }); } export function verifyDERCertificates(bin, certSelect) { const asn1 = forge.asn1.fromDer(forge.util.createBuffer(bin.toString('binary'))); try { forge.pki.certificateFromAsn1(asn1); return bin; } catch (_a) { } try { const signedData = forge.pkcs7.messageFromAsn1(asn1); if (!('certificates' in signedData)) { throw new Error(); } const certificates = signedData.certificates; let asn1Cert; switch (certSelect) { case CertificateSelectMode.NoRoot: signedData.certificates = certificates.filter((cert) => { return cert.issuer.hash !== cert.subject.hash; }); asn1Cert = signedData.toAsn1(); break; case CertificateSelectMode.All: asn1Cert = asn1; break; case CertificateSelectMode.Leaf: default: asn1Cert = forge.pki.certificateToAsn1(certificates[0]); break; } return Buffer.from(forge.asn1.toDer(asn1Cert).getBytes(), 'binary'); } catch (_b) { throw new Error('Not supported certificate data'); } } function getPrivateKeyAlgorithmTypeFromBase64(data) { const bin = Buffer.from(data, 'base64'); const asn1 = forge.asn1.fromDer(forge.util.createBuffer(bin.toString('binary'))); if (asn1.type !== forge.asn1.Type.SEQUENCE || asn1.value.length !== 3) { return null; } const privateKeyAlgorithm = asn1.value[1]; if (privateKeyAlgorithm.type !== forge.asn1.Type.SEQUENCE || privateKeyAlgorithm.value.length !== 2) { return null; } const algorithm = privateKeyAlgorithm.value[0]; if (algorithm.type !== forge.asn1.Type.OID) { return null; } const oid = forge.asn1.derToOid(forge.util.createBuffer(algorithm.value)); if (oid === '1.2.840.113549.1.1.1') { return true; } else if (oid === '1.2.840.10040.4.1') { return false; } return null; } export function pickPrivateKeyFromPem(pemData) { const ret = []; let inSection = false; let isRSA = null; let tempText = ''; let tempTextHeader = ''; pemData.split(/\r\n|\n/g).forEach((line) => { if (/^-----BEGIN RSA PRIVATE KEY-----$/.test(line)) { if (!inSection) { inSection = true; isRSA = true; tempText = line + '\n'; } } else if (/^-----END RSA PRIVATE KEY-----$/.test(line)) { if (inSection) { inSection = false; if (isRSA) { ret.push([true, tempText + line + '\n']); } } } else if (/^-----BEGIN DSA PRIVATE KEY-----$/.test(line)) { if (!inSection) { inSection = true; isRSA = false; tempText = line + '\n'; } } else if (/^-----END DSA PRIVATE KEY-----$/.test(line)) { if (inSection) { inSection = false; if (isRSA === false) { ret.push([false, tempText + line + '\n']); } } } else if (/^-----BEGIN PRIVATE KEY-----$/.test(line)) { if (!inSection) { inSection = true; isRSA = null; tempTextHeader = line; tempText = ''; } } else if (/^-----END PRIVATE KEY-----$/.test(line)) { if (inSection) { inSection = false; if (isRSA === null) { isRSA = getPrivateKeyAlgorithmTypeFromBase64(tempText); if (isRSA !== null) { ret.push([ isRSA, tempTextHeader + '\n' + tempText + line + '\n', ]); } } } } else { if (inSection) { tempText += line + '\n'; } } }); return ret; } export function pickKeysFromP12File(p12Bin, certSelect, password) { var _a; const asn1 = forge.asn1.fromDer(forge.util.createBuffer(p12Bin.toString('binary'))); const p12 = forge.pkcs12.pkcs12FromAsn1(asn1, password); const pkeyBag = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag, }); const pkeyData = (_a = pkeyBag[forge.pki.oids.pkcs8ShroudedKeyBag]) === null || _a === void 0 ? void 0 : _a[0]; if (!(pkeyData === null || pkeyData === void 0 ? void 0 : pkeyData.key)) { throw new Error('No private key is found for p12 data'); } const privatePem = forge.pki .privateKeyToPem(pkeyData.key) .replace(/\r\n/g, '\n'); const certBag = p12.getBags({ bagType: forge.pki.oids.certBag }); const certList = certBag[forge.pki.oids.certBag]; const certsResult = []; if (certList) { const sortedCertList = filterAndSortCertListByChain(certList, certSelect); sortedCertList.forEach((certData) => { let asn1; if (certData.cert) { asn1 = forge.pki.certificateToAsn1(certData.cert); } else { asn1 = certData.asn1; } if (asn1) { const certBin = forge.asn1.toDer(asn1); certsResult.push(Buffer.from(certBin.getBytes(), 'binary')); } }); } if (certsResult.length === 0) { throw new Error('No certificates are found for p12 data.'); } return { certs: certsResult, privatePem, isRSA: true, password, }; }