╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────────╮ │src/serve_ssh_protocol.zig│ ╰──────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │1272 main_key: [32]u8, // K_2 │ │1273 header_key: [32]u8, // K_1 │ │1274 seq: u64, │ │1275 + idle: ?*IdleState = null, │ │1276 │ │1277 pub fn init(key_material: *const [64]u8, initial_seq: u64) Cipher {│ │1278 return .{ │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │1282 }; │ │1283 } │ │1284 │ │1285 + /// swap in new key material after a rekey, leaving the rest of the │ │1286 + /// cipher state alone │ │1287 + fn setKeys(self: *Cipher, key_material: *const [64]u8, seq: u64) void {│ │1288 + self.main_key = key_material[0..32].*; │ │1289 + self.header_key = key_material[32..64].*; │ │1290 + self.seq = seq; │ │1291 + } │ │1292 + │ │1293 fn makeNonce(seq: u64) [8]u8 { │ │1294 var nonce: [8]u8 = undefined; │ │1295 std.mem.writeInt(u64, &nonce, seq, .big); │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │1389 const payload = try allocator.dupe(u8, enc_body[1 .. 1 + payload_len]);│ │1390 │ │1391 self.seq += 1; │ │1392 + if (self.idle) |idle| _ = idle.activity.fetchAdd(1, .monotonic); │ │1393 return payload; │ │1394 } │ │1395 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │1423 writer: *std.Io.Writer, │ │1424 cs_cipher: *Cipher, │ │1425 sc_cipher: *Cipher, │ │1263 - session_id: *const [Sha256.digest_length]u8, │ │1426 + rekey: *const RekeyState, │ │1427 ) ![fingerprint_len]u8 { │ │1428 // step 1: service request for ssh-userauth → service accept│ │1429 { │ ╰──────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1267 - const req = try readNonIgnoredPacket(cs_cipher, allocator, reader); │ │1430 + const req = try readSessionPacket(io, allocator, reader, writer, cs_cipher, sc_cipher, rekey);│ │1431 defer allocator.free(req); │ │1269 - if (req.len >= 1 and req[0] == SSH_MSG_KEXINIT) { │ │1270 - try sendDisconnect(io, allocator, sc_cipher, writer, "rekey is not supported"); │ │1271 - return error.RekeyUnsupported; │ │1272 - } │ │1432 if (req.len < 1 or req[0] != SSH_MSG_SERVICE_REQUEST) return error.UnexpectedMessage; │ │1433 │ │1434 var req_reader = std.Io.Reader.fixed(req[1..]); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1447 // signature verifies against the offered pubkey. │ │1448 var auth_attempts: u32 = 0; │ │1449 while (true) { │ │1291 - const req = try readNonIgnoredPacket(cs_cipher, allocator, reader); │ │1450 + const req = try readSessionPacket(io, allocator, reader, writer, cs_cipher, sc_cipher, rekey);│ │1451 defer allocator.free(req); │ │1293 - if (req.len >= 1 and req[0] == SSH_MSG_KEXINIT) { │ │1294 - try sendDisconnect(io, allocator, sc_cipher, writer, "rekey is not supported"); │ │1295 - return error.RekeyUnsupported; │ │1296 - } │ │1452 if (req.len < 1 or req[0] != SSH_MSG_USERAUTH_REQUEST) return error.UnexpectedMessage; │ │1453 │ │1454 var req_reader = std.Io.Reader.fixed(req[1..]); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │1458 defer allocator.free(service_name); │ │1459 const method = try takeStringField(allocator, &req_reader, 64); │ │1460 defer allocator.free(method); │ │1461 + │ │1462 + // RFC 4252 §5: the server must verify the requested service │ │1463 + if (!std.mem.eql(u8, service_name, "ssh-connection")) { │ │1464 + auth_attempts += 1; │ │1465 + if (auth_attempts >= max_auth_attempts) return error.TooManyAuthAttempts;│ │1466 + try sendUserauthFailure(io, allocator, sc_cipher, writer); │ │1467 + continue; │ │1468 + } │ │1469 │ │1470 if (!std.mem.eql(u8, method, "publickey")) { │ │1471 auth_attempts += 1; │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────╮ │1508 │ │1509 const ok = verifyUserauthSignature(│ │1510 allocator, │ │1348 - session_id, │ │1511 + &rekey.session_id, │ │1512 user_name, │ │1513 service_name, │ │1514 algo, │ ╰─────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │1542 try sc_cipher.writePacket(io, allocator, writer, buf.items); │ │1543 } │ │1544 │ │1382 -fn sendDisconnect( │ │1383 - io: std.Io, │ │1384 - allocator: std.mem.Allocator, │ │1385 - sc_cipher: *Cipher, │ │1386 - writer: *std.Io.Writer, │ │1387 - description: []const u8, │ │1388 -) !void { │ │1389 - var buf: std.ArrayList(u8) = .empty; │ │1390 - defer buf.deinit(allocator); │ │1391 - try buf.append(allocator, SSH_MSG_DISCONNECT); │ │1392 - try writeU32(&buf, allocator, SSH_DISCONNECT_PROTOCOL_ERROR); │ │1393 - try writeStringField(&buf, allocator, description); │ │1394 - try writeStringField(&buf, allocator, ""); │ │1395 - try sc_cipher.writePacket(io, allocator, writer, buf.items); │ │1396 -} │ │1397 - │ │1545 /// Append the canonical publickey-signed-data bytes (RFC 4252 §7) to `buf`.│ │1546 /// Used by the server to recompute the signed input for verification │ │1547 pub fn appendPublickeySignedData( │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────╮ │1640 writer: *std.Io.Writer, │ │1641 cs_cipher: *Cipher, │ │1642 sc_cipher: *Cipher, │ │1643 + rekey: *const RekeyState, │ │1644 fingerprint: *const [fingerprint_len]u8,│ │1645 handler: anytype, │ │1646 ) !void { │ ╰──────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