Files
banban/tools/probe_talkingq_wss.ps1
T
chenjintao 3e463f57b6 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.
2026-09-16 11:23:33 +08:00

60 lines
3.9 KiB
PowerShell

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()
}