Add verified WSS transport for legacy boards

Configure the default WSS endpoint and ISRG Root X2 trust anchor, preserve device authentication, enforce TLS and WebSocket handshake validation, and handle partial I/O and connection cleanup. Add host tests, server probes, package verification and integration documentation. Backend 443 /ws still returns HTTP 404; on-device validation remains pending.
This commit is contained in:
chenjintao
2026-09-16 11:23:33 +08:00
parent 4b565958f9
commit 3e463f57b6
23 changed files with 809 additions and 396 deletions
+59
View File
@@ -0,0 +1,59 @@
param([string]$OutputDir = "$PSScriptRoot/../artifacts/wss", [ValidateSet(443, 8080)][int]$ServerPort = 443)
$ErrorActionPreference = 'Stop'
$serverHost = 'banban.api.talkingq.com'
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
$OutputDir = (Resolve-Path -LiteralPath $OutputDir).Path
$tcp = New-Object System.Net.Sockets.TcpClient
$tls = $null
try {
$pending = $tcp.BeginConnect($serverHost, $serverPort, $null, $null)
if (-not $pending.AsyncWaitHandle.WaitOne(15000)) { throw 'TCP connect timeout' }
$tcp.EndConnect($pending)
$tcp.ReceiveTimeout = 15000
$tcp.SendTimeout = 15000
# Default SslStream validation checks the trusted chain and server hostname.
$tls = New-Object System.Net.Security.SslStream($tcp.GetStream(), $false)
$tls.ReadTimeout = 15000
$tls.WriteTimeout = 15000
$tls.AuthenticateAsClient($serverHost, $null, [System.Security.Authentication.SslProtocols]::Tls12, $false)
$leaf = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($tls.RemoteCertificate)
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.ChainPolicy.RevocationMode = [System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck
if (-not $chain.Build($leaf)) { throw 'Trusted certificate chain could not be built' }
$certificates = @()
for ($i = 0; $i -lt $chain.ChainElements.Count; $i++) {
$cert = $chain.ChainElements[$i].Certificate
$pem = "-----BEGIN CERTIFICATE-----`n" + [Convert]::ToBase64String($cert.RawData, [Base64FormattingOptions]::InsertLineBreaks).Replace("`r`n", "`n") + "`n-----END CERTIFICATE-----`n"
[IO.File]::WriteAllText((Join-Path $OutputDir "chain-$i.pem"), $pem, [Text.Encoding]::ASCII)
$certificates += [ordered]@{subject=$cert.Subject; issuer=$cert.Issuer; not_before=$cert.NotBefore.ToUniversalTime().ToString('o'); not_after=$cert.NotAfter.ToUniversalTime().ToString('o'); thumbprint=$cert.Thumbprint}
if ($i -eq $chain.ChainElements.Count - 1) {
if ($cert.Subject -ne $cert.Issuer) { throw 'Chain did not terminate at a root CA' }
[IO.File]::WriteAllText((Join-Path $OutputDir 'root-ca.pem'), $pem, [Text.Encoding]::ASCII)
}
}
$nonce = New-Object byte[] 16
$rng = [Security.Cryptography.RandomNumberGenerator]::Create()
$rng.GetBytes($nonce)
$rng.Dispose()
$key = [Convert]::ToBase64String($nonce)
$request = "GET /ws HTTP/1.1`r`nHost: ${serverHost}:${serverPort}`r`nUpgrade: websocket`r`nConnection: Upgrade`r`nSec-WebSocket-Key: $key`r`nSec-WebSocket-Version: 13`r`n`r`n"
$bytes = [Text.Encoding]::ASCII.GetBytes($request)
$tls.Write($bytes, 0, $bytes.Length)
$response = ''
while (-not $response.EndsWith("`r`n`r`n") -and $response.Length -lt 16384) {
$next = $tls.ReadByte()
if ($next -lt 0) { break }
$response += [char]$next
}
$sha1 = [Security.Cryptography.SHA1]::Create()
$expected = [Convert]::ToBase64String($sha1.ComputeHash([Text.Encoding]::ASCII.GetBytes($key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')))
$sha1.Dispose()
$accepted = $response -match '^HTTP/1\.1 101 ' -and $response -match ('(?im)^Sec-WebSocket-Accept:\s*' + [regex]::Escape($expected) + '\s*$')
$report = [ordered]@{url="wss://${serverHost}:${serverPort}/ws"; tested_utc=[DateTime]::UtcNow.ToString('o'); tls_protocol=$tls.SslProtocol.ToString(); cipher=$tls.CipherAlgorithm.ToString(); cipher_bits=$tls.CipherStrength; certificate_validation='System trust and hostname validation passed'; certificates=$certificates; websocket_upgrade=$accepted; response_headers=$response; device_auth_sent=$false}
$report | ConvertTo-Json -Depth 6 | Set-Content -Encoding UTF8 -LiteralPath (Join-Path $OutputDir 'server-probe.json')
$report | ConvertTo-Json -Depth 6
if (-not $accepted) { throw 'WebSocket upgrade did not return a valid HTTP 101 response' }
} finally {
if ($tls) { $tls.Dispose() }
$tcp.Close()
}