VeNCrypt should handle classical types

VeNCrypt is a superset of the original security types, so it should be
fine to send any of the classical values here as well.
This commit is contained in:
Pierre Ossman 2022-08-18 16:15:43 +02:00
parent 795494ade1
commit df8d005de9
2 changed files with 109 additions and 36 deletions

View File

@ -1524,48 +1524,66 @@ export default class RFB extends EventTargetMixin {
subtypes.push(this._sock.rQshift32());
}
if (subtypes.indexOf(securityTypePlain) != -1) {
// 0x100 = 256
this._sock.send([0, 0, 1, 0]);
this._rfbVeNCryptState = 4;
} else {
return this._fail("VeNCrypt Plain subtype not offered by server");
}
}
// Look for a matching security type in the order that the
// server prefers
this._rfbAuthScheme = -1;
for (let type of subtypes) {
// Avoid getting in to a loop
if (type === securityTypeVeNCrypt) {
continue;
}
// negotiated Plain subtype, server waits for password
if (this._rfbVeNCryptState == 4) {
if (this._rfbCredentials.username === undefined ||
this._rfbCredentials.password === undefined) {
this.dispatchEvent(new CustomEvent(
"credentialsrequired",
{ detail: { types: ["username", "password"] } }));
return false;
if (this._isSupportedSecurityType(type)) {
this._rfbAuthScheme = type;
break;
}
}
const user = encodeUTF8(this._rfbCredentials.username);
const pass = encodeUTF8(this._rfbCredentials.password);
if (this._rfbAuthScheme === -1) {
return this._fail("Unsupported security types (types: " + subtypes + ")");
}
this._sock.send([
(user.length >> 24) & 0xFF,
(user.length >> 16) & 0xFF,
(user.length >> 8) & 0xFF,
user.length & 0xFF
]);
this._sock.send([
(pass.length >> 24) & 0xFF,
(pass.length >> 16) & 0xFF,
(pass.length >> 8) & 0xFF,
pass.length & 0xFF
]);
this._sock.sendString(user);
this._sock.sendString(pass);
this._sock.send([this._rfbAuthScheme >> 24,
this._rfbAuthScheme >> 16,
this._rfbAuthScheme >> 8,
this._rfbAuthScheme]);
this._rfbInitState = "SecurityResult";
this._rfbVeNCryptState == 4;
return true;
}
}
_negotiatePlainAuth() {
if (this._rfbCredentials.username === undefined ||
this._rfbCredentials.password === undefined) {
this.dispatchEvent(new CustomEvent(
"credentialsrequired",
{ detail: { types: ["username", "password"] } }));
return false;
}
const user = encodeUTF8(this._rfbCredentials.username);
const pass = encodeUTF8(this._rfbCredentials.password);
this._sock.send([
(user.length >> 24) & 0xFF,
(user.length >> 16) & 0xFF,
(user.length >> 8) & 0xFF,
user.length & 0xFF
]);
this._sock.send([
(pass.length >> 24) & 0xFF,
(pass.length >> 16) & 0xFF,
(pass.length >> 8) & 0xFF,
pass.length & 0xFF
]);
this._sock.sendString(user);
this._sock.sendString(pass);
this._rfbInitState = "SecurityResult";
return true;
}
_negotiateStdVNCAuth() {
if (this._sock.rQwait("auth challenge", 16)) { return false; }
@ -1877,6 +1895,9 @@ export default class RFB extends EventTargetMixin {
case securityTypeVeNCrypt:
return this._negotiateVeNCryptAuth();
case securityTypePlain:
return this._negotiatePlainAuth();
case securityTypeUnixLogon:
return this._negotiateTightUnixAuth();

View File

@ -1463,18 +1463,70 @@ describe('Remote Frame Buffer Protocol Client', function () {
expect(client._fail).to.have.been.calledOnce;
});
it('should fail if the Plain authentication is not present', function () {
it('should fail if there are no supported subtypes', function () {
// VeNCrypt version
client._sock._websocket._receiveData(new Uint8Array([0, 2]));
expect(client._sock).to.have.sent(new Uint8Array([0, 2]));
// Server ACK.
client._sock._websocket._receiveData(new Uint8Array([0]));
// Subtype list, only list subtype 1.
// Subtype list
sinon.spy(client, "_fail");
client._sock._websocket._receiveData(new Uint8Array([1, 0, 0, 0, 1]));
client._sock._websocket._receiveData(new Uint8Array([2, 0, 0, 0, 9, 0, 0, 1, 4]));
expect(client._fail).to.have.been.calledOnce;
});
it('should support standard types', function () {
// VeNCrypt version
client._sock._websocket._receiveData(new Uint8Array([0, 2]));
expect(client._sock).to.have.sent(new Uint8Array([0, 2]));
// Server ACK.
client._sock._websocket._receiveData(new Uint8Array([0]));
// Subtype list
client._sock._websocket._receiveData(new Uint8Array([2, 0, 0, 0, 2, 0, 0, 1, 4]));
let expectedResponse = [];
push32(expectedResponse, 2); // Chosen subtype.
expect(client._sock).to.have.sent(new Uint8Array(expectedResponse));
});
it('should respect server preference order', function () {
// VeNCrypt version
client._sock._websocket._receiveData(new Uint8Array([0, 2]));
expect(client._sock).to.have.sent(new Uint8Array([0, 2]));
// Server ACK.
client._sock._websocket._receiveData(new Uint8Array([0]));
// Subtype list
let subtypes = [ 6 ];
push32(subtypes, 79);
push32(subtypes, 30);
push32(subtypes, 188);
push32(subtypes, 256);
push32(subtypes, 6);
push32(subtypes, 1);
client._sock._websocket._receiveData(new Uint8Array(subtypes));
let expectedResponse = [];
push32(expectedResponse, 30); // Chosen subtype.
expect(client._sock).to.have.sent(new Uint8Array(expectedResponse));
});
it('should ignore redundant VeNCrypt subtype', function () {
// VeNCrypt version
client._sock._websocket._receiveData(new Uint8Array([0, 2]));
expect(client._sock).to.have.sent(new Uint8Array([0, 2]));
// Server ACK.
client._sock._websocket._receiveData(new Uint8Array([0]));
// Subtype list
client._sock._websocket._receiveData(new Uint8Array([2, 0, 0, 0, 19, 0, 0, 0, 2]));
let expectedResponse = [];
push32(expectedResponse, 2); // Chosen subtype.
expect(client._sock).to.have.sent(new Uint8Array(expectedResponse));
});
it('should support Plain authentication', function () {
client._rfbCredentials = { username: 'username', password: 'password' };
// VeNCrypt version