豫言 / 安全外壳会话 @ 0.1.0
连接 SSH channel 数据与原生伪终端读写及流量窗口。
包说明.汉语.md
# 安全外壳会话 `重换钥。豫` 保存首次 `session_id` 和本轮待启用的双向 AES-256-GCM 密钥、IV。调用方用旧钥发送并认证 `NEWKEYS` 后,分别切换发送和接收方向;状态接口拒绝同方向重复切换。豫言客户端与服务端互通探针均可在认证后、开启通道前主动发起一轮重协商;客户端已与真实 OpenSSH 服务端互通,服务端已与真实 OpenSSH 客户端互通。服务端会话与客户端互通探针现均按本轮任一方向报文数自动换钥,默认阈值 4096 包。 `服务端重换钥。豫` 验证客户端与服务端 KEXINIT 的曲线、主机密钥、双向 GCM 和无压缩候选项,再用客户端 ECDH_INIT、服务器临时种子和主机私种生成 ECDH_REPLY 与待切换密钥状态。它沿用首次 `session_id`;发送回报、收发 `NEWKEYS` 和切换方向仍由调用方负责。 `重换钥传输。豫` 将剩余密文缓冲和双向密钥、IV 保存为一个传输状态。服务端收到客户端 KEXINIT 后,可用此状态完成加密的 ECDH_INIT、ECDH_REPLY 与双向 NEWKEYS;发送 NEWKEYS 后才切换发送钥,验收对端 NEWKEYS 后才切换接收钥。服务端主动发起时,旧钥验证后先到的通道报文按顺序暂存,最多 16 条、合计 1 MiB,换钥后再交给桥接层。自动触发以本轮双向 IV 为基准,默认任一方向累计 4096 包即重换钥;计数器接近末界时提前触发。 `应按时重换钥吗` 接受本轮起始和当前的单调纳秒读数,阈值为 1 至 86400 秒;达到阈值返回真,时钟倒退则报错。客户端互通探针与服务端标准流、PTY 会话桥接均以默认 3600 秒间隔调用它,并在换钥后重置起始时间。服务端桥接与客户端单步收报后的就绪等待会周期返回以复查时限,半包不会使客户端一直阻塞到整帧到齐。 `客户端重换钥传输。豫` 在已打开的会话中收到服务端 KEXINIT 后,重新验证 Ed25519 主机签名,沿用首次 `session_id` 派钥,并在双向 NEWKEYS 边界切换。豫言客户端已与豫言服务端在无 PTY 小窗口输出和 PTY 数据回传中验证此路径。客户端也可在通道已打开后先发 KEXINIT,并有界暂存等待服务端协商期间收到的已认证通道报文;打开通道后、请求命令前的先发路径已与真实 OpenSSH 服务端互通。 `客户端会话收包。豫` 单步读取并认证一帧密报。未收齐时返回状态 0,完整通道或换钥载荷返回 1,合法传输控制、未知全局请求或窗口调整处理后返回 2;剩余密文、双向下一 IV 始终随结果返回。调用方可在状态 0 等待就绪并复查计时器,无需阻塞至整帧到齐。客户端互通探针在小窗口输出和空闲计时换钥路径中已使用该接口。 无 PTY 标准流和 PTY 双向桥接在收到已认证的客户端 KEXINIT 后保存当前窗口、EOF、待写数据和剩余网络缓冲,完成重换钥后以新密钥继续;退出报告和通道关闭也使用新发送密钥。关闭等待期若再收到 KEXINIT,服务端仍会尝试完成重协商;本端已发送 CLOSE 后,对端明确 DISCONNECT 或关闭连接可结束等待。客户端发起的运行中重协商已与真实 OpenSSH 的无 PTY、PTY 会话互通;服务端按报文数自动触发已与真实 OpenSSH 在两种会话中互通。客户端互通探针的按报文数及按时间自动触发亦已与真实 OpenSSH 服务端互通;客户端单步收包可在完整空闲或半包时周期复查时限。 `标准流桥接。豫` 为无 PTY 会话封装 stdout 的 CHANNEL_DATA 和 stderr 的 CHANNEL_EXTENDED_DATA,按两路共用的远端窗口及最大包限制读取。单步 stdin 写入返回实际写入量和未写尾部,供调用方按实际写入量回补接收窗口。标准流 EOF 分别返回,只有两路均结束后才应发送通道 EOF;`标准流会话。豫` 负责单通道加密收发与三路标准流就绪事件循环,调用方负责子进程、exit-status 和 CLOSE 生命周期。 `双向转发终端` 返回发送 IV、剩余网络字节、接收 IV、是否已收到客户端 EOF,以及当前发送和接收密钥。PTY 子进程可先退出;调用方据 EOF 标志记录通道寿命,并用返回的密钥发送 exit-status、EOF 和 CLOSE。 标准流与 PTY 双向桥接会识别本通道的 `signal` 请求,按 RFC 4254 标准信号名调用原生接口;仅向本库登记的子进程或 PTY 进程组发送,不回请求应答。未知扩展名忽略。豫言客户端与服务端已分别验证无 PTY、PTY 的 `TERM` 和 `INT` 请求及对应 `exit-signal`;正常退出仍发送 `exit-status`。 `桥接。豫` 在已认证、已打开的 SSH session channel 与本机 PTY 主端之间搬运原始字节。`等待连接与伪终端` 以同一次原生多路等待观察 SSH 套接字和 PTY,网络端始终关注可读,PTY 可选择不关注、可读、可写或读写;返回两个独立事件位和状态。入站先解析 CHANNEL_DATA 并扣减本端接收窗口,再尝试非阻塞写入 PTY;实际未写入的尾部原样返回。`冲刷伪终端待写至尽` 会等待可写并重试,返回累计写入量及剩余尾部;超时仍保留尾部,调用方须在继续接收网络数据前处理它。出站读取量不超过对端窗口、对端最大通道包和 64 KiB,并返回新的对端窗口。入站待写缓冲上限为 1 MiB。 状态 0 表示入站处理成功;负的普通数值为原生 `-errno`,`-100001` 至 `-100004` 为消息、通道、缓冲或参数错误,`-100005` 表示待写重试次数耗尽。出站状态 0 表示窗口阻塞,1 表示产生 CHANNEL_DATA,2 表示 PTY EOF 并产生 CHANNEL_EOF,负值为错误。调用方负责按实际已写入 PTY 的字节发送 WINDOW_ADJUST,并确保 EOF 只发送一次。本库不启动程序,也不维护整个 SSH 连接状态。 `加密收包。豫` 从已有 TCP 缓冲区优先提取并认证一帧 AES-256-GCM 报文;若未收齐,单步接口最多非阻塞读取 64 KiB,保留半包、粘包剩余字节和当前 IV。状态 0 表示等待更多数据,1 表示已得到一帧,2 表示连接关闭,负值表示报头、认证或网络错误。会话循环可在状态 0 时转去处理 PTY 事件。客户端和服务端互通探针均已使用该接口收取加密报文。 会话桥接收到已认证的传输控制载荷时,严格检查 `IGNORE`、`UNIMPLEMENTED` 和 `DEBUG` 的字段并继续会话;合法的 `DISCONNECT` 结束会话,格式错误的控制报文被拒绝。此处理适用于 PTY 和无 PTY 的会话循环。 通道运行期间收到 `GLOBAL_REQUEST` 时,两种桥接均检查名称和 `want_reply` 字段,保留请求专属数据但不执行未知请求;要求应答时发送 `REQUEST_FAILURE`,并更新发送方向的 IV 后继续原通道。不要求应答的请求直接跳过,非法报文终止会话。 `加密发包。豫` 处理加密帧的部分写入与可写等待,完整发出后才返回下一发送 IV;发送失败后调用方应终止此连接。`双向终端。豫` 是服务端单通道 PTY 桥接:交替处理网络和终端就绪事件,按实际写入回补接收窗口,按对端窗口发送数据,解析数据、增窗、EOF 和终端尺寸变化,保留接收缓冲与双向 IV。调用前须已完成认证与通道开启,并提供本地通道号 0、最大接收包 32768 字节及规范行 PTY;客户端 EOF 通过 EOT 传给终端。桥接不启动或回收子进程,也不发送 exit-status/CLOSE;这些由调用方完成。当前仍是单通道、有界空闲的会话接口,不处理会话中的其他 SSH 消息。
包说明.文言.md
# 安全外壳会话 「重换钥。豫」存首次 `session_id` 与本轮待启之双向 AES-256-GCM 钥、IV。调用者以旧钥送且验 `NEWKEYS` 后,发收各自易钥;同向重易则拒。豫言客户与服务者探针皆可于认证后、开通道前主动再议;客户已与真 OpenSSH 服务者通,服务者已与真 OpenSSH 客通。服务者会话与客户互通探针今皆依双向报数自易钥,常限四千零九十六报。 「服务端重换钥。豫」核客、服 KEXINIT 之曲线、主钥、双向 GCM 及无压缩候选,复以客 ECDH_INIT、服务临时种与主私种造 ECDH_REPLY 及待易钥态。仍循首次 `session_id`;送回报、收发 `NEWKEYS` 与各向易钥,皆由调用者掌之。 「重换钥传输。豫」合余密缓冲与双向钥、IV 为一态。服务者既收客户 KEXINIT,可凭此态行加密 ECDH_INIT、ECDH_REPLY 与双向 NEWKEYS;己发 NEWKEYS 后乃易发钥,验彼 NEWKEYS 后乃易收钥。服务者先发之时,以旧钥验先至通道报,循序暂存,至多十六报、共一兆字;换钥后复交桥接。自发之限以本轮双向 IV 为基,常为任一向四千零九十六报;计数将尽则先易。 「应按时重换钥吗」受本轮始、此刻之单调钟纳秒数,限一至八万六千四百秒;足限则阳,钟倒行则报错。客户互通探针及服务者常流、PTY 双向桥皆用之,常隔三千六百秒,易钥后重记始刻。服务者桥与客户单步收报后候就绪,皆可周期复察时限;半报不使客户阻至整帧齐。 「客户端重换钥传输。豫」于已开会话得服务者 KEXINIT,复验 Ed25519 主钥签,循首次 `session_id` 派钥,于双向 NEWKEYS 之界各易之。豫言客户已与豫言服务者于无 PTY 微窗输出及 PTY 数据回传验此途。客户亦可于通道已开后先发 KEXINIT,候服务者协商时有界暂存已验通道报;开通道而未请命令之先发路已与真 OpenSSH 服务者通。 「客户端会话收包。豫」单步读验一密报;未足返零,完整通道或再议报返一,合法控制、未知全局请或增窗既治返二。余密缓冲及双向后继 IV 随果还。调用者得于零态候就绪而复察时限,不必阻至整帧齐。客户互通探针之微窗输出与久闲依时再议皆用此术。 无 PTY 常流及 PTY 双向桥既得已验之客户 KEXINIT,存旧窗、EOF、待写字与网余缓冲,换钥后以新钥续行;退出报与通道关闭亦用新发钥。候 CLOSE 时若复得 KEXINIT,仍试再议;己发 CLOSE 后,彼明发 DISCONNECT 或断连,可止候。客户发起之运行中再议已与真 OpenSSH 于二式互通;服务者依报数自发者亦于二式互通。客户互通探针依报数及依时自发者亦与真 OpenSSH 服务者通;客户单步收报,无字或半报时皆可周期复察时限。 「标准流桥接。豫」于无 PTY 会话,封 stdout 为 CHANNEL_DATA,stderr 为 CHANNEL_EXTENDED_DATA;二出同耗彼窗,读数不得逾最大包。stdin 单步写返实写数及未写余尾,调用者据实写数回增收窗。二出之 EOF 各别返,二者皆尽方宜发通道 EOF;「标准流会话。豫」掌单通道密报收发及三流就绪之循环;调用者掌子进程、exit-status 与 CLOSE 之寿命。 「双向转发终端」返发 IV、网余字、收 IV、彼 EOF 已至之爻,及在用发收钥。PTY 子进程可先终;调用者依 EOF 爻记通道寿命,以所返钥继发 exit-status、EOF、CLOSE。 标准流与 PTY 双向桥皆识本通道 `signal` 请,依 RFC 4254 常名调用原生术;惟向本库在籍子进程或 PTY 进程组发送,不回请答。未知扩展名暂略。豫言客与服务者已各验无 PTY、PTY 之 `TERM`、`INT` 请及相应 `exit-signal`;常退仍发 `exit-status`。 「桥接。豫」于已认证、已开之 SSH session 通道与本机 PTY 主端间转原字节。「等待连接与伪终端」一候网连及 PTY,网端恒候读,终端可择无、读、写、读写,别返二事件码与状态。入者先析 CHANNEL_DATA,减己收窗,复试非阻塞写 PTY;未写余尾原样还。「冲刷伪终端待写至尽」候可写而续冲,返累计已写数与余尾;逾次仍留尾,调用者未清前勿续收网报。出者所读不逾彼窗、彼最大通道包及六万五千五百三十六字节,并还彼新窗。入端待写限一兆字节。 入端状态零为成;普通负数为原生 `-errno`,`-100001` 至 `-100004` 分指报、通道、缓冲、参数之误,`-100005` 为待写重试次数尽。出端零为窗塞,一为得 CHANNEL_DATA,二为 PTY EOF 且得 CHANNEL_EOF,负为误。调用者按实写 PTY 字数发送 WINDOW_ADJUST,且 EOF 只发一回。此库不启程序,亦不总掌 SSH 连接状态。 「加密收包。豫」先自旧缓冲取一帧 AES-256-GCM 报而验签;未足则单步非阻塞读至多六万五千五百三十六字节,保半报、余帧及旧 IV。状态零待字,一已得报,二连已闭,负为头、签或网络之误。候字之际,会话循环可转治 PTY 事。客户与服务者探针皆以此术收加密报。 会话桥得已验之传输控制载物,严核 `IGNORE`、`UNIMPLEMENTED`、`DEBUG` 诸字段而续行;合法 `DISCONNECT` 则止,坏控制报则拒。PTY 与无 PTY 之循环皆施之。 通道行中得 `GLOBAL_REQUEST`,二桥皆核名与待答位,存其专用余文而不施未知请;待答则回 `REQUEST_FAILURE`,递进发向 IV 而续旧通道。不待答者径略,坏报则止。 「加密发包。豫」续写加密帧之未尽字,候可写而重试,报全发乃返后续 IV;若败,调用者当断此连。「双向终端。豫」为服务者单通道 PTY 桥:交治网与终端之就绪事,PTY 实写几字乃回增收窗,出文则守彼窗;析数据、增窗、EOF 与终端尺寸变,存余缓冲及二向 IV。调用前须已认证开通,授本地通道号零、最大收包三万二千七百六十八字节及规范行 PTY;客户 EOF 以 EOT 告终端。桥接不启亦不收子进程,不发 exit-status/CLOSE,皆由调用者行之。今惟单通道、有界空闲之术,不治会话中余类 SSH 报。