1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-02-12 11:01:52 +00:00

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

This commit is contained in:
Ylian Saint-Hilaire 2022-06-23 13:04:48 -07:00
parent 89c152027f
commit 156993666b

View file

@ -407,123 +407,100 @@ function createAuthenticodeHandler(path) {
const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64'); const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64');
// Make an HTTP request // Make an HTTP request
const http = require('http'); const options = { url: args.time, proxy: args.proxy };
const timeServerUrl = new URL(args.time);
const options = { // Make a request to the time server
protocol: timeServerUrl.protocol, httpRequest(options, requestBody, function (err, data) {
hostname: timeServerUrl.hostname, if (err != null) { func(err); return; }
path: timeServerUrl.pathname,
port: ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)), // Decode the timestamp signature block
method: 'POST', var timepkcs7der = null;
headers: { try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(data, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
'accept': 'application/octet-stream',
'cache-control': 'no-cache', // Decode the executable signature block
'user-agent': 'Transport', var pkcs7der = null;
'content-type': 'application/octet-stream', try { pkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(obj.getRawSignatureBlock(), 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
'content-length': Buffer.byteLength(requestBody)
// Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
// TODO: We could look to see if the certificate is already present in the executable
const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
// Remove any existing time stamp signatures
var newValues = [];
for (var i in pkcs7der.value[1].value[0].value[4].value[0].value) {
const j = pkcs7der.value[1].value[0].value[4].value[0].value[i];
if ((j.tagClass != 128) || (j.type != 1)) { newValues.push(j); } // If this is not a time stamp, add it to out new list.
} }
}; pkcs7der.value[1].value[0].value[4].value[0].value = newValues; // Set the new list
// Set up the request // Get the time signature and add it to the executables PKCS7
var responseAccumulator = ''; const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
var req = http.request(options, function (res) { const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
res.setEncoding('utf8'); const asn1obj2 =
res.on('data', function (chunk) { responseAccumulator += chunk; }); asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
res.on('end', function () { asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
// Decode the timestamp signature block asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
var timepkcs7der = null; timeasn1Signature
try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(responseAccumulator, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; } ])
]);
pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
// Decode the executable signature block // Re-encode the executable signature block
var pkcs7der = null; const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
try { pkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(obj.getRawSignatureBlock(), 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
// Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable // Open the output file
// TODO: We could look to see if the certificate is already present in the executable var output = null;
const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value; try { output = fs.openSync(args.out, 'w+'); } catch (ex) { }
for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); } if (output == null) return false;
var tmp, written = 0;
var executableSize = obj.header.sigpos ? obj.header.sigpos : this.filesize;
// Remove any existing time stamp signatures // Compute pre-header length and copy that to the new file
var newValues = []; var preHeaderLen = (obj.header.peHeaderLocation + 152 + (obj.header.pe32plus * 16));
for (var i in pkcs7der.value[1].value[0].value[4].value[0].value) { var tmp = readFileSlice(written, preHeaderLen);
const j = pkcs7der.value[1].value[0].value[4].value[0].value[i]; fs.writeSync(output, tmp);
if ((j.tagClass != 128) || (j.type != 1)) { newValues.push(j); } // If this is not a time stamp, add it to out new list. written += tmp.length;
}
pkcs7der.value[1].value[0].value[4].value[0].value = newValues; // Set the new list
// Get the time signature and add it to the executables PKCS7 // Quad Align the results, adding padding if necessary
const timeasn1Signature = timepkcs7der.value[1].value[0].value[4]; var len = executableSize + p7signature.length;
const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data; var padding = (8 - ((len) % 8)) % 8;
const asn1obj2 =
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
timeasn1Signature
])
]);
pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
// Re-encode the executable signature block // Write the signature header
const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary'); var addresstable = Buffer.alloc(8);
addresstable.writeUInt32LE(executableSize);
addresstable.writeUInt32LE(8 + p7signature.length + padding, 4);
fs.writeSync(output, addresstable);
written += addresstable.length;
// Open the output file // Copy the rest of the file until the start of the signature block
var output = null; while ((executableSize - written) > 0) {
try { output = fs.openSync(args.out, 'w+'); } catch (ex) { } tmp = readFileSlice(written, Math.min(executableSize - written, 65536));
if (output == null) return false;
var tmp, written = 0;
var executableSize = obj.header.sigpos ? obj.header.sigpos : this.filesize;
// Compute pre-header length and copy that to the new file
var preHeaderLen = (obj.header.peHeaderLocation + 152 + (obj.header.pe32plus * 16));
var tmp = readFileSlice(written, preHeaderLen);
fs.writeSync(output, tmp); fs.writeSync(output, tmp);
written += tmp.length; written += tmp.length;
}
// Quad Align the results, adding padding if necessary // Write the signature block header and signature
var len = executableSize + p7signature.length; var win = Buffer.alloc(8); // WIN CERTIFICATE Structure
var padding = (8 - ((len) % 8)) % 8; win.writeUInt32LE(p7signature.length + padding + 8); // DWORD length
win.writeUInt16LE(512, 4); // WORD revision
win.writeUInt16LE(2, 6); // WORD type
fs.writeSync(output, win);
fs.writeSync(output, p7signature);
if (padding > 0) { fs.writeSync(output, Buffer.alloc(padding, 0)); }
written += (p7signature.length + padding + 8);
// Write the signature header // Compute the checksum and write it in the PE header checksum location
var addresstable = Buffer.alloc(8); var tmp = Buffer.alloc(4);
addresstable.writeUInt32LE(executableSize); tmp.writeUInt32LE(runChecksumOnFile(output, written, ((obj.header.peOptionalHeaderLocation + 64) / 4)));
addresstable.writeUInt32LE(8 + p7signature.length + padding, 4); fs.writeSync(output, tmp, 0, 4, obj.header.peOptionalHeaderLocation + 64);
fs.writeSync(output, addresstable);
written += addresstable.length;
// Copy the rest of the file until the start of the signature block // Close the file
while ((executableSize - written) > 0) { fs.closeSync(output);
tmp = readFileSlice(written, Math.min(executableSize - written, 65536));
fs.writeSync(output, tmp);
written += tmp.length;
}
// Write the signature block header and signature // Indicate we are done
var win = Buffer.alloc(8); // WIN CERTIFICATE Structure func(null);
win.writeUInt32LE(p7signature.length + padding + 8); // DWORD length
win.writeUInt16LE(512, 4); // WORD revision
win.writeUInt16LE(2, 6); // WORD type
fs.writeSync(output, win);
fs.writeSync(output, p7signature);
if (padding > 0) { fs.writeSync(output, Buffer.alloc(padding, 0)); }
written += (p7signature.length + padding + 8);
// Compute the checksum and write it in the PE header checksum location
var tmp = Buffer.alloc(4);
tmp.writeUInt32LE(runChecksumOnFile(output, written, ((obj.header.peOptionalHeaderLocation + 64) / 4)));
fs.writeSync(output, tmp, 0, 4, obj.header.peOptionalHeaderLocation + 64);
// Close the file
fs.closeSync(output);
// Indicate we are done
func(null);
});
}); });
// Post the data
req.on('error', function (err) { func('' + err); });
req.write(requestBody);
req.end();
} }
// Read a resource table. // Read a resource table.
@ -1330,65 +1307,78 @@ function createAuthenticodeHandler(path) {
const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64'); const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64');
// Make an HTTP request // Make an HTTP request
const http = require('http'); const options = { url: args.time, proxy: args.proxy };
const timeServerUrl = new URL(args.time);
const options = {
protocol: timeServerUrl.protocol,
hostname: timeServerUrl.hostname,
path: timeServerUrl.pathname,
port: ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)),
method: 'POST',
headers: {
'accept': 'application/octet-stream',
'cache-control': 'no-cache',
'user-agent': 'Transport',
'content-type': 'application/octet-stream',
'content-length': Buffer.byteLength(requestBody)
}
};
// Set up the request // Make a request to the time server
var responseAccumulator = ''; httpRequest(options, requestBody, function (err, data) {
var req = http.request(options, function (res) { if (err != null) { func(err); return; }
res.setEncoding('utf8');
res.on('data', function (chunk) { responseAccumulator += chunk; });
res.on('end', function () {
// Decode the timestamp signature block
var timepkcs7der = null;
try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(responseAccumulator, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
// Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable // Decode the timestamp signature block
// TODO: We could look to see if the certificate is already present in the executable var timepkcs7der = null;
const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value; try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(data, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
// Get the time signature and add it to the executables PKCS7 // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
const timeasn1Signature = timepkcs7der.value[1].value[0].value[4]; // TODO: We could look to see if the certificate is already present in the executable
const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data; const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
const asn1obj2 = for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
timeasn1Signature
])
]);
pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
// Re-encode the executable signature block // Get the time signature and add it to the executables PKCS7
const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary'); const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
const asn1obj2 =
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
timeasn1Signature
])
]);
pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
// Write the file with the signature block // Re-encode the executable signature block
signEx(args, p7signature, obj.filesize, func); const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
});
// Write the file with the signature block
signEx(args, p7signature, obj.filesize, func);
}); });
// Post the data
req.on('error', function (err) { func('' + err); });
req.write(requestBody);
req.end();
} }
} }
// Make a HTTP request, use a proxy if needed
function httpRequest(options, requestBody, func) {
// If needed, decode the URL
if (options.url) {
const timeServerUrl = new URL(options.url);
options.protocol = timeServerUrl.protocol;
options.hostname = timeServerUrl.hostname;
options.path = timeServerUrl.pathname;
options.port = ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port));
delete options.url;
}
// Setup the options
options.method = 'POST';
options.headers = {
'accept': 'application/octet-stream',
'cache-control': 'no-cache',
'user-agent': 'Transport',
'content-type': 'application/octet-stream',
'content-length': Buffer.byteLength(requestBody)
};
// Set up the request
var responseAccumulator = '';
var req = require('http').request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) { responseAccumulator += chunk; });
res.on('end', function () { func(null, responseAccumulator); });
});
// Post the data
req.on('error', function (err) { func('' + err); });
req.write(requestBody);
req.end();
}
function signEx(args, p7signature, filesize, func) { function signEx(args, p7signature, filesize, func) {
// Open the output file // Open the output file
var output = null; var output = null;
@ -1651,62 +1641,39 @@ function createAuthenticodeHandler(path) {
const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64'); const requestBody = Buffer.from(asn1.toDer(asn1obj).data, 'binary').toString('base64');
// Make an HTTP request // Make an HTTP request
const http = require('http'); const options = { url: args.time, proxy: args.proxy };
const timeServerUrl = new URL(args.time);
const options = {
protocol: timeServerUrl.protocol,
hostname: timeServerUrl.hostname,
path: timeServerUrl.pathname,
port: ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)),
method: 'POST',
headers: {
'accept': 'application/octet-stream',
'cache-control': 'no-cache',
'user-agent': 'Transport',
'content-type': 'application/octet-stream',
'content-length': Buffer.byteLength(requestBody)
}
};
// Set up the request // Make a request to the time server
var responseAccumulator = ''; httpRequest(options, requestBody, function (err, data) {
var req = http.request(options, function (res) { if (err != null) { func(err); return; }
res.setEncoding('utf8');
res.on('data', function (chunk) { responseAccumulator += chunk; });
res.on('end', function () {
// Decode the timestamp signature block
var timepkcs7der = null;
try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(responseAccumulator, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
// Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable // Decode the timestamp signature block
// TODO: We could look to see if the certificate is already present in the executable var timepkcs7der = null;
const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value; try { timepkcs7der = forge.asn1.fromDer(forge.util.createBuffer(Buffer.from(data, 'base64').toString('binary'))); } catch (ex) { func('' + ex); return; }
for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
// Get the time signature and add it to the executables PKCS7 // Get the ASN1 certificates used to sign the timestamp and add them to the certs in the PKCS7 of the executable
const timeasn1Signature = timepkcs7der.value[1].value[0].value[4]; // TODO: We could look to see if the certificate is already present in the executable
const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data; const timeasn1Certs = timepkcs7der.value[1].value[0].value[3].value;
const asn1obj2 = for (var i in timeasn1Certs) { pkcs7der.value[1].value[0].value[3].value.push(timeasn1Certs[i]); }
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
timeasn1Signature
])
]);
pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
// Re-encode the executable signature block // Get the time signature and add it to the executables PKCS7
const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary'); const timeasn1Signature = timepkcs7der.value[1].value[0].value[4];
const countersignatureOid = asn1.oidToDer('1.2.840.113549.1.9.6').data;
const asn1obj2 =
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, countersignatureOid),
timeasn1Signature
])
]);
pkcs7der.value[1].value[0].value[4].value[0].value.push(asn1obj2);
// Write the file with the signature block // Re-encode the executable signature block
writeExecutableEx(output, p7signature, written, func); const p7signature = Buffer.from(forge.asn1.toDer(pkcs7der).data, 'binary');
});
// Write the file with the signature block
writeExecutableEx(output, p7signature, written, func);
}); });
// Post the data
req.on('error', function (err) { func('' + err); });
req.write(requestBody);
req.end();
} }
return; return;
} }