Files
terminalX/packages/TXCore/Tests/TXCoreTests/SSHWireTests.swift
kid 1a257fae7f feat: M4a host key 校验(TOFU pin,关闭 MITM 敞口)
- TXCore/SSH: SSHWire(string/mpint 编码)、ECDSAConv(DER→SSH 签名/P256 blob)、
  HostKey(opensshFingerprint/evaluate/HostTriple/KnownHostsStore),+10 单测(含真实指纹向量、高位 DER)
- TXTransport: SSHConfig.hostKeyVerifier 闭包 + SSHError.hostKeyMismatch;
  SSHSession 握手后 libssh2_session_hostkey 取 blob 交 verifier,拒绝则断开抛错
- app: 文件后端 KnownHostsStore(未签名 app 无 keychain 权限 SecItem -34018,host key 是
  公钥非机密,沙盒文件对 TOFU 足够)+ TOFU verifier + firstUse 横幅 + mismatch alert(信任/取消)
- 验证(192.168.9.199):首次信任 pin+接受连上;假 pin→不符→断开+告警,本次指纹与 ssh-keygen 逐字符一致

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-24 18:06:39 +08:00

61 lines
2.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import XCTest
@testable import TXCore
final class SSHWireTests: XCTestCase {
func testStringEncoding() {
XCTAssertEqual(SSHWire.string([0xAA, 0xBB]), [0, 0, 0, 2, 0xAA, 0xBB])
XCTAssertEqual(SSHWire.string(""), [0, 0, 0, 0])
XCTAssertEqual(SSHWire.string("nistp256"), [0, 0, 0, 8] + Array("nistp256".utf8))
}
func testMpint() {
// 0
XCTAssertEqual(SSHWire.mpint([0x01, 0x02]), [0, 0, 0, 2, 0x01, 0x02])
// 1 0x00
XCTAssertEqual(SSHWire.mpint([0xFF]), [0, 0, 0, 2, 0x00, 0xFF])
//
XCTAssertEqual(SSHWire.mpint([0x00, 0x00, 0x05]), [0, 0, 0, 1, 0x05])
// 0
XCTAssertEqual(SSHWire.mpint([0x00, 0x00]), [0, 0, 0, 0])
}
func testDerToSSHSignatureHighBit() {
// DER SEQUENCE{ INTEGER r(100), INTEGER s(0) }
let r = [UInt8(0x00), 0xFF] + [UInt8](repeating: 0x11, count: 31) // 33B DER
let s = [UInt8(0x01)] + [UInt8](repeating: 0x22, count: 31) // 32B DER
var der: [UInt8] = [0x30, UInt8(2 + r.count + 2 + s.count)]
der += [0x02, UInt8(r.count)] + r
der += [0x02, UInt8(s.count)] + s
let sig = ECDSAConv.derToSSHSignature(der)
XCTAssertNotNil(sig)
// mpint(r)+mpint(s)
let expected = SSHWire.mpint(r) + SSHWire.mpint(s)
XCTAssertEqual(sig, expected)
// r 1 mpint 33 0x21
XCTAssertEqual(Array(sig!.prefix(4)), [0, 0, 0, 0x21])
}
func testP256Blob() {
let q = [UInt8(0x04)] + [UInt8](repeating: 0xAB, count: 64) // X9.63 65B
let blob = ECDSAConv.p256PublicKeyBlob(x963: q)
// string("ecdsa-sha2-nistp256")
XCTAssertEqual(Array(blob.prefix(4)), [0, 0, 0, 0x13])
XCTAssertEqual(Array(blob[4 ..< 4 + 19]), Array("ecdsa-sha2-nistp256".utf8))
}
/// 192.168.9.199 ecdsa host key `ssh-keygen -lf`
func testOpenSSHFingerprintRealVector() {
let b64 = "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCkvFPRkGE8RGQ+scBa3JZMWnZnGUn7BWfsz8rfEtKjIojjqxxJLdZvQE9rUlaNNUFi8eGb9lfr5rO4yFS0dnsU="
let blob = Data(base64Encoded: b64)!
XCTAssertEqual(HostKey.opensshFingerprint(blob), "SHA256:dcpjdomtDzOZJuv/NHr1vYtm0mP5EbsEML0kClhgqxg")
}
func testEvaluate() {
let a = Data([1, 2, 3]); let b = Data([1, 2, 3]); let c = Data([9])
XCTAssertEqual(HostKey.evaluate(stored: nil, presented: a), .firstUse)
XCTAssertEqual(HostKey.evaluate(stored: b, presented: a), .trusted)
XCTAssertEqual(HostKey.evaluate(stored: c, presented: a), .mismatch(stored: c))
}
}