mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-01-13 16:03:20 -05:00
Added agent time stamping when signing a Windows agent.
This commit is contained in:
parent
de3d47e948
commit
18c11a344c
@ -486,7 +486,7 @@ function createAuthenticodeHandler(path) {
|
||||
fs.closeSync(output);
|
||||
|
||||
// Indicate we are done
|
||||
func(null);
|
||||
func(null, written);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1372,7 +1372,7 @@ function createAuthenticodeHandler(path) {
|
||||
|
||||
// Close the file
|
||||
fs.closeSync(output);
|
||||
func(null);
|
||||
func(null, written);
|
||||
}
|
||||
|
||||
// Save an executable without the signature
|
||||
@ -1635,7 +1635,7 @@ function createAuthenticodeHandler(path) {
|
||||
fs.closeSync(output);
|
||||
|
||||
// Indicate success
|
||||
func(null);
|
||||
func(null, written);
|
||||
}
|
||||
|
||||
function writeExecutableEx(output, p7signature, written, func) {
|
||||
@ -1669,7 +1669,7 @@ function createAuthenticodeHandler(path) {
|
||||
fs.closeSync(output);
|
||||
|
||||
// Indicate success
|
||||
func(null);
|
||||
func(null, written);
|
||||
}
|
||||
|
||||
// Return null if we could not open the file
|
||||
|
@ -101,6 +101,7 @@
|
||||
"agentCoreDump": { "type": "boolean", "default": false, "description": "Automatically activates and transfers any agent crash dump files to the server in meshcentral-data/coredumps." },
|
||||
"agentCoreDumpUsers": { "type": "array", "description": "List of non-administrator users that have access to mesh agent crash dumps." },
|
||||
"agentSignLock": { "type": "boolean", "default": false, "description": "When code signing an agent using authenticode, lock the agent to only allow connection to this server. (This is in testing, the default value will change to true in the future)." },
|
||||
"agentTimeStampServer": { "type": [ "boolean", "string" ], "default": "http://timestamp.comodoca.com/authenticode", "description": "The time stamping server to use when code signing Windows executables. When set to false, the executables are not time stamped." },
|
||||
"ignoreAgentHashCheck": { "type": [ "boolean", "string" ], "default": false, "description": "When true, the agent no longer checked the TLS certificate of the server. This should be used for debugging only. You can also set this to a comma seperated list of IP addresses to ignore, for example: \"192.168.2.100,192.168.1.0/24\"." },
|
||||
"exactPorts": { "type": "boolean", "default": false, "description": "When set to true, MeshCentral will only grab the required TCP listening ports or fail. It will not try to use the next available port of it's busy." },
|
||||
"allowLoginToken": { "type": "boolean", "default": false },
|
||||
|
@ -1617,6 +1617,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Load the list of mesh agents and install scripts
|
||||
if ((obj.args.noagentupdate == 1) || (obj.args.noagentupdate == true)) { for (i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } }
|
||||
obj.signMeshAgents(obj.config.domains[''], function () {
|
||||
obj.updateMeshAgentsTable(obj.config.domains[''], function () {
|
||||
obj.updateMeshAgentInstallScripts();
|
||||
|
||||
@ -1888,6 +1889,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Called when the web server finished loading
|
||||
@ -2841,24 +2843,29 @@ function CreateMeshCentralServer(config, args) {
|
||||
10006: { id: 10006, localname: 'MeshCentralAssistant.exe', rname: 'MeshCentralAssistant.exe', desc: 'MeshCentral Assistant for Windows', update: false, amt: false, platform: 'win32' } // MeshCentral Assistant
|
||||
};
|
||||
|
||||
// Update the list of available mesh agents
|
||||
obj.updateMeshAgentsTable = function (domain, func) {
|
||||
// Sign windows agents
|
||||
obj.signMeshAgents = function (domain, func) {
|
||||
// Setup the domain is specified
|
||||
var objx = domain, suffix = '';
|
||||
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
||||
|
||||
// Check if a custom agent signing certificate is available
|
||||
var agentSignCertInfo = require('./authenticode.js').loadCertificates([ obj.path.join(obj.datapath, 'agentsigningcert.pem') ]);
|
||||
var agentSignCertInfo = require('./authenticode.js').loadCertificates([obj.path.join(obj.datapath, 'agentsigningcert.pem')]);
|
||||
if (agentSignCertInfo == null) { func(); return; } // No code signing certificate, nothing to do.
|
||||
|
||||
// If not using a custom signing cert, get agent code signature certificate ready with the full cert chain
|
||||
if ((agentSignCertInfo == null) && (obj.certificates.codesign != null)) {
|
||||
agentSignCertInfo = {
|
||||
cert: obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.codesign.cert),
|
||||
key: obj.certificateOperations.forge.pki.privateKeyFromPem(obj.certificates.codesign.key),
|
||||
extraCerts: [obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.root.cert) ]
|
||||
extraCerts: [obj.certificateOperations.forge.pki.certificateFromPem(obj.certificates.root.cert)]
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the domain is specified
|
||||
var objx = domain, suffix = '';
|
||||
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
||||
|
||||
// Generate the agent signature description and URL
|
||||
var serverSignedAgentsPath, signDesc, signUrl;
|
||||
if (agentSignCertInfo != null) {
|
||||
@ -2877,12 +2884,17 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (obj.config.settings.agentsignlock) { signUrl += '?ServerID=' + obj.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert).toUpperCase(); }
|
||||
}
|
||||
|
||||
// Load agent information file. This includes the data & time of the agent.
|
||||
const agentInfo = [];
|
||||
try { agentInfo = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'hashagents.json'), 'utf8')); } catch (ex) { }
|
||||
// Setup the time server
|
||||
var timeStampUrl = 'http://timestamp.comodoca.com/authenticode';
|
||||
if (args.agenttimestampserver === false) { timeStampUrl = null; }
|
||||
else if (typeof args.agenttimestampserver == 'string') { timeStampUrl = args.agenttimestampserver; }
|
||||
|
||||
// Setup the pending operations counter
|
||||
var pendingOperations = 1;
|
||||
|
||||
var archcount = 0;
|
||||
for (var archid in obj.meshAgentsArchitectureNumbers) {
|
||||
if (obj.meshAgentsArchitectureNumbers[archid].codesign !== true) continue;
|
||||
|
||||
var agentpath;
|
||||
if (domain.id == '') {
|
||||
// Load all agents when processing the default domain
|
||||
@ -2895,13 +2907,6 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (obj.fs.existsSync(agentpath)) { delete obj.meshAgentsArchitectureNumbers[archid].codesign; } else { continue; } // If the agent is not present in "meshcentral-data/agents" skip.
|
||||
}
|
||||
|
||||
// Fetch agent binary information
|
||||
var stats = null;
|
||||
try { stats = obj.fs.statSync(agentpath); } catch (ex) { }
|
||||
if ((stats == null)) continue; // If this agent does not exist, skip it.
|
||||
|
||||
// Check if we need to sign this agent, if so, check if it's already been signed
|
||||
if ((obj.meshAgentsArchitectureNumbers[archid].codesign === true) && (agentSignCertInfo != null)) {
|
||||
// Open the original agent with authenticode
|
||||
var signeedagentpath = obj.path.join(serverSignedAgentsPath, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||
const originalAgent = require('./authenticode.js').createAuthenticodeHandler(agentpath);
|
||||
@ -2920,20 +2925,64 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (destinationAgentOk == false) {
|
||||
// If not signed correctly, sign it. First, create the server signed agent folder if needed
|
||||
try { obj.fs.mkdirSync(serverSignedAgentsPath); } catch (ex) { }
|
||||
if (originalAgent.sign(agentSignCertInfo, { out: signeedagentpath, desc: signDesc, url: signUrl }) == true) {
|
||||
const xagentSignedFunc = function agentSignedFunc(err, size) {
|
||||
if (err == null) {
|
||||
// Agent was signed succesfuly
|
||||
agentpath = signeedagentpath;
|
||||
console.log(obj.common.format('Code signed agent {0}.', obj.meshAgentsArchitectureNumbers[archid].localname));
|
||||
console.log(obj.common.format('Code signed agent {0}.', agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname));
|
||||
} else {
|
||||
console.log(obj.common.format('Failed to sign agent {0}.', obj.meshAgentsArchitectureNumbers[archid].localname));
|
||||
console.log(obj.common.format('Failed to sign agent {0}: ' + err, agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname));
|
||||
}
|
||||
if (--pendingOperations === 0) { agentSignedFunc.func(); }
|
||||
}
|
||||
pendingOperations++;
|
||||
xagentSignedFunc.func = func;
|
||||
xagentSignedFunc.objx = objx;
|
||||
xagentSignedFunc.archid = archid;
|
||||
xagentSignedFunc.signeedagentpath = signeedagentpath;
|
||||
originalAgent.sign(agentSignCertInfo, { out: signeedagentpath, desc: signDesc, url: signUrl, time: timeStampUrl }, xagentSignedFunc);
|
||||
} else {
|
||||
// Signed agent is already ok, use it.
|
||||
agentpath = signeedagentpath;
|
||||
}
|
||||
originalAgent.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (--pendingOperations === 0) { func(); }
|
||||
}
|
||||
|
||||
// Update the list of available mesh agents
|
||||
obj.updateMeshAgentsTable = function (domain, func) {
|
||||
// Check if a custom agent signing certificate is available
|
||||
var agentSignCertInfo = require('./authenticode.js').loadCertificates([obj.path.join(obj.datapath, 'agentsigningcert.pem')]);
|
||||
|
||||
// Setup the domain is specified
|
||||
var objx = domain, suffix = '';
|
||||
if (domain.id == '') { objx = obj; } else { suffix = '-' + domain.id; objx.meshAgentBinaries = {}; }
|
||||
|
||||
// Load agent information file. This includes the data & time of the agent.
|
||||
const agentInfo = [];
|
||||
try { agentInfo = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'hashagents.json'), 'utf8')); } catch (ex) { }
|
||||
|
||||
var archcount = 0;
|
||||
for (var archid in obj.meshAgentsArchitectureNumbers) {
|
||||
var agentpath;
|
||||
if (domain.id == '') {
|
||||
// Load all agents when processing the default domain
|
||||
agentpath = obj.path.join(__dirname, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||
const agentpath2 = obj.path.join(obj.datapath, 'signedagents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||
if (obj.fs.existsSync(agentpath2)) { agentpath = agentpath2; } // If the agent is present in "meshcentral-data/signedagents", use that one instead.
|
||||
const agentpath3 = obj.path.join(obj.datapath, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||
if (obj.fs.existsSync(agentpath3)) { agentpath = agentpath3; } // If the agent is present in "meshcentral-data/agents", use that one instead.
|
||||
} else {
|
||||
// When processing an extra domain, only load agents that are specific to that domain
|
||||
var agentpath = obj.path.join(obj.datapath, 'agents' + suffix, obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||
if (obj.fs.existsSync(agentpath)) { delete obj.meshAgentsArchitectureNumbers[archid].codesign; } else { continue; } // If the agent is not present in "meshcentral-data/agents" skip.
|
||||
}
|
||||
|
||||
// Fetch agent binary information
|
||||
var stats = null;
|
||||
try { stats = obj.fs.statSync(agentpath); } catch (ex) { }
|
||||
if ((stats == null)) continue; // If this agent does not exist, skip it.
|
||||
|
||||
// Setup agent information
|
||||
archcount++;
|
||||
|
@ -38,6 +38,7 @@
|
||||
"_agentCoreDump": true,
|
||||
"_agentCoreDumpUsers": "user1,user2",
|
||||
"_agentSignLock": true,
|
||||
"_agentTimeStampServer": "http://timestamp.digicert.com",
|
||||
"_ignoreAgentHashCheck": true,
|
||||
"_exactPorts": true,
|
||||
"_allowLoginToken": true,
|
||||
|
Loading…
Reference in New Issue
Block a user