feat: M4b publickey 认证(SE 优先/软件回退,sign_callback)
- TXTransport: SSHSigner 协议 + Authentication.publicKeyCallback;SSHSession 用 @convention(c) sshSignCallback(abstract 桥 SignerBox + malloc 出参)接 libssh2_userauth_publickey - app SigningKeyProvider: SE 优先(kSecAttrTokenIDSecureEnclave),未签名/无 SE 回退软件 P-256 (导出落文件持久化),同一 SSHSigner 路径;SecKeyCreateSignature(ecdsa)→ECDSAConv.derToSSHSignature - 公钥 blob=ecdsa-sha2-nistp256||nistp256||X963;-txPubkeyAuth 日志打 authorized_keys 行 - 验证(192.168.9.199):不给密码,公钥加 authorized_keys 后免密登录成功(whoami=kid); 模拟器 SE 生成 hw=true 可达,真机 SE 硬件签名+keychain 持久化待补 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -240,10 +240,14 @@ final class SSHTerminalModel: ObservableObject {
|
||||
|
||||
// MARK: - 公开入口
|
||||
|
||||
/// M4b:非 nil 时用 publickey(SE/软件签名器) 认证而非密码。
|
||||
private var pubkeySigner: SigningKeyProvider?
|
||||
|
||||
func connect(host: String, port: Int, username: String, password: String) {
|
||||
let egress = tsnetAuthKey != nil ? "tsnet" : "direct"
|
||||
let auth: SSHConfig.Authentication = pubkeySigner.map { .publicKeyCallback($0) } ?? .password(password)
|
||||
config = SSHConfig(host: host, port: port, username: username,
|
||||
authentication: .password(password),
|
||||
authentication: auth,
|
||||
hostKeyVerifier: makeHostKeyVerifier(egress: egress, host: host, port: port))
|
||||
run(machine.reduce(.connectRequested))
|
||||
}
|
||||
@@ -324,6 +328,13 @@ final class SSHTerminalModel: ObservableObject {
|
||||
autoCommand = nil // mosh 模式用自己的引导流程,不用 txAutoCommand
|
||||
}
|
||||
let realPort = port == 0 ? 22 : port
|
||||
// M4b:publickey 认证(SE/软件签名器)。日志打出 authorized_keys 行供加入服务器。
|
||||
if d.bool(forKey: "txPubkeyAuth") {
|
||||
pubkeySigner = SigningKeyProvider.loadOrCreate()
|
||||
if let s = pubkeySigner {
|
||||
NSLog("M4DBG authorized_keys hw=\(s.isHardwareBacked): \(s.authorizedKeysLine)")
|
||||
}
|
||||
}
|
||||
// 无头验证:播种一个假 pin → 真实 host key 将 mismatch,触发 alert 路径。
|
||||
if let b64 = d.string(forKey: "txHostKeyPinOverrideBase64"), let fake = Data(base64Encoded: b64) {
|
||||
let egress = tsnetAuthKey != nil ? "tsnet" : "direct"
|
||||
|
||||
Reference in New Issue
Block a user