screen: fix VeNCrypt security negotiation for weston VNC backend
weston's VNC backend (neatvnc) uses VeNCrypt (security type 19) as the outer type even with --disable-transport-layer-security, offering sub-type 1 (None, no TLS, no password) within it. The old screen.html only handled type 1 (plain None) and type 2 (VNC auth), causing 'auth failed' against weston. Add VeNCrypt states to the RFB state machine: - vencrypt-version: echo back server's major.minor - vencrypt-subtypes: pick sub-type 1 (None) if available - vencrypt-accept: check server's acceptance byte Then falls through to the normal security-result / server-init path.
This commit is contained in:
parent
270ef19920
commit
de13e80082
1 changed files with 52 additions and 5 deletions
|
|
@ -167,21 +167,68 @@ canvas { display: block; cursor: default; }
|
||||||
if (n === 0) { state = 'error'; return false; }
|
if (n === 0) { state = 'error'; return false; }
|
||||||
const types = drainTo(n);
|
const types = drainTo(n);
|
||||||
if (!types) { chunks.unshift(b); totalBytes += 1; return false; }
|
if (!types) { chunks.unshift(b); totalBytes += 1; return false; }
|
||||||
// Prefer type 1 (None), else use first offered
|
// Prefer type 1 (None), then type 19 (VeNCrypt — used by neatvnc/weston
|
||||||
const prefer = types.indexOf(1) !== -1 ? 1 : types[0];
|
// even with --disable-transport-layer-security), else first offered.
|
||||||
|
let prefer;
|
||||||
|
if (types.indexOf(1) !== -1) prefer = 1; // plain None
|
||||||
|
else if (types.indexOf(19) !== -1) prefer = 19; // VeNCrypt
|
||||||
|
else prefer = types[0];
|
||||||
send(new Uint8Array([prefer]));
|
send(new Uint8Array([prefer]));
|
||||||
state = prefer === 1 ? 'security-result' : 'security-vnc-challenge';
|
if (prefer === 1) state = 'security-result';
|
||||||
|
else if (prefer === 19) state = 'vencrypt-version';
|
||||||
|
else state = 'security-vnc-challenge';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 'security-vnc-challenge': {
|
case 'security-vnc-challenge': {
|
||||||
// VNC auth: skip challenge bytes, respond with zeros (will fail,
|
// VNC auth (type 2): we don't have the password, so send zeros.
|
||||||
// but we're in plain-RFB mode for hyperhive — see weston-vnc.nix)
|
// This will fail for password-protected servers; fine for our
|
||||||
|
// weston VNC which uses None via VeNCrypt.
|
||||||
const b = drainTo(16);
|
const b = drainTo(16);
|
||||||
if (!b) return false;
|
if (!b) return false;
|
||||||
send(new Uint8Array(16));
|
send(new Uint8Array(16));
|
||||||
state = 'security-result';
|
state = 'security-result';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// ── VeNCrypt (type 19) sub-handshake ───────────────────────────────
|
||||||
|
// neatvnc (weston VNC backend) uses VeNCrypt as the outer type even
|
||||||
|
// with --disable-transport-layer-security, offering sub-type 1 (None).
|
||||||
|
case 'vencrypt-version': {
|
||||||
|
// Server sends: major (u8), minor (u8) — e.g. 0, 2
|
||||||
|
const b = drainTo(2);
|
||||||
|
if (!b) return false;
|
||||||
|
// Echo same version back
|
||||||
|
send(new Uint8Array([b[0], b[1]]));
|
||||||
|
state = 'vencrypt-subtypes';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 'vencrypt-subtypes': {
|
||||||
|
// Server sends: nSubtypes (u8), then nSubtypes × u32 sub-type ids
|
||||||
|
const nb = drainTo(1);
|
||||||
|
if (!nb) return false;
|
||||||
|
const nSub = nb[0];
|
||||||
|
const raw = drainTo(nSub * 4);
|
||||||
|
if (!raw) { chunks.unshift(nb); totalBytes += 1; return false; }
|
||||||
|
// Build sub-type array from big-endian u32s
|
||||||
|
const subs = [];
|
||||||
|
for (let i = 0; i < nSub; i++) subs.push(u32be(raw, i * 4));
|
||||||
|
// Prefer sub-type 1 (VeNCrypt None) — no TLS, no password.
|
||||||
|
// Fall back to first offered.
|
||||||
|
const sub = subs.includes(1) ? 1 : subs[0];
|
||||||
|
// Send chosen sub-type as big-endian u32
|
||||||
|
send(new Uint8Array([sub>>>24, (sub>>>16)&0xff, (sub>>>8)&0xff, sub&0xff]));
|
||||||
|
state = 'vencrypt-accept';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 'vencrypt-accept': {
|
||||||
|
// Server sends 1 byte: 1=accepted, 0=refused
|
||||||
|
const b = drainTo(1);
|
||||||
|
if (!b) return false;
|
||||||
|
if (b[0] !== 1) { setStatus('VeNCrypt sub-type refused', 'error'); return false; }
|
||||||
|
// Sub-type 1 (None): proceed to SecurityResult
|
||||||
|
state = 'security-result';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// ──────────────────────────────────────────────────────────────────
|
||||||
case 'security-result': {
|
case 'security-result': {
|
||||||
const b = drainTo(4);
|
const b = drainTo(4);
|
||||||
if (!b) return false;
|
if (!b) return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue