Merged all authenticode-js HTTP requests to a single location.

Ylian Saint-Hilaire committed Jun 23, 2022 at 13:04 UTC 156993666b88d98b863b8696e64dac4daab8264d
1 file changed +177 -210
authenticode.js
+177 -210
@@ -407,123 +407,100 @@ function createAuthenticodeHandler(path) {
407 const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64');
408
409 // Make an HTTP request
410 - const http = require('http');
411 - const timeServerUrl = new URL(args.time);
412 - const options = {
413 - protocol: timeServerUrl.protocol,
414 - hostname: timeServerUrl.hostname,
415 - path: timeServerUrl.pathname,
416 - port: ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)),
417 - method: 'POST',
418 - headers: {
419 - 'accept': 'application/octet-stream',
420 - 'cache-control': 'no-cache',
421 - 'user-agent': 'Transport',
422 - 'content-type': 'application/octet-stream',
423 - 'content-length': Buffer.byteLength(requestBody)
424 - }
425 - };
410 + const options = { url: args.time, proxy: args.proxy };
411
427 - // Set up the request
428 - var responseAccumulator = '';
429 - var req = http.request(options, function (res) {
430 - res.setEncoding('utf8');
431 - res.on('data', function (chunk) { responseAccumulator += chunk; });
432 - res.on('end', function () {
433 - // Decode the timestamp signature block
434 - var timepkcs7der = null;
435 - try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(responseAccumulator, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
412 + // Make a request to the time server
413 + httpRequest(options, requestBody, function (err, data) {
414 + if (err != null) { func(err); return; }
415
437 - // Decode the executable signature block
438 - var pkcs7der = null;
439 - try { pkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(obj.getRawSignatureBlock(), 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
416 + // Decode the timestamp signature block
417 + var timepkcs7der = null;
418 + try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(data, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
419
441 - // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
442 - // TODO: We could look to see if the certificate is already present in the executable
443 - const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
444 - for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
420 + // Decode the executable signature block
421 + var pkcs7der = null;
422 + try { pkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(obj.getRawSignatureBlock(), 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
423 +
424 + // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
425 + // TODO: We could look to see if the certificate is already present in the executable
426 + const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
427 + for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
428 +
429 + // Remove any existing time stamp signatures
430 + var newValues = [];
431 + for (var i in pkcs7der.value[1].value[0].value[4].value[0].value) {
432 + const j = pkcs7der.value[1].value[0].value[4].value[0].value[i];
433 + if ((j.tagClass != 128) || (j.type != 1)) { newValues.push(j); } // If this is not a time stamp, add it to out new list.
434 + }
435 + pkcs7der.value[1].value[0].value[4].value[0].value = newValues; // Set the new list
436
446 - // Remove any existing time stamp signatures
447 - var newValues = [];
448 - for (var i in pkcs7der.value[1].value[0].value[4].value[0].value) {
449 - const j = pkcs7der.value[1].value[0].value[4].value[0].value[i];
450 - if ((j.tagClass != 128) || (j.type != 1)) { newValues.push(j); } // If this is not a time stamp, add it to out new list.
451 - }
452 - pkcs7der.value[1].value[0].value[4].value[0].value = newValues; // Set the new list
437 + // Get the time signature and add it to the executables PKCS7
438 + const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
439 + const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
440 + const asn1obj2 =
441 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
442 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
443 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
444 + timeasn1Signature
445 + ])
446 + ]);
447 + pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
448
454 - // Get the time signature and add it to the executables PKCS7
455 - const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
456 - const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
457 - const asn1obj2 =
458 - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
459 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
460 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
461 - timeasn1Signature
462 - ])
463 - ]);
464 - pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
449 + // Re-encode the executable signature block
450 + const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
451
466 - // Re-encode the executable signature block
467 - const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
452 + // Open the output file
453 + var output = null;
454 + try { output = fs.openSync(args.out, 'w+'); } catch (ex) { }
455 + if (output == null) return false;
456 + var tmp, written = 0;
457 + var executableSize = obj.header.sigpos ? obj.header.sigpos : this.filesize;
458 +
459 + // Compute pre-header length and copy that to the new file
460 + var preHeaderLen = (obj.header.peHeaderLocation + 152 + (obj.header.pe32plus * 16));
461 + var tmp = readFileSlice(written, preHeaderLen);
462 + fs.writeSync(output, tmp);
463 + written += tmp.length;
464 +
465 + // Quad Align the results, adding padding if necessary
466 + var len = executableSize + p7signature.length;
467 + var padding = (8 - ((len) % 8)) % 8;
468
469 - // Open the output file
470 - var output = null;
471 - try { output = fs.openSync(args.out, 'w+'); } catch (ex) { }
472 - if (output == null) return false;
473 - var tmp, written = 0;
474 - var executableSize = obj.header.sigpos ? obj.header.sigpos : this.filesize;
469 + // Write the signature header
470 + var addresstable = Buffer.alloc(8);
471 + addresstable.writeUInt32LE(executableSize);
472 + addresstable.writeUInt32LE(8 + p7signature.length + padding, 4);
473 + fs.writeSync(output, addresstable);
474 + written += addresstable.length;
475
476 - // Compute pre-header length and copy that to the new file
477 - var preHeaderLen = (obj.header.peHeaderLocation + 152 + (obj.header.pe32plus * 16));
478 - var tmp = readFileSlice(written, preHeaderLen);
476 + // Copy the rest of the file until the start of the signature block
477 + while ((executableSize - written) > 0) {
478 + tmp = readFileSlice(written, Math.min(executableSize - written, 65536));
479 fs.writeSync(output, tmp);
480 written += tmp.length;
481 + }
482
482 - // Quad Align the results, adding padding if necessary
483 - var len = executableSize + p7signature.length;
484 - var padding = (8 - ((len) % 8)) % 8;
485 -
486 - // Write the signature header
487 - var addresstable = Buffer.alloc(8);
488 - addresstable.writeUInt32LE(executableSize);
489 - addresstable.writeUInt32LE(8 + p7signature.length + padding, 4);
490 - fs.writeSync(output, addresstable);
491 - written += addresstable.length;
492 -
493 - // Copy the rest of the file until the start of the signature block
494 - while ((executableSize - written) > 0) {
495 - tmp = readFileSlice(written, Math.min(executableSize - written, 65536));
496 - fs.writeSync(output, tmp);
497 - written += tmp.length;
498 - }
499 -
500 - // Write the signature block header and signature
501 - var win = Buffer.alloc(8); // WIN CERTIFICATE Structure
502 - win.writeUInt32LE(p7signature.length + padding + 8); // DWORD length
503 - win.writeUInt16LE(512, 4); // WORD revision
504 - win.writeUInt16LE(2, 6); // WORD type
505 - fs.writeSync(output, win);
506 - fs.writeSync(output, p7signature);
507 - if (padding > 0) { fs.writeSync(output, Buffer.alloc(padding, 0)); }
508 - written += (p7signature.length + padding + 8);
509 -
510 - // Compute the checksum and write it in the PE header checksum location
511 - var tmp = Buffer.alloc(4);
512 - tmp.writeUInt32LE(runChecksumOnFile(output, written, ((obj.header.peOptionalHeaderLocation + 64) / 4)));
513 - fs.writeSync(output, tmp, 0, 4, obj.header.peOptionalHeaderLocation + 64);
514 -
515 - // Close the file
516 - fs.closeSync(output);
517 -
518 - // Indicate we are done
519 - func(null);
520 - });
483 + // Write the signature block header and signature
484 + var win = Buffer.alloc(8); // WIN CERTIFICATE Structure
485 + win.writeUInt32LE(p7signature.length + padding + 8); // DWORD length
486 + win.writeUInt16LE(512, 4); // WORD revision
487 + win.writeUInt16LE(2, 6); // WORD type
488 + fs.writeSync(output, win);
489 + fs.writeSync(output, p7signature);
490 + if (padding > 0) { fs.writeSync(output, Buffer.alloc(padding, 0)); }
491 + written += (p7signature.length + padding + 8);
492 +
493 + // Compute the checksum and write it in the PE header checksum location
494 + var tmp = Buffer.alloc(4);
495 + tmp.writeUInt32LE(runChecksumOnFile(output, written, ((obj.header.peOptionalHeaderLocation + 64) / 4)));
496 + fs.writeSync(output, tmp, 0, 4, obj.header.peOptionalHeaderLocation + 64);
497 +
498 + // Close the file
499 + fs.closeSync(output);
500 +
501 + // Indicate we are done
502 + func(null);
503 });
522 -
523 - // Post the data
524 - req.on('error', function (err) { func('' + err); });
525 - req.write(requestBody);
526 - req.end();
504 }
505
506 // Read a resource table.
@@ -1330,63 +1307,76 @@ function createAuthenticodeHandler(path) {
1307 const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64');
1308
1309 // Make an HTTP request
1333 - const http = require('http');
1334 - const timeServerUrl = new URL(args.time);
1335 - const options = {
1336 - protocol: timeServerUrl.protocol,
1337 - hostname: timeServerUrl.hostname,
1338 - path: timeServerUrl.pathname,
1339 - port: ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)),
1340 - method: 'POST',
1341 - headers: {
1342 - 'accept': 'application/octet-stream',
1343 - 'cache-control': 'no-cache',
1344 - 'user-agent': 'Transport',
1345 - 'content-type': 'application/octet-stream',
1346 - 'content-length': Buffer.byteLength(requestBody)
1347 - }
1348 - };
1349 -
1350 - // Set up the request
1351 - var responseAccumulator = '';
1352 - var req = http.request(options, function (res) {
1353 - res.setEncoding('utf8');
1354 - res.on('data', function (chunk) { responseAccumulator += chunk; });
1355 - res.on('end', function () {
1356 - // Decode the timestamp signature block
1357 - var timepkcs7der = null;
1358 - try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(responseAccumulator, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
1310 + const options = { url: args.time, proxy: args.proxy };
1311
1360 - // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
1361 - // TODO: We could look to see if the certificate is already present in the executable
1362 - const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
1363 - for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
1312 + // Make a request to the time server
1313 + httpRequest(options, requestBody, function (err, data) {
1314 + if (err != null) { func(err); return; }
1315
1365 - // Get the time signature and add it to the executables PKCS7
1366 - const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
1367 - const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
1368 - const asn1obj2 =
1369 - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
1370 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1371 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
1372 - timeasn1Signature
1373 - ])
1374 - ]);
1375 - pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
1316 + // Decode the timestamp signature block
1317 + var timepkcs7der = null;
1318 + try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(data, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
1319
1377 - // Re-encode the executable signature block
1378 - const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
1320 + // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
1321 + // TODO: We could look to see if the certificate is already present in the executable
1322 + const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
1323 + for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
1324
1380 - // Write the file with the signature block
1381 - signEx(args, p7signature, obj.filesize, func);
1382 - });
1325 + // Get the time signature and add it to the executables PKCS7
1326 + const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
1327 + const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
1328 + const asn1obj2 =
1329 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
1330 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1331 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
1332 + timeasn1Signature
1333 + ])
1334 + ]);
1335 + pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
1336 +
1337 + // Re-encode the executable signature block
1338 + const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
1339 +
1340 + // Write the file with the signature block
1341 + signEx(args, p7signature, obj.filesize, func);
1342 });
1343 + }
1344 + }
1345
1385 - // Post the data
1386 - req.on('error', function (err) { func('' + err); });
1387 - req.write(requestBody);
1388 - req.end();
1346 + // Make a HTTP request, use a proxy if needed
1347 + function httpRequest(options, requestBody, func) {
1348 + // If needed, decode the URL
1349 + if (options.url) {
1350 + const timeServerUrl = new URL(options.url);
1351 + options.protocol = timeServerUrl.protocol;
1352 + options.hostname = timeServerUrl.hostname;
1353 + options.path = timeServerUrl.pathname;
1354 + options.port = ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port));
1355 + delete options.url;
1356 }
1357 +
1358 + // Setup the options
1359 + options.method = 'POST';
1360 + options.headers = {
1361 + 'accept': 'application/octet-stream',
1362 + 'cache-control': 'no-cache',
1363 + 'user-agent': 'Transport',
1364 + 'content-type': 'application/octet-stream',
1365 + 'content-length': Buffer.byteLength(requestBody)
1366 + };
1367 +
1368 + // Set up the request
1369 + var responseAccumulator = '';
1370 + var req = require('http').request(options, function (res) {
1371 + res.setEncoding('utf8');
1372 + res.on('data', function (chunk) { responseAccumulator += chunk; });
1373 + res.on('end', function () { func(null, responseAccumulator); });
1374 + });
1375 +
1376 + // Post the data
1377 + req.on('error', function (err) { func('' + err); });
1378 + req.write(requestBody);
1379 + req.end();
1380 }
1381
1382 function signEx(args, p7signature, filesize, func) {
@@ -1651,62 +1641,39 @@ function createAuthenticodeHandler(path) {
1641 const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64');
1642
1643 // Make an HTTP request
1654 - const http = require('http');
1655 - const timeServerUrl = new URL(args.time);
1656 - const options = {
1657 - protocol: timeServerUrl.protocol,
1658 - hostname: timeServerUrl.hostname,
1659 - path: timeServerUrl.pathname,
1660 - port: ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)),
1661 - method: 'POST',
1662 - headers: {
1663 - 'accept': 'application/octet-stream',
1664 - 'cache-control': 'no-cache',
1665 - 'user-agent': 'Transport',
1666 - 'content-type': 'application/octet-stream',
1667 - 'content-length': Buffer.byteLength(requestBody)
1668 - }
1669 - };
1670 -
1671 - // Set up the request
1672 - var responseAccumulator = '';
1673 - var req = http.request(options, function (res) {
1674 - res.setEncoding('utf8');
1675 - res.on('data', function (chunk) { responseAccumulator += chunk; });
1676 - res.on('end', function () {
1677 - // Decode the timestamp signature block
1678 - var timepkcs7der = null;
1679 - try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(responseAccumulator, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
1680 -
1681 - // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
1682 - // TODO: We could look to see if the certificate is already present in the executable
1683 - const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
1684 - for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
1685 -
1686 - // Get the time signature and add it to the executables PKCS7
1687 - const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
1688 - const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
1689 - const asn1obj2 =
1690 - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
1691 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1692 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
1693 - timeasn1Signature
1694 - ])
1695 - ]);
1696 - pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
1697 -
1698 - // Re-encode the executable signature block
1699 - const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
1700 -
1701 - // Write the file with the signature block
1702 - writeExecutableEx(output, p7signature, written, func);
1703 - });
1704 - });
1644 + const options = { url: args.time, proxy: args.proxy };
1645 +
1646 + // Make a request to the time server
1647 + httpRequest(options, requestBody, function (err, data) {
1648 + if (err != null) { func(err); return; }
1649 +
1650 + // Decode the timestamp signature block
1651 + var timepkcs7der = null;
1652 + try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(data, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
1653 +
1654 + // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
1655 + // TODO: We could look to see if the certificate is already present in the executable
1656 + const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
1657 + for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
1658 +
1659 + // Get the time signature and add it to the executables PKCS7
1660 + const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
1661 + const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
1662 + const asn1obj2 =
1663 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
1664 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1665 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
1666 + timeasn1Signature
1667 + ])
1668 + ]);
1669 + pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
1670 +
1671 + // Re-encode the executable signature block
1672 + const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
1673
1706 - // Post the data
1707 - req.on('error', function (err) { func('' + err); });
1708 - req.write(requestBody);
1709 - req.end();
1674 + // Write the file with the signature block
1675 + writeExecutableEx(output, p7signature, written, func);
1676 + });
1677 }
1678 return;
1679 }