Files
markbase/markbase-core/src/ssh_server/server.rs
Warren 66f38698f5
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled
fix(ssh): correct signature to sign Exchange Hash instead of shared_secret
SSH签名修复完成(RFC 4253 Section 7.2):

问题:
- 之前直接签名shared_secret(错误)
- SSH协议要求签名Exchange Hash H

修复内容:
1. kex_exchange.rs:添加compute_exchange_hash函数
   - 计算H = SHA256(V_C || V_S || I_C || I_S || K_S || K_C || K_S || K)
   - 签名H而不是shared_secret

2. kex_exchange.rs:修改handle_kexdh_init函数
   - 添加client_version, server_version, kexinit_payloads参数
   - 传递所有Exchange Hash所需参数

3. server.rs:修改调用点
   - 传递KexState中的版本和KEXINIT payloads

测试结果:
-  SSH版本交换成功(SSH-2.0-MarkBaseSSH_1.0)
-  SSH_MSG_KEXINIT交换成功(curve25519-sha256)
-  签名验证通过(无incorrect signature错误)
-  SSH_MSG_NEWKEYS交换成功(加密通道建立)
-  加密packet MAC验证失败(cipher.rs AES-CTR待实现)

技术亮点:
-  符合RFC 4253标准
-  参考OpenSSH kex.c实现
-  完整Exchange Hash计算(SSH string + mpint格式)

下一步:
- 实现cipher.rs的AES-256-CTR加密功能
- 完成加密packet的MAC计算
- 测试完整SSH连接流程
2026-06-13 18:25:50 +08:00

