1
0
mirror of https://github.com/Ylianst/MeshCommander synced 2025-12-06 06:03:20 +00:00

Fixed Kerberos, added redirection error messages.

This commit is contained in:
Ylian Saint-Hilaire
2020-06-29 14:47:09 -07:00
parent 921f46f32b
commit c982c10e30
5 changed files with 223 additions and 54 deletions

View File

@@ -114,6 +114,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (accview.getUint32(0) != 0) { return obj.Stop(); }
obj.send(String.fromCharCode(1)); // Send share desktop flag
obj.state = 3;
if (obj.parent) { obj.parent.disconnectCode = 50000; } // If Intel AMT disconnects at exactly this moment, indicates we need RLE8 or unsupported GPU.
}
else if ((obj.state == 3) && (obj.acc.byteLength >= 24)) {
// Getting server init
@@ -171,7 +172,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.bpp == 1) obj.send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(7) + ShortToStr(7) + ShortToStr(3) + String.fromCharCode(5, 2, 0, 0, 0, 0)); // Setup 8 bit color RGB332
obj.state = 4;
if (obj.parent) { obj.parent.xxStateChange(3); }
if (obj.parent) { obj.parent.disconnectCode = 0; obj.parent.xxStateChange(3); }
_SendRefresh();
//obj.timer = setInterval(obj.xxOnTimer, 50);

View File

