More Intel AMT ACM activation work.

This commit is contained in:
Ylian Saint-Hilaire 2019-06-20 14:27:57 -07:00
parent 1d96f89f9d
commit e45a919c6e
4 changed files with 45 additions and 13 deletions

View File

@ -484,7 +484,7 @@ function AmtManager(agent, db, isdebug) {
// Fetch Intel AMT realm and activation nonce and get ready to ACM activation... // Fetch Intel AMT realm and activation nonce and get ready to ACM activation...
if (osamtstack != null) { if (osamtstack != null) {
//debug('Trying to get Intel AMT activation information (1)...'); //debug('Trying to get Intel AMT activation information (1)...');
osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activeToACM2, { fqdn: trustedFqdn, hash: hashMatch }); osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activeToACM2, { fqdn: trustedFqdn, hash: hashMatch, uuid: mestate.UUID });
} else { } else {
//debug('ACM Activation: Trying to get local account info...'); //debug('ACM Activation: Trying to get local account info...');
amtMei.getLocalSystemAccount(function (x) { amtMei.getLocalSystemAccount(function (x) {
@ -496,7 +496,7 @@ function AmtManager(agent, db, isdebug) {
oswsstack = new wsman(transport, '127.0.0.1', 16992, x.user, x.pass, false); oswsstack = new wsman(transport, '127.0.0.1', 16992, x.user, x.pass, false);
osamtstack = new amt(oswsstack); osamtstack = new amt(oswsstack);
//debug('Trying to get Intel AMT activation information (2)...'); //debug('Trying to get Intel AMT activation information (2)...');
osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activeToACM2, { fqdn: trustedFqdn, hash: hashMatch }); osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activeToACM2, { fqdn: trustedFqdn, hash: hashMatch, uuid: mestate.UUID });
} else { } else {
//debug('Unable to get $$OsAdmin password.'); //debug('Unable to get $$OsAdmin password.');
} }
@ -509,7 +509,7 @@ function AmtManager(agent, db, isdebug) {
if (status != 200) return; if (status != 200) return;
var fwNonce = responses['IPS_HostBasedSetupService'].response['ConfigurationNonce']; var fwNonce = responses['IPS_HostBasedSetupService'].response['ConfigurationNonce'];
var digestRealm = responses['AMT_GeneralSettings'].response['DigestRealm']; var digestRealm = responses['AMT_GeneralSettings'].response['DigestRealm'];
agent.SendCommand({ "action": "acmactivate", "nonce": fwNonce, "realm": digestRealm, "fqdn": tag.fqdn, "hash": tag.hash }); agent.SendCommand({ "action": "acmactivate", "nonce": fwNonce, "realm": digestRealm, "fqdn": tag.fqdn, "hash": tag.hash, "uuid": tag.uuid });
} }
// Called when the server responds with a ACM activation signature. // Called when the server responds with a ACM activation signature.

View File

@ -29,12 +29,13 @@ module.exports.CertificateOperations = function (parent) {
const TopLevelDomainExtendedSupport = { 'net': 2, 'com': 2, 'arpa': 3, 'org': 2, 'gov': 2, 'edu': 2, 'de': 2, 'fr': 3, 'cn': 3, 'nl': 3, 'br': 3, 'mx': 3, 'uk': 3, 'pl': 3, 'tw': 3, 'ca': 3, 'fi': 3, 'be': 3, 'ru': 3, 'se': 3, 'ch': 2, 'dk': 2, 'ar': 3, 'es': 3, 'no': 3, 'at': 3, 'in': 3, 'tr': 3, 'cz': 2, 'ro': 3, 'hu': 3, 'nz': 3, 'pt': 3, 'il': 3, 'gr': 3, 'co': 3, 'ie': 3, 'za': 3, 'th': 3, 'sg': 3, 'hk': 3, 'cl': 2, 'lt': 3, 'id': 3, 'hr': 3, 'ee': 3, 'bg': 3, 'ua': 2 }; const TopLevelDomainExtendedSupport = { 'net': 2, 'com': 2, 'arpa': 3, 'org': 2, 'gov': 2, 'edu': 2, 'de': 2, 'fr': 3, 'cn': 3, 'nl': 3, 'br': 3, 'mx': 3, 'uk': 3, 'pl': 3, 'tw': 3, 'ca': 3, 'fi': 3, 'be': 3, 'ru': 3, 'se': 3, 'ch': 2, 'dk': 2, 'ar': 3, 'es': 3, 'no': 3, 'at': 3, 'in': 3, 'tr': 3, 'cz': 2, 'ro': 3, 'hu': 3, 'nz': 3, 'pt': 3, 'il': 3, 'gr': 3, 'co': 3, 'ie': 3, 'za': 3, 'th': 3, 'sg': 3, 'hk': 3, 'cl': 2, 'lt': 3, 'id': 3, 'hr': 3, 'ee': 3, 'bg': 3, 'ua': 2 };
// Sign a Intel AMT ACM activation request // Sign a Intel AMT ACM activation request
obj.signAcmRequest = function (domain, request, user, pass) { obj.signAcmRequest = function (domain, request, user, pass, ipport, nodeid, meshid, computerName, agentId) {
if ((domain == null) || (domain.amtacmactivation == null) || (domain.amtacmactivation.certs == null) || (request == null) || (request.nonce == null) || (request.realm == null) || (request.fqdn == null) || (request.hash == null)) return null; if ((domain == null) || (domain.amtacmactivation == null) || (domain.amtacmactivation.certs == null) || (request == null) || (request.nonce == null) || (request.realm == null) || (request.fqdn == null) || (request.hash == null)) return null;
if (parent.common.validateString(request.nonce, 16, 256) == false) return null; if (parent.common.validateString(request.nonce, 16, 256) == false) return null;
if (parent.common.validateString(request.realm, 16, 256) == false) return null; if (parent.common.validateString(request.realm, 16, 256) == false) return null;
if (parent.common.validateString(request.fqdn, 4, 256) == false) return null; if (parent.common.validateString(request.fqdn, 4, 256) == false) return null;
if (parent.common.validateString(request.hash, 16, 256) == false) return null; if (parent.common.validateString(request.hash, 16, 256) == false) return null;
if (parent.common.validateString(request.uuid, 36, 36) == false) return null;
// Look for the signing certificate // Look for the signing certificate
var signkey = null, certChain = null, hashAlgo = null, certIndex = null; var signkey = null, certChain = null, hashAlgo = null, certIndex = null;
@ -60,10 +61,22 @@ module.exports.CertificateOperations = function (parent) {
signature = signer.sign(signkey, 'base64'); signature = signer.sign(signkey, 'base64');
} catch (ex) { return null; } } catch (ex) { return null; }
// Log the activation request, logging is a required step for activation.
if (obj.logAmtActivation(domain, { time: new Date(), domain: domain.id, amtUuid: request.uuid, certHash: request.hash, hashType: hashAlgo, amtRealm: request.realm, amtFqdn: request.fqdn, user: user, password: pass, ipport: ipport, nodeid: nodeid, meshid: meshid, computerName: computerName, agentId: agentId }) == false) return null;
// Return the signature with the computed account password hash // Return the signature with the computed account password hash
return { 'action': 'acmactivate', 'signature': signature, 'password': obj.crypto.createHash('md5').update(user + ':' + request.realm + ':' + pass).digest('hex'), 'nonce': mcNonce.toString('base64'), 'certs': certChain }; return { 'action': 'acmactivate', 'signature': signature, 'password': obj.crypto.createHash('md5').update(user + ':' + request.realm + ':' + pass).digest('hex'), 'nonce': mcNonce.toString('base64'), 'certs': certChain };
} }
// Log the Intel AMT activation operation
obj.logAmtActivation = function (domain, x) {
if ((domain.amtacmactivation == null) || (domain.amtacmactivation.log == null) || (typeof domain.amtacmactivation.log != 'string') || (x == null)) return true;
var logpath = null;
if ((domain.amtacmactivation.log.length >= 2) && ((domain.amtacmactivation.log[0] == '/') || (domain.amtacmactivation.log[1] == ':'))) { logpath = domain.amtacmactivation.log; } else { logpath = parent.path.join(obj.parent.datapath, domain.amtacmactivation.log); }
try { obj.fs.appendFileSync(logpath, JSON.stringify(x) + '\r\n'); } catch (ex) { console.log(ex); return false; }
return true;
}
// Load Intel AMT ACM activation certificates // Load Intel AMT ACM activation certificates
obj.loadIntelAmtAcmCerts = function (amtacmactivation) { obj.loadIntelAmtAcmCerts = function (amtacmactivation) {
if (amtacmactivation == null) return; if (amtacmactivation == null) return;

View File

@ -1210,10 +1210,30 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
} }
case 'acmactivate': case 'acmactivate':
{ {
if (obj.agentInfo.capabilities & 0x20) return; // If this is a temporary device, don't do ACM activation.
// Get the current Intel AMT policy
var mesh = parent.meshes[obj.dbMeshKey];
if ((mesh == null) || (mesh.amt == null) || (mesh.amt.type != 3) || (domain.amtacmactivation == null) || (domain.amtacmactivation.acmmatch == null) || (mesh.amt.password == null)) break; // If this is not the right policy, ignore this.
// Get the Intel AMT admin password, randomize if needed.
var amtpassword = ((mesh.amt.password == '') ? getRandomAmtPassword() : mesh.amt.password);
if (checkAmtPassword(amtpassword) == false) return; // Invalid Intel AMT password, this should never happen.
// Agent is asking the server to sign an Intel AMT ACM activation request // Agent is asking the server to sign an Intel AMT ACM activation request
//console.log(command); var signResponse = parent.parent.certificateOperations.signAcmRequest(domain, command, 'admin', amtpassword, obj.remoteaddrport, obj.dbNodeKey, obj.dbMeshKey, obj.agentInfo.computerName, obj.agentInfo.agentId); // TODO: Place account credentials!!!
var signResponse = parent.parent.certificateOperations.signAcmRequest(domain, command, 'admin', 'P@ssw0rd'); // TODO: Place account credentials!!! if (signResponse != null) {
if (signResponse != null) { obj.send(JSON.stringify(signResponse)); } // Log this activation event
var event = { etype: 'node', action: 'amtactivate', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Device requested Intel AMT ACM activation, FQDN: ' + command.fqdn, ip: obj.remoteaddrport };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, event);
// Update the device Intel AMT information
ChangeAgentCoreInfo({ "intelamt": { user: 'admin', pass: amtpassword, uuid: command.uuid, realm: command.realm } });
// Send the activation response
//obj.send(JSON.stringify(signResponse));
}
break; break;
} }
case 'diagnostic': case 'diagnostic':
@ -1307,6 +1327,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (device.intelamt.flags) { changes.push('AMT flags (' + device.intelamt.flags + ' --> ' + command.intelamt.flags + ')'); } else { changes.push('AMT flags (' + command.intelamt.flags + ')'); } if (device.intelamt.flags) { changes.push('AMT flags (' + device.intelamt.flags + ' --> ' + command.intelamt.flags + ')'); } else { changes.push('AMT flags (' + command.intelamt.flags + ')'); }
device.intelamt.flags = command.intelamt.flags; change = 1; log = 1; device.intelamt.flags = command.intelamt.flags; change = 1; log = 1;
} }
if ((command.intelamt.realm != null) && (device.intelamt.realm != command.intelamt.realm)) { changes.push('AMT realm'); device.intelamt.realm = command.intelamt.realm; change = 1; log = 1; }
if ((command.intelamt.host != null) && (device.intelamt.host != command.intelamt.host)) { changes.push('AMT host'); device.intelamt.host = command.intelamt.host; change = 1; log = 1; } if ((command.intelamt.host != null) && (device.intelamt.host != command.intelamt.host)) { changes.push('AMT host'); device.intelamt.host = command.intelamt.host; change = 1; log = 1; }
if ((command.intelamt.uuid != null) && (device.intelamt.uuid != command.intelamt.uuid)) { changes.push('AMT uuid'); device.intelamt.uuid = command.intelamt.uuid; change = 1; log = 1; } if ((command.intelamt.uuid != null) && (device.intelamt.uuid != command.intelamt.uuid)) { changes.push('AMT uuid'); device.intelamt.uuid = command.intelamt.uuid; change = 1; log = 1; }
if ((command.intelamt.user != null) && (device.intelamt.user != command.intelamt.user)) { changes.push('AMT user'); device.intelamt.user = command.intelamt.user; change = 1; log = 1; } if ((command.intelamt.user != null) && (device.intelamt.user != command.intelamt.user)) { changes.push('AMT user'); device.intelamt.user = command.intelamt.user; change = 1; log = 1; }
@ -1420,5 +1441,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
}); });
} }
// Generate a random Intel AMT password
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
function getRandomAmtPassword() { var p; do { p = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
return obj; return obj;
}; };

View File

@ -734,12 +734,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
r = parent.db.getBackupConfig(); r = parent.db.getBackupConfig();
break; break;
} }
case 'acm': {
var acmrequest = { action: 'acmactivate', nonce: 'H9e099o2wIhnRkjd5vXJWBceqIY=', realm: 'Digest:4DCA0000000000000000000000000000', fqdn: 'vprodemo.com', hash: 'c3846bf24b9e93ca64274c0ec67c1ecc5e024ffcacd2d74019350e81fe546ae4' };
var response = parent.parent.certificateOperations.signAcmRequest(domain, acmrequest, 'admin', 'P@ssw0rd');
r = 'ACM Response: ' + JSON.stringify(response);
break;
}
default: { // This is an unknown command, return an error message default: { // This is an unknown command, return an error message
r = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.'; r = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
break; break;