285 lines
10 KiB
Rust
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.
// SSH服务器完整实现Phase 1-7集成版
// 参考OpenSSH sshd.c: complete SSH/SFTP flow
use crate::ssh_server::version::VersionExchange;
use crate::ssh_server::packet::{SshPacket, PacketType};
use crate::ssh_server::kex::{KexProposal, KexResult};
use crate::ssh_server::kex_complete::{KexState};
use crate::ssh_server::auth::{AuthHandler, AuthResult};
use crate::ssh_server::channel::{ChannelManager};
use anyhow::Result;
use log::{info, warn, error, debug};
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io::{Read, Write};
/// SSH服务器配置
pub struct SshServerConfig {
pub port: u16,
pub bind_address: String,
}
impl Default for SshServerConfig {
fn default() -> Self {
Self {
port: 2024,
bind_address: "127.0.0.1".to_string(),
}
}
}
/// SSH服务器主结构Phase 1-7完整版
pub struct SshServer {
config: SshServerConfig,
}
impl SshServer {
pub fn new(config: SshServerConfig) -> Self {
Self { config }
}
pub fn run(&self) -> Result<()> {
let bind_addr = format!("{}:{}", self.config.bind_address, self.config.port);
let listener = TcpListener::bind(&bind_addr)?;
info!("MarkBaseSSH server listening on {}", bind_addr);
info!("Implementation: Complete SSH/SFTP (Phase 1-7)");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let client_addr = stream.peer_addr()?;
info!("New SSH connection from {}", client_addr);
thread::spawn(move || {
if let Err(e) = handle_connection_complete(stream) {
error!("Connection error: {}", e);
}
});
}
Err(e) => {
warn!("Failed to accept connection: {}", e);
}
}
}
Ok(())
}
}
/// 处理完整SSH连接Phase 1-7完整流程
fn handle_connection_complete(stream: TcpStream) -> Result<()> {
info!("Handling client connection (Phase 1-7 complete flow)");
let mut stream = stream;
// Phase 1: 版本交换
let client_version = VersionExchange::exchange(&mut stream)?;
info!("Version exchange: client={}, server=SSH-2.0-MarkBaseSSH_1.0", client_version);
// Phase 2: 算法协商
let (kex_result, server_kexinit, client_kexinit) = perform_kex_negotiation_complete(&mut stream)?;
info!("KEX negotiation: KEX={}, Cipher={}", kex_result.kex_algorithm, kex_result.encryption_ctos);
// Phase 3: 密钥交换完整流程
perform_complete_kex_exchange(&mut stream, client_version.clone(), kex_result, server_kexinit, client_kexinit)?;
info!("Key exchange completed, encryption channel ready");
// Phase 5: SSH认证参考OpenSSH auth2.c
let mut auth_handler = AuthHandler::new()?;
let auth_user = perform_ssh_auth(&mut stream, &mut auth_handler)?;
info!("SSH authentication succeeded: user={}", auth_user);
// Phase 6: SSH Channel管理参考OpenSSH channel.c
let mut channel_manager = ChannelManager::new();
// Phase 6-7: SSH服务循环处理channel请求
handle_ssh_service_loop(&mut stream, &mut channel_manager)?;
info!("SSH session completed successfully");
Ok(())
}
/// 完整算法协商返回KEXINIT payloads
fn perform_kex_negotiation_complete(stream: &mut TcpStream) -> Result<(KexResult, SshPacket, SshPacket)> {
info!("Starting complete KEX negotiation");
// 1. 发送服务器KEXINIT
let server_proposal = KexProposal::server_default();
let server_kexinit = server_proposal.to_kexinit_packet()?;
server_kexinit.write(stream)?;
info!("Sent server KEXINIT (payload size: {} bytes)", server_kexinit.payload.len());
// 2. 接收客户端KEXINIT
let client_kexinit = SshPacket::read(stream)?;
let client_proposal = KexProposal::from_kexinit_packet(&client_kexinit)?;
info!("Received client KEXINIT (payload size: {} bytes)", client_kexinit.payload.len());
// 3. 算法匹配
let kex_result = KexResult::choose_algorithms(&server_proposal, &client_proposal)?;
Ok((kex_result, server_kexinit, client_kexinit))
}
/// 完整密钥交换流程Phase 3核心
fn perform_complete_kex_exchange(
stream: &mut TcpStream,
client_version: String,
kex_result: KexResult,
server_kexinit: SshPacket,
client_kexinit: SshPacket,
) -> Result<()> {
info!("Starting complete key exchange flow");
// 1. 创建密钥交换状态
let mut kex_state = KexState::new(
client_version,
"SSH-2.0-MarkBaseSSH_1.0".to_string(),
kex_result,
)?;
// 2. 保存KEXINIT payloads用于Exchange Hash
kex_state.save_kexinit_payloads(&client_kexinit, &server_kexinit);
// 3. 接收SSH_MSG_KEX_ECDH_INIT
let kexdh_init = SshPacket::read(stream)?;
info!("Received SSH_MSG_KEX_ECDH_INIT");
// 4. 处理KEXDH_INIT并生成KEXDH_REPLY
let kexdh_reply = kex_state.exchange_handler.handle_kexdh_init(
&kexdh_init,
&kex_state.client_version,
&kex_state.server_version,
&kex_state.client_kexinit_payload,
&kex_state.server_kexinit_payload,
)?;
kexdh_reply.write(stream)?;
info!("Sent SSH_MSG_KEX_ECDH_REPLY");
// 5. 发送SSH_MSG_NEWKEYS
let newkeys_packet = KexState::send_newkeys()?;
newkeys_packet.write(stream)?;
kex_state.newkeys_sent = true;
info!("Sent SSH_MSG_NEWKEYS");
// 6. 接收SSH_MSG_NEWKEYS
let client_newkeys = SshPacket::read(stream)?;
kex_state.handle_newkeys(&client_newkeys)?;
info!("Received SSH_MSG_NEWKEYS");
// 7. 验证加密通道建立
if kex_state.is_encryption_ready() {
info!("Encryption channel established successfully");
} else {
return Err(anyhow::anyhow!("Encryption channel not ready"));
}
Ok(())
}
/// SSH认证流程Phase 5
fn perform_ssh_auth(stream: &mut TcpStream, auth_handler: &mut AuthHandler) -> Result<String> {
info!("Starting SSH authentication");
// 发送SSH_MSG_SERVICE_REQUEST
use byteorder::{BigEndian, WriteBytesExt};
let mut service_accept_payload = Vec::new();
service_accept_payload.write_u8(PacketType::SSH_MSG_SERVICE_ACCEPT as u8)?;
service_accept_payload.write_u32::<BigEndian>(14)?; // "ssh-userauth".len()
service_accept_payload.write_all("ssh-userauth".as_bytes())?;
let service_accept = SshPacket::new(service_accept_payload);
service_accept.write(stream)?;
info!("Sent SSH_MSG_SERVICE_ACCEPT (ssh-userauth)");
// 认证循环
loop {
let auth_packet = SshPacket::read(stream)?;
info!("Received SSH_MSG_USERAUTH_REQUEST");
match auth_handler.handle_userauth_request(&auth_packet)? {
AuthResult::Success => {
// 发送SSH_MSG_USERAUTH_SUCCESS
let success_payload = vec![PacketType::SSH_MSG_USERAUTH_SUCCESS as u8];
let success_packet = SshPacket::new(success_payload);
success_packet.write(stream)?;
info!("Sent SSH_MSG_USERAUTH_SUCCESS");
return Ok("demo".to_string()); // 返回默认用户名
}
AuthResult::Failure(message) => {
// 发送SSH_MSG_USERAUTH_FAILURE
let mut failure_payload = Vec::new();
failure_payload.write_u8(PacketType::SSH_MSG_USERAUTH_FAILURE as u8)?;
failure_payload.write_u32::<BigEndian>(9)?; // "password".len()
failure_payload.write_all("password".as_bytes())?;
failure_payload.write_u8(0)?; // partial_success = false
let failure_packet = SshPacket::new(failure_payload);
failure_packet.write(stream)?;
warn!("Sent SSH_MSG_USERAUTH_FAILURE: {}", message);
}
AuthResult::PartialSuccess => {
// 部分成功多步骤认证Phase 5不实现
warn!("Partial success auth not implemented");
continue;
}
}
}
}
/// SSH服务循环Phase 6
fn handle_ssh_service_loop(
stream: &mut TcpStream,
channel_manager: &mut ChannelManager,
) -> Result<()> {
info!("Starting SSH service loop (channel management)");
loop {
let packet = SshPacket::read(stream)?;
match packet.payload.first() {
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_OPEN as u8 => {
info!("Received SSH_MSG_CHANNEL_OPEN");
let response = channel_manager.handle_channel_open(&packet)?;
response.write(stream)?;
info!("Sent SSH_MSG_CHANNEL_OPEN_CONFIRMATION");
}
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_REQUEST as u8 => {
info!("Received SSH_MSG_CHANNEL_REQUEST");
if let Some(response) = channel_manager.handle_channel_request(&packet)? {
response.write(stream)?;
}
}
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_DATA as u8 => {
info!("Received SSH_MSG_CHANNEL_DATA");
channel_manager.handle_channel_data(&packet)?;
}
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_CLOSE as u8 => {
info!("Received SSH_MSG_CHANNEL_CLOSE");
channel_manager.handle_channel_close(&packet)?;
break;
}
Some(&pt) if pt == PacketType::SSH_MSG_DISCONNECT as u8 => {
info!("Received SSH_MSG_DISCONNECT");
break;
}
_ => {
warn!("Unknown packet type: {:?}", packet.payload.first());
}
}
}
Ok(())
}
/// SSH服务器CLI入口
pub fn run_ssh_server(port: Option<u16>) -> Result<()> {
let config = SshServerConfig {
port: port.unwrap_or(2024),
bind_address: "127.0.0.1".to_string(),
};
let server = SshServer::new(config);
server.run()
}