@@ -28,6 +28,7 @@ var CreateAmtRedirect = function (module) {
obj.authuri = '/RedirectionService';
obj.digestRealmMatch = null;
obj.onStateChanged = null;
obj.disconnectCode = 0;
function ToIntStr(v) { return String.fromCharCode((v & 0xFF), ((v >> 8) & 0xFF), ((v >> 16) & 0xFF), ((v >> 24) & 0xFF)); }
function ToShortStr(v) { return String.fromCharCode((v & 0xFF), ((v >> 8) & 0xFF)); }
@@ -95,6 +96,13 @@ var CreateAmtRedirect = function (module) {
obj.xxOnSocketData = function (data) {
if (!data || obj.connectstate == -1) return;
// Redirection tracing
if (urlvars && urlvars['redirtrace']) {
var datastr = arrToStr(new Uint8Array(data));
console.log('REDIR-RECV(' + datastr.length + '): ' + rstr2hex(datastr));
}
//obj.inDataCount++;
data = new Uint8Array(data).buffer;
@@ -129,6 +137,7 @@ var CreateAmtRedirect = function (module) {
cmdsize = (13 + oemlen);
break;
default:
obj.disconnectCode = statuscode; // 2 = BUSY, 3 = UNSUPPORTED, 0xFF = ERROR.
obj.Stop(1);
break;
}
@@ -142,6 +151,32 @@ var CreateAmtRedirect = function (module) {
var authDataBuf = new Uint8Array(obj.acc.slice(9, 9 + authDataLen));
cmdsize = 9 + authDataLen;
if (authType == 0) {
// ###BEGIN###{Mode-NodeWebkit}
if (obj.user == '*') {
if (authData.indexOf(2) >= 0) {
// Kerberos Auth
var ticket;
if (kerberos && kerberos != null) {
var ticketReturn = kerberos.getTicket('HTTP' + ((obj.tls == 1)?'S':'') + '/' + ((obj.pass == '') ? (obj.host + ':' + obj.port) : obj.pass));
if (ticketReturn.returnCode == 0 || ticketReturn.returnCode == 0x90312) {
ticket = ticketReturn.ticket;
if (process.platform.indexOf('win') >= 0) {
// Clear kerberos tickets on both 32 and 64bit Windows platforms
try { require('child_process').exec('%windir%\\system32\\klist purge', function (error, stdout, stderr) { if (error) { require('child_process').exec('%windir%\\sysnative\\klist purge', function (error, stdout, stderr) { if (error) { console.error('Unable to purge kerberos tickets'); } }); } }); } catch (e) { console.log(e); }
}
} else {
console.error('Unexpected Kerberos error code: ' + ticketReturn.returnCode);
}
}
if (ticket) {
obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x02) + IntToStrX(ticket.length) + ticket);
} else {
obj.Stop(2);
}
}
else obj.Stop(2);
} else {
// ###END###{Mode-NodeWebkit}
// Query
if (authData.indexOf(4) >= 0) {
// Good Digest Auth (With cnonce and all)
@@ -156,6 +191,9 @@ var CreateAmtRedirect = function (module) {
obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x01) + IntToStrX(obj.user.length + obj.pass.length + 2) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(obj.pass.length) + obj.pass);
}
else obj.Stop(2);
// ###BEGIN###{Mode-NodeWebkit}
}
// ###END###{Mode-NodeWebkit}
} else if (((authType == 3) || (authType == 4)) && (status == 1)) {
var curptr = 0;
@@ -261,7 +299,15 @@ var CreateAmtRedirect = function (module) {
}
}
obj.directSend = function (arr) { try { obj.socket.write(new Buffer(arr)); } catch (ex) { console.log(ex); } }
obj.directSend = function (arr) {
// Redirection tracing
if (urlvars && urlvars['redirtrace']) {
var datastr = arrToStr(new Uint8Array(arr));
console.log('REDIR-DSEND(' + datastr.length + '): ' + rstr2hex(datastr));
}
try { obj.socket.write(new Buffer(arr)); } catch (ex) { console.log(ex); }
}
obj.xxSend = function (x) {
if (urlvars && urlvars['redirtrace']) { console.log('REDIR-SEND(' + x.length + '): ' + rstr2hex(x)); }

View File

@@ -206,12 +206,13 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions) {
}
// Get the certificate of Intel AMT
obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate(); } return null; }
obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate().fingerprint.split(':').join('').toLowerCase(); } return null; }
obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.xtlsCertificate; } return null; }
obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.xtlsCertificate.fingerprint.split(':').join('').toLowerCase(); } return null; }
// NODE.js specific private method
obj.xxOnSocketConnected = function () {
if (obj.socket == null) return;
obj.localAddress = obj.socket.localAddress; // Store the local address of this socket, useful for UEFI HTTPS boot
if (obj.xtls == 1) {
obj.xtlsCertificate = obj.socket.getPeerCertificate();

View File

@@ -7779,6 +7779,11 @@
// ###BEGIN###{Mode-MeshCentral2}
QV('termRecordIcon', false);
// ###END###{Mode-MeshCentral2}
if (terminal.disconnectCode == 2) { // BUSY
messagebox("Remote Terminal", "The remote device is busy, a session may already be open.");
} else if (terminal.disconnectCode == 3) { // UNSUPPORTED
messagebox("Remote Terminal", "The device indicated that this type of connection of not supported.");
}
break;
case 3:
// ###BEGIN###{Mode-MeshCentral2}
@@ -8180,6 +8185,13 @@
// ###BEGIN###{Mode-MeshCentral2}
QV('deskRecordIcon', false);
// ###END###{Mode-MeshCentral2}
if (desktop.disconnectCode == 2) { // BUSY
messagebox("Remote Desktop", "The remote device is busy, a session may already be open.");
} else if (desktop.disconnectCode == 3) { // UNSUPPORTED
messagebox("Remote Desktop", "The device indicated that this type of connection of not supported.");
} else if (desktop.disconnectCode == 50000) { // KVM-Disconnect
messagebox("Remote Desktop", "KVM disconnection, they may indicate that Intel AMT is unable to capture the display (Try RLE8 encoding), or unsupported GPU.");
}
break;
case 3:
// ###BEGIN###{DesktopInband}
@@ -8402,11 +8414,21 @@
// Toggle desktop session recording
function deskClipboard() {
if (xxdialogMode || (desktop == null) || (desktop.State != 3)) return;
setDialogMode(11, "Clipboard", 3, deskClipboardEx, "Enter text to send to Intel&reg; AMT clipboard." + '<br><textarea id=kvmClipText style=width:100%;height:120px;resize:none;margin-top:8px />');
var x = '';
x += "Enter text to send to Intel&reg; AMT clipboard." + '<br />';
x += '<select id=kvmClipEncoding style=width:100%;margin-top:8px><option value=0>' + "Text Encoding" + '<option value=1>' + "Hex Encoding" + '</select>';
x += '<textarea id=kvmClipText style=width:100%;height:120px;resize:none;margin-top:8px />';
setDialogMode(11, "Clipboard", 3, deskClipboardEx, x);
focusTextBox('kvmClipText');
}
function deskClipboardEx() { desktop.m.sendClipboardData(Q('kvmClipText').value.split('\\0').join('\0')); }
function deskClipboardEx() {
if (Q('kvmClipEncoding').value == 0) {
desktop.m.sendClipboardData(Q('kvmClipText').value.split('\\0').join('\0')); // Text encoded input
} else {
desktop.m.sendClipboardData(hex2rstr(Q('kvmClipText').value)); // Hex encoded input
}
}
// ###END###{DesktopClipboard}
// ###BEGIN###{FileSaver}
@@ -9878,7 +9900,7 @@
addOption('d5actionSelect', "Power on to PXE", 401);
// ###BEGIN###{PowerControl-Advanced}
// ###BEGIN###{PowerControl-OneClick}
if (amtPowerBootCapabilities['ForceUEFIHTTPSBoot'] == true) {
if (amtPowerBootCapabilities['ForceUEFIHTTPSBoot'] === true) {
addOption('d5actionSelect', "Reset to HTTPS Boot", 600);
addOption('d5actionSelect', "Power on to HTTPS Boot", 601);
}
@@ -9908,7 +9930,7 @@
setDialogMode(11, "HTTPS Boot", 3, function () {
var files = Q('ocrfile').files;
if (files.length != 1) return;
webserver.setupBootImage(files[0].path, wsstack.comm.socket.localAddress);
webserver.setupBootImage(files[0].path, wsstack.comm.localAddress);
powerActionDlg();
}, x);
QE('idx_dlgOkButton', false);
@@ -10257,6 +10279,7 @@
if (action == 300 || action == 301) { bootSource = 'Force Diagnostic Boot'; }
if (action == 400 || action == 401) { bootSource = 'Force PXE Boot'; }
// ###BEGIN###{PowerControl-Advanced}
if (action == 600 || action == 601) { bootSource = 'Force OCR UEFI HTTPS Boot'; }
}
// Resetting Force boot data in case it was changed so that it won't be used on the next power action

View File

@@ -12,8 +12,10 @@ var CreateWebServer = function () {
const path = require("path");
var obj = {};
var server = null;
obj.port = random(1, 65535); // Port used to listen for incoming requests.
obj.port = random(33000, 65500); // Port used to listen for incoming requests.
obj.state = 0; // State of the web server, 0 = Disabled, 2 = Listening.
obj.rootCert = null; // Root certificate in PEM format.
obj.rootKey = null; // Root certificate private key in PEM format.
obj.cert = null; // TLS certificate in PEM format.
obj.key = null; // TLS certificate private key in PEM format.
obj.certHashRaw = null; // SHA384 hash of TLS certificate.
@@ -32,7 +34,7 @@ var CreateWebServer = function () {
if (server != null) return;
obj.state = 1;
if ((obj.cert != null) && (obj.key != null)) { server = tls.createServer({ cert: obj.cert, key: obj.key, minVersion: 'TLSv1' }, onConnection); } else { server = net.createServer(onConnection); }
server.on('error', function (err) { if (err.code == 'EADDRINUSE') { obj.port = random(1, 65535); server = null; obj.start(func); } else { console.log('WebServer Listen Error', err.code); } });
server.on('error', function (err) { if (err.code == 'EADDRINUSE') { obj.port = random(33000, 65500); server = null; obj.start(func); } else { console.log('WebServer Listen Error', err.code); } });
server.listen({ port: obj.port }, function (x) { obj.state = 2; console.log('WebServer listening on ' + obj.port); if (func != null) { func(); } });
}
@@ -101,6 +103,42 @@ var CreateWebServer = function () {
// Generate a TLS certificate (this is really a root cert)
obj.generateCertificate = function () {
var attrs1 = [{ name: 'commonName', value: 'MeshCommanderRoot' }, { name: 'countryName', value: 'Unknown' }, { shortName: 'ST', value: 'Unknown' }, { name: 'organizationName', value: 'Unknown' }];
var attrs2 = [{ name: 'commonName', value: 'MeshCommander.com' }, { name: 'countryName', value: 'Unknown' }, { shortName: 'ST', value: 'Unknown' }, { name: 'organizationName', value: 'Unknown' }];
if (fs.existsSync('webroot.pem') && fs.existsSync('webroot.key')) {
console.log('Read root from file');
obj.rootCert = fs.readFileSync('webroot.pem').toString();
obj.rootKey = fs.readFileSync('webroot.key').toString();
var rootcert = forge.pki.certificateFromPem(obj.rootCert);
var rootkeys = { privateKey: forge.pki.privateKeyFromPem(obj.rootKey) };
} else {
console.log('Generate root');
// Generate a root keypair and create an X.509v3 root certificate
var rootkeys = forge.pki.rsa.generateKeyPair(1024);
var rootcert = forge.pki.createCertificate();
rootcert.publicKey = rootkeys.publicKey;
rootcert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1);
rootcert.validity.notBefore = new Date(2018, 0, 1);
rootcert.validity.notAfter = new Date(2049, 11, 31);
rootcert.setSubject(attrs1);
rootcert.setIssuer(attrs1);
rootcert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'nsCertType', sslCA: true, emailCA: true, objCA: true }, { name: 'subjectKeyIdentifier' }]); // Root extensions
rootcert.sign(rootkeys.privateKey, forge.md.sha256.create());
obj.rootCert = forge.pki.certificateToPem(rootcert);
obj.rootKey = forge.pki.privateKeyToPem(rootkeys.privateKey);
fs.writeFileSync('webroot.pem', obj.rootCert);
fs.writeFileSync('webroot.key', obj.rootKey);
}
if (fs.existsSync('webleaf.pem') && fs.existsSync('webleaf.key')) {
console.log('Read leaf from file');
obj.cert = fs.readFileSync('webleaf.pem').toString();
obj.key = fs.readFileSync('webleaf.key').toString();
var cert = forge.pki.certificateFromPem(obj.cert);
var keys = { privateKey: forge.pki.privateKeyFromPem(obj.key) };
} else {
console.log('Generate leaf');
// Generate a keypair and create an X.509v3 certificate
var keys = forge.pki.rsa.generateKeyPair(1024);
var cert = forge.pki.createCertificate();
@@ -108,22 +146,55 @@ var CreateWebServer = function () {
cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1);
cert.validity.notBefore = new Date(2018, 0, 1);
cert.validity.notAfter = new Date(2049, 11, 31);
var attrs = [ { name: 'commonName', value: 'MeshCommander' }, { name: 'countryName', value: 'Unknown' }, { shortName: 'ST', value: 'Unknown' }, { name: 'organizationName', value: 'Unknown' } ];
cert.setSubject(attrs);
cert.setIssuer(attrs);
cert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'nsCertType', sslCA: true, emailCA: true, objCA: true }, { name: 'subjectKeyIdentifier' }]); // Root extensions
cert.sign(keys.privateKey, forge.md.sha256.create());
cert.setSubject(attrs2);
cert.setIssuer(attrs1);
// Figure out the extended key usages
var extKeyUsage = { name: 'extKeyUsage', serverAuth: true }
// Create a leaf certificate
cert.setExtensions([{ name: 'basicConstraints' }, { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }, extKeyUsage, { name: 'nsCertType', server: true }, { name: 'subjectKeyIdentifier' }]);
// Self-sign certificate
cert.sign(rootkeys.privateKey, forge.md.sha256.create());
obj.cert = forge.pki.certificateToPem(cert);
obj.key = forge.pki.privateKeyToPem(keys.privateKey);
fs.writeFileSync('webleaf.pem', obj.cert);
fs.writeFileSync('webleaf.key', obj.key);
}
// Compute the SHA384 hash of the certificate
var md = forge.md.sha384.create();
// Compute the SHA256 hash of the certificate
var md = forge.md.sha256.create();
md.start(); md.update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes());
var digest = md.digest();
obj.certHashRaw = digest.data;
obj.certHashHex = digest.toHex();
console.log('SHA256', md.digest().toHex());
// Compute the SHA384 hash of the certificate
md = forge.md.sha384.create();
md.start(); md.update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes());
console.log('SHA384', md.digest().toHex());
// Compute the SHA512 hash of the certificate
md = forge.md.sha512.create();
md.start(); md.update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes());
console.log('SHA512', md.digest().toHex());
}
// MC 0.8.6
// 8680 0100 2c000000 68747470733a2f2f31302e3135312e3133372e3139383a343133352f34343131313435323237343935353831 // https://10.151.137.198:4135/4411145227495581
// 8680 1400 01000000 00 // OCR_HTTPS_CERT_SYNC_ROOT_CA
// 8680 1700 20000000 ac8adfe3809dc66990040fdaac53765e369c0242f2a789327b57c072d5dd2677
// 8680 1e00 02000000 3c00 // OCR_HTTPS_REQUEST_TIMEOUT (60)
// MC 0.8.3-alpha
// 8680 0100 2c000000 68747470733a2f2f31302e3135312e3133372e3139383a343133352f34343131313435323237343935353831 // https://10.151.137.198:4135/4411145227495581
// 8680 0300 02000000 2c00 // OCR_EFI_FILE_DEVICE_PATH (44)
// 8680 1700 20000000 ac8adfe3809dc66990040fdaac53765e369c0242f2a789327b57c072d5dd2677
// 8680 1400 01000000 00 // OCR_HTTPS_CERT_SYNC_ROOT_CA
// 8680 1e00 02000000 0000 // OCR_HTTPS_REQUEST_TIMEOUT
// Returns a UEFI boot parameter in binary
function makeUefiBootParam(type, data, len) {
if (typeof data == 'number') { if (len == 1) { data = String.fromCharCode(data & 0xFF); } if (len == 2) { data = ShortToStrX(data); } if (len == 4) { data = IntToStrX(data); } }
@@ -135,15 +206,42 @@ var CreateWebServer = function () {
if (fs.existsSync(filePath) == false) return null;
var name = ('' + Math.random()).substring(2);
obj.responses['/' + name] = { type: 'application/octet-stream', file: filePath };
console.log('https://' + ip + ':' + obj.port + '/' + name);
var url = 'http' + ((obj.cert != null) ? 's' : '') + '://' + ip + ':' + obj.port + '/' + name;
console.log(url);
/*
obj.lastBootImageArgs = {
args: btoa(
makeUefiBootParam(1, 'http' + ((obj.cert != null)?'s':'') + '://' + ip + ':' + obj.port + '/' + name) + // OCR_EFI_NETWORK_DEVICE_PATH
makeUefiBootParam(20, 0, 1) + // OCR_HTTPS_CERT_SYNC_ROOT_CA
makeUefiBootParam(23, obj.certHashRaw) + // OCR_HTTPS_SERVER_CERT_HASH_SHA384
makeUefiBootParam(30, 60, 2)), // OCR_HTTPS_REQUEST_TIMEOUT (60 seconds)
makeUefiBootParam(1, url) + // OCR_EFI_NETWORK_DEVICE_PATH (1)
makeUefiBootParam(3, url.length, 2) + // OCR_EFI_DEVICE_PATH_LEN (3)
makeUefiBootParam(20, 0, 1) + // OCR_HTTPS_CERT_SYNC_ROOT_CA (20) (0 = false)
makeUefiBootParam(21, "MeshCommander.com") + // OCR_HTTPS_CERT_SERVER_NAME (21)
makeUefiBootParam(22, 1, 2) + // OCR_HTTPS_SERVER_NAME_VERIFY_METHOD (22) (1 = FullName)
makeUefiBootParam(23, obj.certHashRaw) + // OCR_HTTPS_SERVER_CERT_HASH_SHA256 (23)
makeUefiBootParam(30, 0, 2)), // OCR_HTTPS_REQUEST_TIMEOUT (30) (0 seconds = default)
argscount: 7
};
obj.lastBootImageArgs = {
args: btoa(
makeUefiBootParam(1, url) + // OCR_EFI_NETWORK_DEVICE_PATH (1)
makeUefiBootParam(20, 0, 1) + // OCR_HTTPS_CERT_SYNC_ROOT_CA (20) (0 = false)
makeUefiBootParam(21, "MeshCommander.com") + // OCR_HTTPS_CERT_SERVER_NAME (21)
makeUefiBootParam(22, 1, 2) + // OCR_HTTPS_SERVER_NAME_VERIFY_METHOD (22) (1 = FullName)
makeUefiBootParam(23, obj.certHashRaw)), // OCR_HTTPS_SERVER_CERT_HASH_SHA256 (23)
argscount: 5
};
*/
obj.lastBootImageArgs = {
args: btoa(
makeUefiBootParam(1, url) + // OCR_EFI_NETWORK_DEVICE_PATH (1)
makeUefiBootParam(20, 1, 1) + // OCR_HTTPS_CERT_SYNC_ROOT_CA (20) (0 = false)
makeUefiBootParam(21, "MeshCommander.com") + // OCR_HTTPS_CERT_SERVER_NAME (21)
makeUefiBootParam(22, 1, 2)), // OCR_HTTPS_SERVER_NAME_VERIFY_METHOD (22) (1 = FullName)
argscount: 4
};
return obj.lastBootImageArgs;
}