╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────────╮ │src/serve_ssh_protocol.zig│ ╰──────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │921 // chacha20-poly1305@openssh.com wants 64 bytes per direction (32-byte main key│ │922 // + 32-byte header key); SHA256 produces 32, so each encrypt key is two hash │ │923 // blocks chained per RFC 4253. │ │917 -const SessionKeys = struct { │ │924 +pub const SessionKeys = struct { │ │925 cs_iv: [16]u8, │ │926 sc_iv: [16]u8, │ │927 cs_enc: [64]u8, │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────╮ │928 sc_enc: [64]u8, │ │929 }; │ │930 │ │924 -fn deriveSessionKeys( │ │931 +pub fn deriveSessionKeys( │ │932 allocator: std.mem.Allocator,│ │933 shared_secret: []const u8, │ │934 exchange_hash: []const u8, │ ╰──────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │1002 // padding) — the 4-byte length field is excluded from alignment. body must│ │1003 // be a multiple of 8 bytes; minimum padding 4 bytes. │ │1004 │ │ 998 -const Cipher = struct { │ │1005 +pub const Cipher = struct { │ │1006 main_key: [32]u8, // K_2 │ │1007 header_key: [32]u8, // K_1 │ │1008 seq: u64, │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │1009 │ │1003 - fn init(key_material: *const [64]u8, initial_seq: u64) Cipher { │ │1010 + pub fn init(key_material: *const [64]u8, initial_seq: u64) Cipher {│ │1011 return .{ │ │1012 .main_key = key_material[0..32].*, │ │1013 .header_key = key_material[32..64].*, │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────╮ │1021 return nonce; │ │1022 } │ │1023 │ │1017 - fn writePacket( │ │1024 + pub fn writePacket( │ │1025 self: *Cipher, │ │1026 io: std.Io, │ │1027 allocator: std.mem.Allocator,│ ╰───────────────────────────────────────────╯ ╭───────────────────────────────────────────╮ │1071 self.seq += 1; │ │1072 } │ │1073 │ │1067 - fn readPacket( │ │1074 + pub fn readPacket( │ │1075 self: *Cipher, │ │1076 allocator: std.mem.Allocator,│ │1077 reader: *std.Io.Reader, │ ╰───────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │1284 try sc_cipher.writePacket(io, allocator, writer, buf.items); │ │1285 } │ │1286 │ │1287 +/// Append the canonical publickey-signed-data bytes (RFC 4252 §7) to `buf`.│ │1288 +/// Used by the server to recompute the signed input for verification │ │1289 +pub fn appendPublickeySignedData( │ │1290 + buf: *std.ArrayList(u8), │ │1291 + allocator: std.mem.Allocator, │ │1292 + session_id: []const u8, │ │1293 + user_name: []const u8, │ │1294 + service_name: []const u8, │ │1295 + algo: []const u8, │ │1296 + pubkey_blob: []const u8, │ │1297 +) !void { │ │1298 + try writeStringField(buf, allocator, session_id); │ │1299 + try buf.append(allocator, SSH_MSG_USERAUTH_REQUEST); │ │1300 + try writeStringField(buf, allocator, user_name); │ │1301 + try writeStringField(buf, allocator, service_name); │ │1302 + try writeStringField(buf, allocator, "publickey"); │ │1303 + try buf.append(allocator, 1); │ │1304 + try writeStringField(buf, allocator, algo); │ │1305 + try writeStringField(buf, allocator, pubkey_blob); │ │1306 +} │ │1307 + │ │1308 // build the bytes a publickey signature is computed over (RFC 4252 §7) and │ │1309 // verify the supplied signature against them. │ │1310 fn verifyUserauthSignature( │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1316 pubkey_blob: []const u8, │ │1317 signature_blob: []const u8, │ │1318 ) !bool { │ │1291 - // signed data: │ │1292 - // string session_id │ │1293 - // byte SSH_MSG_USERAUTH_REQUEST │ │1294 - // string user_name │ │1295 - // string service_name │ │1296 - // string "publickey" │ │1297 - // bool TRUE │ │1298 - // string algo │ │1299 - // string pubkey │ │1319 var signed: std.ArrayList(u8) = .empty; │ │1320 defer signed.deinit(allocator); │ │1302 - try writeStringField(&signed, allocator, session_id); │ │1303 - try signed.append(allocator, SSH_MSG_USERAUTH_REQUEST); │ │1304 - try writeStringField(&signed, allocator, user_name); │ │1305 - try writeStringField(&signed, allocator, service_name); │ │1306 - try writeStringField(&signed, allocator, "publickey"); │ │1307 - try signed.append(allocator, 1); │ │1308 - try writeStringField(&signed, allocator, algo); │ │1309 - try writeStringField(&signed, allocator, pubkey_blob); │ │1321 + try appendPublickeySignedData(&signed, allocator, session_id, user_name, service_name, algo, pubkey_blob);│ │1322 │ │1323 // parse pubkey_blob: string "ssh-ed25519" || string raw_pubkey │ │1324 var pubkey_reader = std.Io.Reader.fixed(pubkey_blob); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │1718 try sc_cipher.writePacket(io, allocator, writer, adj.items); │ │1719 } │ │1720 │ │1709 -fn writeU32(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, value: u32) !void { │ │1721 +pub fn writeU32(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, value: u32) !void {│ │1722 var bytes: [4]u8 = undefined; │ │1723 std.mem.writeInt(u32, &bytes, value, .big); │ │1724 try buf.appendSlice(allocator, &bytes); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────╮ │src/test/ssh.zig│ ╰────────────────╯ ╭───────────────────────────────────────╮ │1 const std = @import("std"); │ │2 -const builtin = @import("builtin"); │ │2 const hx = @import("haxy"); │ │3 const ssh = hx.serve_ssh; │ │4 const proto = hx.serve_ssh_protocol;│ ╰───────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