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
}