Improved APF security using session cookies.
Ylian Saint-Hilaire committed
Oct 22, 2020 at 15:10 UTC
c35192396196420c0cdc11f2f3342ed314f9ace8
3 files changed
+37
-17
agents/meshcore.js
+4
-4
@@ -1075,15 +1075,15 @@ function createMeshCore(agent) {
1075
}
1076
case 'amtconfig': {
1077
// Perform Intel AMT activation and/or configuration
1078
- if ((apftunnel != null) || (amt == null)) break;
1078
+ if ((apftunnel != null) || (amt == null) || (typeof data.user != 'string') || (typeof data.pass != 'string')) break;
1079
getMeiState(15, function (state) {
1080
if ((apftunnel != null) || (amt == null)) return;
1081
if ((state == null) || (state.ProvisioningState == null)) return;
1082
if ((state.UUID == null) || (state.UUID.length != 36)) return; // Bad UUID
1083
var apfarg = {
1084
- mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
1085
- mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16), // TODO: User a server provided encrypted cookie for CIRA-LMS login
1086
- mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
1084
+ mpsurl: mesh.ServerUrl.replace('/agent.ashx', '/apf.ashx'),
1085
+ mpsuser: data.user, // Agent user name
1086
+ mpspass: data.pass, // Encrypted login cookie
1087
mpskeepalive: 60000,
1088
clientname: state.OsHostname,
1089
clientaddress: '127.0.0.1',
meshagent.js
+8
-5
@@ -897,11 +897,15 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
897
}
898
}
899
900
- // Indicate to the agent that we want to reconfigure Intel AMT
900
+ // Indicate to the agent that we want to check Intel AMT configuration
901
+ // This may trigger a CIRA-LMS tunnel from the agent so the server can inspect the device.
902
obj.sendUpdatedIntelAmtPolicy = function (policy) {
903
if (obj.agentExeInfo && (obj.agentExeInfo.amt == true)) { // Only send Intel AMT policy to agents what could have AMT.
904
if (policy == null) { var mesh = parent.meshes[obj.dbMeshKey]; if (mesh == null) return; policy = mesh.amt; }
904
- if ((policy != null) && (policy.type != 0)) { try { obj.send(JSON.stringify({ action: 'amtconfig' })); } catch (ex) { } }
905
+ if ((policy != null) && (policy.type != 0)) {
906
+ const cookie = parent.parent.encodeCookie({ a: 'apf', n: obj.dbNodeKey, m: obj.dbMeshKey }, parent.parent.loginCookieEncryptionKey);
907
+ try { obj.send(JSON.stringify({ action: 'amtconfig', user: '**MeshAgentApfTunnel**', pass: cookie })); } catch (ex) { }
908
+ }
909
}
910
}
911
@@ -954,9 +958,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
958
});
959
960
// Indicate that we want to check the Intel AMT configuration
957
- if (obj.agentExeInfo && (obj.agentExeInfo.amt == true) && (mesh.amt != null) && (mesh.amt.type != 0)) { // Only send yo agents what could have AMT and if the policy is not empty.
958
- try { obj.send(JSON.stringify({ action: 'amtconfig' })); } catch (ex) { }
959
- }
961
+ // This may trigger a CIRA-LMS tunnel to the server for further processing
962
+ obj.sendUpdatedIntelAmtPolicy();
963
964
// Fetch system information
965
db.GetHash('si' + obj.dbNodeKey, function (err, results) {
mpsserver.js
+25
-8
@@ -544,14 +544,31 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
544
//console.log('MPS:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
545
parent.debug('mpscmd', '--> USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
546
547
- // Check the CIRA password
548
- if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; parent.debug('mps', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
549
-
550
- // Check the CIRA username, which should be the start of the MeshID.
551
- if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('mps', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
552
- var meshIdStart = '/' + username, mesh = null;
553
- if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } }
554
- if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Device group not found', username, password); SendUserAuthFail(socket); return -1; }
547
+ // If the login uses a cookie, check this now
548
+ if ((username == '**MeshAgentApfTunnel**') && (password != null)) {
549
+ const cookie = parent.decodeCookie(password, parent.loginCookieEncryptionKey);
550
+ if ((cookie == null) || (cookie.a !== 'apf')) { incorrectPasswordCount++; parent.debug('mps', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
551
+ if (obj.parent.webserver.meshes[cookie.m] == null) { meshNotFoundCount++; parent.debug('mps', 'Device group not found', username, password); SendUserAuthFail(socket); return -1; }
552
+
553
+ // Setup the connection
554
+ socket.tag.nodeid = cookie.n;
555
+ socket.tag.meshid = cookie.m;
556
+ socket.tag.connectTime = Date.now();
557
+
558
+ // Add the connection to the MPS connection list
559
+ addCiraConnection(socket);
560
+ SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
561
+ return 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen;
562
+ } else {
563
+ // Check the CIRA password
564
+ if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; parent.debug('mps', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
565
+
566
+ // Check the CIRA username, which should be the start of the MeshID.
567
+ if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('mps', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
568
+ var meshIdStart = '/' + username, mesh = null;
569
+ if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } }
570
+ if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Device group not found', username, password); SendUserAuthFail(socket); return -1; }
571
+ }
572
573
// If this is a agent-less mesh, use the device guid 3 times as ID.
574
if (mesh.mtype == 1) {