/ firmware / src / services / ssh / wire.rs
wire.rs
   1  use super::codec::{ObjectReader, ObjectWriter};
   2  use super::error::ProtocolError;
   3  
   4  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
   5  pub enum Message<'a> {
   6      ServiceRequest {
   7          service_name: &'a str,
   8      },
   9      ServiceAccept {
  10          service_name: &'a str,
  11      },
  12      Disconnect {
  13          reason: DisconnectReason,
  14      },
  15      Ignore {
  16          data: &'a [u8],
  17      },
  18      Debug {
  19          always_display: bool,
  20          message: &'a str,
  21          language_tag: &'a str,
  22      },
  23      Unimplemented {
  24          sequence_number: u32,
  25      },
  26      KexInit {
  27          cookie: &'a [u8; 16],
  28          kex_algorithms: NameList<'a>,
  29          server_host_key_algorithms: NameList<'a>,
  30          encryption_algorithms_client_to_server: NameList<'a>,
  31          encryption_algorithms_server_to_client: NameList<'a>,
  32          mac_algorithms_client_to_server: NameList<'a>,
  33          mac_algorithms_server_to_client: NameList<'a>,
  34          compression_algorithms_client_to_server: NameList<'a>,
  35          compression_algorithms_server_to_client: NameList<'a>,
  36          languages_client_to_server: NameList<'a>,
  37          languages_server_to_client: NameList<'a>,
  38          first_kex_packet_follows: bool,
  39          reserved: u32,
  40      },
  41      NewKeys,
  42      KexEcdhInit {
  43          client_ephemeral_public_key: &'a [u8],
  44      },
  45      KexEcdhReply {
  46          server_public_host_key: PublicKey<'a>,
  47          server_ephemeral_public_key: &'a [u8],
  48          signature: Signature<'a>,
  49      },
  50      UserAuthRequest {
  51          user_name: &'a str,
  52          service_name: &'a str,
  53          auth_method: AuthMethod<'a>,
  54      },
  55      UserAuthFailure {
  56          authentications_that_can_continue: NameList<'a>,
  57          partial_success: bool,
  58      },
  59      UserAuthSuccess,
  60      UserAuthBanner {
  61          message: &'a str,
  62          language: &'a str,
  63      },
  64      UserAuthPkOk {
  65          public_key_algorithm_name: &'a str,
  66          public_key: PublicKey<'a>,
  67      },
  68      GlobalRequest {
  69          request_name: &'a str,
  70          want_reply: bool,
  71          payload: &'a [u8],
  72      },
  73      RequestSuccess {
  74          payload: &'a [u8],
  75      },
  76      RequestFailure,
  77      ChannelOpen {
  78          channel: ChannelType<'a>,
  79      },
  80      ChannelOpenConfirmation {
  81          recipient_channel: u32,
  82          sender_channel: u32,
  83          initial_window_size: u32,
  84          maximum_packet_size: u32,
  85          payload: &'a [u8],
  86      },
  87      ChannelOpenFailure {
  88          recipient_channel: u32,
  89          reason: ChannelOpenFailureReason,
  90      },
  91      ChannelWindowAdjust {
  92          recipient_channel: u32,
  93          bytes_to_add: u32,
  94      },
  95      ChannelData {
  96          recipient_channel: u32,
  97          data: Data<'a>,
  98      },
  99      ChannelExtendedData {
 100          recipient_channel: u32,
 101          data: ExtendedData<'a>,
 102      },
 103      ChannelEof {
 104          recipient_channel: u32,
 105      },
 106      ChannelClose {
 107          recipient_channel: u32,
 108      },
 109      ChannelRequest {
 110          recipient_channel: u32,
 111          request: Request<'a>,
 112      },
 113      ChannelSuccess {
 114          recipient_channel: u32,
 115      },
 116      ChannelFailure {
 117          recipient_channel: u32,
 118      },
 119      Unknown {
 120          message: u8,
 121          payload: &'a [u8],
 122      },
 123  }
 124  
 125  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 126  pub enum ChannelType<'a> {
 127      Session {
 128          sender_channel: u32,
 129          initial_window_size: u32,
 130          maximum_packet_size: u32,
 131      },
 132      Other {
 133          channel_type: &'a str,
 134          sender_channel: u32,
 135          initial_window_size: u32,
 136          maximum_packet_size: u32,
 137          payload: &'a [u8],
 138      },
 139  }
 140  
 141  impl<'a> ChannelType<'a> {
 142      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 143          let decoded = match reader.read_string_utf8()? {
 144              "session" => Self::Session {
 145                  sender_channel: reader.read_uint32()?,
 146                  initial_window_size: reader.read_uint32()?,
 147                  maximum_packet_size: reader.read_uint32()?,
 148              },
 149              channel_type => Self::Other {
 150                  channel_type,
 151                  sender_channel: reader.read_uint32()?,
 152                  initial_window_size: reader.read_uint32()?,
 153                  maximum_packet_size: reader.read_uint32()?,
 154                  payload: reader.read_remaining(),
 155              },
 156          };
 157  
 158          Ok(decoded)
 159      }
 160  
 161      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 162          match self {
 163              Self::Session {
 164                  sender_channel,
 165                  initial_window_size,
 166                  maximum_packet_size,
 167              } => {
 168                  writer.write_string_utf8("session")?;
 169                  writer.write_uint32(sender_channel)?;
 170                  writer.write_uint32(initial_window_size)?;
 171                  writer.write_uint32(maximum_packet_size)?;
 172              }
 173              Self::Other {
 174                  channel_type,
 175                  sender_channel,
 176                  initial_window_size,
 177                  maximum_packet_size,
 178                  payload,
 179              } => {
 180                  writer.write_string_utf8(channel_type)?;
 181                  writer.write_uint32(sender_channel)?;
 182                  writer.write_uint32(initial_window_size)?;
 183                  writer.write_uint32(maximum_packet_size)?;
 184                  writer.write_byte_array(payload)?;
 185              }
 186          }
 187  
 188          Ok(())
 189      }
 190  }
 191  
 192  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 193  pub enum Request<'a> {
 194      Env {
 195          want_reply: bool,
 196          variable_name: &'a str,
 197          variable_value: &'a str,
 198      },
 199      Shell {
 200          want_reply: bool,
 201      },
 202      Exec {
 203          want_reply: bool,
 204          command: &'a str,
 205      },
 206      ExitStatus {
 207          want_reply: bool,
 208          exit_status: u32,
 209      },
 210      PtyReq {
 211          want_reply: bool,
 212          term: &'a str,
 213          width_chars: u32,
 214          height_rows: u32,
 215          width_pixels: u32,
 216          height_pixels: u32,
 217      },
 218      Other {
 219          request_type: &'a str,
 220          want_reply: bool,
 221          payload: &'a [u8],
 222      },
 223  }
 224  
 225  impl<'a> Request<'a> {
 226      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 227          let decoded = match reader.read_string_utf8()? {
 228              "env" => Self::Env {
 229                  want_reply: reader.read_boolean()?,
 230                  variable_name: reader.read_string_utf8()?,
 231                  variable_value: reader.read_string_utf8()?,
 232              },
 233              "shell" => Self::Shell {
 234                  want_reply: reader.read_boolean()?,
 235              },
 236              "exec" => Self::Exec {
 237                  want_reply: reader.read_boolean()?,
 238                  command: reader.read_string_utf8()?,
 239              },
 240              "exit-status" => Self::ExitStatus {
 241                  want_reply: reader.read_boolean()?,
 242                  exit_status: reader.read_uint32()?,
 243              },
 244              "pty-req" => {
 245                  let want_reply = reader.read_boolean()?;
 246                  let term = reader.read_string_utf8()?;
 247                  let width_chars = reader.read_uint32()?;
 248                  let height_rows = reader.read_uint32()?;
 249                  let width_pixels = reader.read_uint32()?;
 250                  let height_pixels = reader.read_uint32()?;
 251                  // Consume remaining bytes (encoded terminal modes)
 252                  let _ = reader.read_remaining();
 253                  Self::PtyReq { want_reply, term, width_chars, height_rows, width_pixels, height_pixels }
 254              }
 255              request_type => Self::Other {
 256                  request_type,
 257                  want_reply: reader.read_boolean()?,
 258                  payload: reader.read_remaining(),
 259              },
 260          };
 261  
 262          Ok(decoded)
 263      }
 264  
 265      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 266          match self {
 267              Self::Env {
 268                  want_reply,
 269                  variable_name,
 270                  variable_value,
 271              } => {
 272                  writer.write_string_utf8("env")?;
 273                  writer.write_boolean(want_reply)?;
 274                  writer.write_string_utf8(variable_name)?;
 275                  writer.write_string_utf8(variable_value)?;
 276              }
 277              Self::Shell { want_reply } => {
 278                  writer.write_string_utf8("shell")?;
 279                  writer.write_boolean(want_reply)?;
 280              }
 281              Self::Exec {
 282                  want_reply,
 283                  command,
 284              } => {
 285                  writer.write_string_utf8("exec")?;
 286                  writer.write_boolean(want_reply)?;
 287                  writer.write_string_utf8(command)?;
 288              }
 289              Self::ExitStatus {
 290                  want_reply,
 291                  exit_status,
 292              } => {
 293                  writer.write_string_utf8("exit-status")?;
 294                  writer.write_boolean(want_reply)?;
 295                  writer.write_uint32(exit_status)?;
 296              }
 297              Self::PtyReq {
 298                  want_reply,
 299                  term,
 300                  width_chars,
 301                  height_rows,
 302                  width_pixels,
 303                  height_pixels,
 304              } => {
 305                  writer.write_string_utf8("pty-req")?;
 306                  writer.write_boolean(want_reply)?;
 307                  writer.write_string_utf8(term)?;
 308                  writer.write_uint32(width_chars)?;
 309                  writer.write_uint32(height_rows)?;
 310                  writer.write_uint32(width_pixels)?;
 311                  writer.write_uint32(height_pixels)?;
 312              }
 313              Self::Other {
 314                  request_type,
 315                  want_reply,
 316                  payload,
 317              } => {
 318                  writer.write_string_utf8(request_type)?;
 319                  writer.write_boolean(want_reply)?;
 320                  writer.write_byte_array(payload)?;
 321              }
 322          }
 323  
 324          Ok(())
 325      }
 326  
 327      pub fn want_reply(self) -> bool {
 328          match self {
 329              Self::Env { want_reply, .. } => want_reply,
 330              Self::Shell { want_reply } => want_reply,
 331              Self::Exec { want_reply, .. } => want_reply,
 332              Self::ExitStatus { want_reply, .. } => want_reply,
 333              Self::PtyReq { want_reply, .. } => want_reply,
 334              Self::Other { want_reply, .. } => want_reply,
 335          }
 336      }
 337  }
 338  
 339  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 340  pub enum Data<'a> {
 341      Borrowed { bytes: &'a [u8] },
 342      InPlace { len: u32 },
 343  }
 344  
 345  impl<'a> Data<'a> {
 346      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 347          let decoded = Self::Borrowed {
 348              bytes: reader.read_string()?,
 349          };
 350  
 351          Ok(decoded)
 352      }
 353  
 354      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 355          match self {
 356              Self::Borrowed { bytes } => {
 357                  writer.write_string(bytes)?;
 358              }
 359              Self::InPlace { len } => {
 360                  writer.write_string_len(len)?;
 361                  writer.skip(from_u32(len))?;
 362              }
 363          }
 364  
 365          Ok(())
 366      }
 367  }
 368  
 369  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 370  pub enum ExtendedData<'a> {
 371      Stderr { data: Data<'a> },
 372      Other { data_type_code: u32, data: Data<'a> },
 373  }
 374  
 375  impl<'a> ExtendedData<'a> {
 376      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 377          let decoded = match reader.read_uint32()? {
 378              1 => Self::Stderr {
 379                  data: Data::decode_with(reader)?,
 380              },
 381              data_type_code => Self::Other {
 382                  data_type_code,
 383                  data: Data::decode_with(reader)?,
 384              },
 385          };
 386  
 387          Ok(decoded)
 388      }
 389  
 390      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 391          match self {
 392              Self::Stderr { data } => {
 393                  writer.write_uint32(1)?;
 394                  data.encode_with(writer)?;
 395              }
 396              Self::Other {
 397                  data_type_code,
 398                  data,
 399              } => {
 400                  writer.write_uint32(data_type_code)?;
 401                  data.encode_with(writer)?;
 402              }
 403          }
 404  
 405          Ok(())
 406      }
 407  }
 408  
 409  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 410  pub enum AuthMethod<'a> {
 411      PublicKey {
 412          public_key_algorithm_name: &'a str,
 413          public_key: PublicKey<'a>,
 414          signature: Option<Signature<'a>>,
 415      },
 416      Unsupported {
 417          method_name: &'a str,
 418          payload: &'a [u8],
 419      },
 420      None,
 421  }
 422  
 423  impl<'a> AuthMethod<'a> {
 424      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 425          let decoded = match reader.read_string_utf8()? {
 426              "publickey" => {
 427                  let has_signature = reader.read_boolean()?;
 428  
 429                  let public_key_algorithm_name = reader.read_string_utf8()?;
 430                  let public_key = PublicKey::decode_with(reader)?;
 431  
 432                  let signature = if has_signature {
 433                      Some(Signature::decode_with(reader)?)
 434                  } else {
 435                      None
 436                  };
 437  
 438                  AuthMethod::PublicKey {
 439                      public_key_algorithm_name,
 440                      public_key,
 441                      signature,
 442                  }
 443              }
 444              "none" => AuthMethod::None,
 445              method_name => AuthMethod::Unsupported {
 446                  method_name,
 447                  payload: reader.read_remaining(),
 448              },
 449          };
 450  
 451          Ok(decoded)
 452      }
 453  
 454      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 455          match self {
 456              AuthMethod::PublicKey {
 457                  public_key_algorithm_name,
 458                  public_key,
 459                  signature,
 460              } => {
 461                  writer.write_string_utf8("publickey")?;
 462                  writer.write_boolean(signature.is_some())?;
 463                  writer.write_string_utf8(public_key_algorithm_name)?;
 464                  public_key.encode_with(writer)?;
 465  
 466                  if let Some(signature) = signature {
 467                      signature.encode_with(writer)?;
 468                  }
 469              }
 470              AuthMethod::Unsupported {
 471                  method_name,
 472                  payload,
 473              } => {
 474                  writer.write_string_utf8(method_name)?;
 475                  writer.write_string(payload)?;
 476              }
 477              AuthMethod::None => {
 478                  writer.write_string_utf8("none")?;
 479              }
 480          }
 481  
 482          Ok(())
 483      }
 484  }
 485  
 486  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 487  pub enum PublicKey<'a> {
 488      Ed25519 {
 489          public_key: &'a [u8; 32],
 490      },
 491      Other {
 492          identifier: &'a str,
 493          payload: &'a [u8],
 494      },
 495  }
 496  
 497  impl<'a> PublicKey<'a> {
 498      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 499          let mut reader = ObjectReader::new(reader.read_string()?);
 500  
 501          let decoded = match reader.read_string_utf8()? {
 502              "ssh-ed25519" => Self::Ed25519 {
 503                  public_key: reader.read_string_fixed::<32>()?,
 504              },
 505              identifier => Self::Other {
 506                  identifier,
 507                  payload: reader.read_remaining(),
 508              },
 509          };
 510  
 511          if reader.read_remaining().is_empty() {
 512              Ok(decoded)
 513          } else {
 514              Err(ProtocolError::TrailingPayload)
 515          }
 516      }
 517  
 518      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 519          writer.write_nested(|writer| {
 520              match self {
 521                  Self::Ed25519 { public_key } => {
 522                      writer.write_string_utf8("ssh-ed25519")?;
 523                      writer.write_string(public_key)?;
 524                  }
 525                  Self::Other {
 526                      identifier,
 527                      payload,
 528                  } => {
 529                      writer.write_string_utf8(identifier)?;
 530                      writer.write_string(payload)?;
 531                  }
 532              }
 533  
 534              Ok(())
 535          })
 536      }
 537  }
 538  
 539  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 540  pub enum Signature<'a> {
 541      Ed25519 {
 542          signature: &'a [u8; 64],
 543      },
 544      Other {
 545          identifier: &'a str,
 546          payload: &'a [u8],
 547      },
 548  }
 549  
 550  impl<'a> Signature<'a> {
 551      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 552          let mut reader = ObjectReader::new(reader.read_string()?);
 553  
 554          let decoded = match reader.read_string_utf8()? {
 555              "ssh-ed25519" => Self::Ed25519 {
 556                  signature: reader.read_string_fixed::<64>()?,
 557              },
 558              identifier => Self::Other {
 559                  identifier,
 560                  payload: reader.read_remaining(),
 561              },
 562          };
 563  
 564          if reader.read_remaining().is_empty() {
 565              Ok(decoded)
 566          } else {
 567              Err(ProtocolError::TrailingPayload)
 568          }
 569      }
 570  
 571      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 572          writer.write_nested(|writer| {
 573              match self {
 574                  Self::Ed25519 { signature } => {
 575                      writer.write_string_utf8("ssh-ed25519")?;
 576                      writer.write_string(signature)?;
 577                  }
 578                  Self::Other {
 579                      identifier,
 580                      payload,
 581                  } => {
 582                      writer.write_string_utf8(identifier)?;
 583                      writer.write_string(payload)?;
 584                  }
 585              }
 586  
 587              Ok(())
 588          })
 589      }
 590  }
 591  
 592  #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
 593  pub struct NameList<'a> {
 594      string: &'a str,
 595  }
 596  
 597  impl<'a> NameList<'a> {
 598      pub fn new_from_string(string: &'a str) -> Result<Self, ProtocolError> {
 599          if !string.is_ascii() {
 600              return Err(ProtocolError::BadStringEncoding);
 601          }
 602  
 603          if string
 604              .as_bytes()
 605              .windows(2)
 606              .any(|window| window == [b','; 2])
 607          {
 608              Err(ProtocolError::BadNameList)
 609          } else {
 610              Ok(Self { string })
 611          }
 612      }
 613  
 614      pub fn is_empty(&self) -> bool {
 615          self.string.is_empty()
 616      }
 617  
 618      pub fn iter(&self) -> impl Iterator<Item = &str> {
 619          self.string.split(',')
 620      }
 621  
 622      pub fn as_str(&self) -> &'a str {
 623          self.string
 624      }
 625  
 626      pub fn find(&self, name: &str) -> Option<usize> {
 627          self.iter().position(|item| item == name)
 628      }
 629  
 630      pub fn decode_with(reader: &mut ObjectReader<'a>) -> Result<Self, ProtocolError> {
 631          Self::new_from_string(reader.read_string_utf8()?)
 632      }
 633  }
 634  
 635  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 636  pub enum ChannelOpenFailureReason {
 637      AdministrativelyProhibited,
 638      ConnectFailed,
 639      UnknownChannelType,
 640      ResourceShortage,
 641      Other(u32),
 642  }
 643  
 644  impl ChannelOpenFailureReason {
 645      pub fn decode_with(reader: &mut ObjectReader) -> Result<Self, ProtocolError> {
 646          let reason_code = reader.read_uint32()?;
 647          let _description = reader.read_string_utf8()?;
 648          let _language_tag = reader.read_string_utf8()?;
 649  
 650          Ok(Self::from_reason_code(reason_code))
 651      }
 652  
 653      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 654          writer.write_uint32(self.into_reason_code())?;
 655          writer.write_string_utf8(self.description())?;
 656          writer.write_string_utf8("en-US")?;
 657  
 658          Ok(())
 659      }
 660  
 661      pub fn into_reason_code(self) -> u32 {
 662          match self {
 663              Self::AdministrativelyProhibited => 1,
 664              Self::ConnectFailed => 2,
 665              Self::UnknownChannelType => 3,
 666              Self::ResourceShortage => 4,
 667              Self::Other(reason_code) => reason_code,
 668          }
 669      }
 670  
 671      pub fn from_reason_code(reason_code: u32) -> Self {
 672          match reason_code {
 673              1 => Self::AdministrativelyProhibited,
 674              2 => Self::ConnectFailed,
 675              3 => Self::UnknownChannelType,
 676              4 => Self::ResourceShortage,
 677              _ => Self::Other(reason_code),
 678          }
 679      }
 680  
 681      pub fn description(self) -> &'static str {
 682          match self {
 683              Self::AdministrativelyProhibited => "Administratively prohibited",
 684              Self::ConnectFailed => "Connect failed",
 685              Self::UnknownChannelType => "Unknown channel type",
 686              Self::ResourceShortage => "Resource shortage",
 687              Self::Other(_) => "No description available",
 688          }
 689      }
 690  }
 691  
 692  /// Set of possible disconnection reasons.
 693  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 694  pub enum DisconnectReason {
 695      /// Standard RFC4253 disconnect reason.
 696      HostNotAllowedToConnect,
 697      /// Standard RFC4253 disconnect reason.
 698      ProtocolError,
 699      /// Standard RFC4253 disconnect reason.
 700      KeyExchangeFailed,
 701      /// Standard RFC4253 disconnect reason.
 702      Reserved,
 703      /// Standard RFC4253 disconnect reason.
 704      MacError,
 705      /// Standard RFC4253 disconnect reason.
 706      CompressionError,
 707      /// Standard RFC4253 disconnect reason.
 708      ServiceNotAvailable,
 709      /// Standard RFC4253 disconnect reason.
 710      ProtocolVersionNotSupported,
 711      /// Standard RFC4253 disconnect reason.
 712      HostKeyNotVerifiable,
 713      /// Standard RFC4253 disconnect reason.
 714      ConnectionLost,
 715      /// Standard RFC4253 disconnect reason.
 716      ByApplication,
 717      /// Standard RFC4253 disconnect reason.
 718      TooManyConnections,
 719      /// Standard RFC4253 disconnect reason.
 720      AuthCancelledByUser,
 721      /// Standard RFC4253 disconnect reason.
 722      NoMoreAuthMethodsAvailable,
 723      /// Standard RFC4253 disconnect reason.
 724      IllegalUserName,
 725      /// Some other disconnect reason.
 726      Other(u32),
 727  }
 728  
 729  impl DisconnectReason {
 730      /// Decodes an instance of this type from an object reader.
 731      pub fn decode_with(reader: &mut ObjectReader) -> Result<Self, ProtocolError> {
 732          let reason_code = reader.read_uint32()?;
 733          let _description = reader.read_string_utf8()?;
 734          let _language_tag = reader.read_string_utf8()?;
 735  
 736          Ok(Self::from_reason_code(reason_code))
 737      }
 738  
 739      /// Encodes this instance into an object writer.
 740      pub fn encode_with(self, writer: &mut ObjectWriter) -> Result<(), ProtocolError> {
 741          writer.write_uint32(self.into_reason_code())?;
 742          writer.write_string_utf8(self.description())?;
 743          writer.write_string_utf8("en-US")?;
 744  
 745          Ok(())
 746      }
 747  
 748      /// Retrieves the underlying reason code.
 749      pub fn into_reason_code(self) -> u32 {
 750          match self {
 751              Self::HostNotAllowedToConnect => 1,
 752              Self::ProtocolError => 2,
 753              Self::KeyExchangeFailed => 3,
 754              Self::Reserved => 4,
 755              Self::MacError => 5,
 756              Self::CompressionError => 6,
 757              Self::ServiceNotAvailable => 7,
 758              Self::ProtocolVersionNotSupported => 8,
 759              Self::HostKeyNotVerifiable => 9,
 760              Self::ConnectionLost => 10,
 761              Self::ByApplication => 11,
 762              Self::TooManyConnections => 12,
 763              Self::AuthCancelledByUser => 13,
 764              Self::NoMoreAuthMethodsAvailable => 14,
 765              Self::IllegalUserName => 15,
 766              Self::Other(reason_code) => reason_code,
 767          }
 768      }
 769  
 770      /// Constructs an instance of this type from a reason code.
 771      pub fn from_reason_code(reason_code: u32) -> Self {
 772          match reason_code {
 773              1 => Self::HostNotAllowedToConnect,
 774              2 => Self::ProtocolError,
 775              3 => Self::KeyExchangeFailed,
 776              4 => Self::Reserved,
 777              5 => Self::MacError,
 778              6 => Self::CompressionError,
 779              7 => Self::ServiceNotAvailable,
 780              8 => Self::ProtocolVersionNotSupported,
 781              9 => Self::HostKeyNotVerifiable,
 782              10 => Self::ConnectionLost,
 783              11 => Self::ByApplication,
 784              12 => Self::TooManyConnections,
 785              13 => Self::AuthCancelledByUser,
 786              14 => Self::NoMoreAuthMethodsAvailable,
 787              15 => Self::IllegalUserName,
 788              _ => Self::Other(reason_code),
 789          }
 790      }
 791  
 792      /// Retrieves a description message for this disconnect reason instance.
 793      pub fn description(self) -> &'static str {
 794          match self {
 795              Self::HostNotAllowedToConnect => "Host not allowed to connect",
 796              Self::ProtocolError => "Protocol error",
 797              Self::KeyExchangeFailed => "Key exchange failed",
 798              Self::Reserved => "Reserved",
 799              Self::MacError => "MAC error",
 800              Self::CompressionError => "Compression error",
 801              Self::ServiceNotAvailable => "Service not available",
 802              Self::ProtocolVersionNotSupported => "Protocol version not supported",
 803              Self::HostKeyNotVerifiable => "Host key not verifiable",
 804              Self::ConnectionLost => "Connection lost",
 805              Self::ByApplication => "By application",
 806              Self::TooManyConnections => "Too many connections",
 807              Self::AuthCancelledByUser => "Auth cancelled by user",
 808              Self::NoMoreAuthMethodsAvailable => "No more auth methods available",
 809              Self::IllegalUserName => "Illegal user name",
 810              Self::Other(_) => "No description available",
 811          }
 812      }
 813  }
 814  
 815  pub const MSG_SERVICE_REQUEST: u8 = 5;
 816  pub const MSG_SERVICE_ACCEPT: u8 = 6;
 817  pub const MSG_DISCONNECT: u8 = 1;
 818  pub const MSG_IGNORE: u8 = 2;
 819  pub const MSG_DEBUG: u8 = 4;
 820  pub const MSG_UNIMPLEMENTED: u8 = 3;
 821  pub const MSG_KEX_INIT: u8 = 20;
 822  pub const MSG_NEW_KEYS: u8 = 21;
 823  pub const MSG_KEX_ECDH_INIT: u8 = 30;
 824  pub const MSG_KEX_ECDH_REPLY: u8 = 31;
 825  pub const MSG_USERAUTH_REQUEST: u8 = 50;
 826  pub const MSG_USERAUTH_FAILURE: u8 = 51;
 827  pub const MSG_USERAUTH_SUCCESS: u8 = 52;
 828  pub const MSG_USERAUTH_BANNER: u8 = 53;
 829  pub const MSG_USERAUTH_PK_OK: u8 = 60;
 830  pub const MSG_GLOBAL_REQUEST: u8 = 80;
 831  pub const MSG_REQUEST_SUCCESS: u8 = 81;
 832  pub const MSG_REQUEST_FAILURE: u8 = 82;
 833  pub const MSG_CHANNEL_OPEN: u8 = 90;
 834  pub const MSG_CHANNEL_OPEN_CONFIRMATION: u8 = 91;
 835  pub const MSG_CHANNEL_OPEN_FAILURE: u8 = 92;
 836  pub const MSG_CHANNEL_WINDOW_ADJUST: u8 = 93;
 837  pub const MSG_CHANNEL_DATA: u8 = 94;
 838  pub const MSG_CHANNEL_EXTENDED_DATA: u8 = 95;
 839  pub const MSG_CHANNEL_EOF: u8 = 96;
 840  pub const MSG_CHANNEL_CLOSE: u8 = 97;
 841  pub const MSG_CHANNEL_REQUEST: u8 = 98;
 842  pub const MSG_CHANNEL_SUCCESS: u8 = 99;
 843  pub const MSG_CHANNEL_FAILURE: u8 = 100;
 844  
 845  impl<'a> Message<'a> {
 846      pub fn decode(buffer: &'a [u8]) -> Result<Self, ProtocolError> {
 847          let mut reader = ObjectReader::new(buffer);
 848  
 849          let decoded = match reader.read_byte()? {
 850              MSG_SERVICE_REQUEST => Self::ServiceRequest {
 851                  service_name: reader.read_internal_name()?,
 852              },
 853              MSG_SERVICE_ACCEPT => Self::ServiceAccept {
 854                  service_name: reader.read_internal_name()?,
 855              },
 856              MSG_DISCONNECT => Self::Disconnect {
 857                  reason: DisconnectReason::decode_with(&mut reader)?,
 858              },
 859              MSG_IGNORE => Self::Ignore {
 860                  data: reader.read_string()?,
 861              },
 862              MSG_DEBUG => Self::Debug {
 863                  always_display: reader.read_boolean()?,
 864                  message: reader.read_string_utf8()?,
 865                  language_tag: reader.read_string_utf8()?,
 866              },
 867              MSG_UNIMPLEMENTED => Self::Unimplemented {
 868                  sequence_number: reader.read_uint32()?,
 869              },
 870              MSG_NEW_KEYS => Self::NewKeys,
 871              MSG_KEX_INIT => Self::KexInit {
 872                  cookie: reader.read_byte_array::<16>()?,
 873                  kex_algorithms: NameList::decode_with(&mut reader)?,
 874                  server_host_key_algorithms: NameList::decode_with(&mut reader)?,
 875                  encryption_algorithms_client_to_server: NameList::decode_with(&mut reader)?,
 876                  encryption_algorithms_server_to_client: NameList::decode_with(&mut reader)?,
 877                  mac_algorithms_client_to_server: NameList::decode_with(&mut reader)?,
 878                  mac_algorithms_server_to_client: NameList::decode_with(&mut reader)?,
 879                  compression_algorithms_client_to_server: NameList::decode_with(&mut reader)?,
 880                  compression_algorithms_server_to_client: NameList::decode_with(&mut reader)?,
 881                  languages_client_to_server: NameList::decode_with(&mut reader)?,
 882                  languages_server_to_client: NameList::decode_with(&mut reader)?,
 883                  first_kex_packet_follows: reader.read_boolean()?,
 884                  reserved: reader.read_uint32()?,
 885              },
 886              MSG_KEX_ECDH_INIT => Self::KexEcdhInit {
 887                  client_ephemeral_public_key: reader.read_string()?,
 888              },
 889              MSG_KEX_ECDH_REPLY => Self::KexEcdhReply {
 890                  server_public_host_key: PublicKey::decode_with(&mut reader)?,
 891                  server_ephemeral_public_key: reader.read_string()?,
 892                  signature: Signature::decode_with(&mut reader)?,
 893              },
 894              MSG_USERAUTH_REQUEST => Self::UserAuthRequest {
 895                  user_name: reader.read_string_utf8()?,
 896                  service_name: reader.read_string_utf8()?,
 897                  auth_method: AuthMethod::decode_with(&mut reader)?,
 898              },
 899              MSG_USERAUTH_FAILURE => Self::UserAuthFailure {
 900                  authentications_that_can_continue: NameList::decode_with(&mut reader)?,
 901                  partial_success: reader.read_boolean()?,
 902              },
 903              MSG_USERAUTH_SUCCESS => Self::UserAuthSuccess,
 904              MSG_USERAUTH_BANNER => Self::UserAuthBanner {
 905                  message: reader.read_string_utf8()?,
 906                  language: reader.read_string_utf8()?,
 907              },
 908              MSG_USERAUTH_PK_OK => Self::UserAuthPkOk {
 909                  public_key_algorithm_name: reader.read_string_utf8()?,
 910                  public_key: PublicKey::decode_with(&mut reader)?,
 911              },
 912              MSG_GLOBAL_REQUEST => Self::GlobalRequest {
 913                  request_name: reader.read_string_utf8()?,
 914                  want_reply: reader.read_boolean()?,
 915                  payload: reader.read_remaining(),
 916              },
 917              MSG_REQUEST_SUCCESS => Self::RequestSuccess {
 918                  payload: reader.read_remaining(),
 919              },
 920              MSG_REQUEST_FAILURE => Self::RequestFailure,
 921              MSG_CHANNEL_OPEN => Self::ChannelOpen {
 922                  channel: ChannelType::decode_with(&mut reader)?,
 923              },
 924              MSG_CHANNEL_OPEN_CONFIRMATION => Self::ChannelOpenConfirmation {
 925                  recipient_channel: reader.read_uint32()?,
 926                  sender_channel: reader.read_uint32()?,
 927                  initial_window_size: reader.read_uint32()?,
 928                  maximum_packet_size: reader.read_uint32()?,
 929                  payload: reader.read_remaining(),
 930              },
 931              MSG_CHANNEL_OPEN_FAILURE => Self::ChannelOpenFailure {
 932                  recipient_channel: reader.read_uint32()?,
 933                  reason: ChannelOpenFailureReason::decode_with(&mut reader)?,
 934              },
 935              MSG_CHANNEL_WINDOW_ADJUST => Self::ChannelWindowAdjust {
 936                  recipient_channel: reader.read_uint32()?,
 937                  bytes_to_add: reader.read_uint32()?,
 938              },
 939              MSG_CHANNEL_DATA => Self::ChannelData {
 940                  recipient_channel: reader.read_uint32()?,
 941                  data: Data::decode_with(&mut reader)?,
 942              },
 943              MSG_CHANNEL_EXTENDED_DATA => Self::ChannelExtendedData {
 944                  recipient_channel: reader.read_uint32()?,
 945                  data: ExtendedData::decode_with(&mut reader)?,
 946              },
 947              MSG_CHANNEL_EOF => Self::ChannelEof {
 948                  recipient_channel: reader.read_uint32()?,
 949              },
 950              MSG_CHANNEL_CLOSE => Self::ChannelClose {
 951                  recipient_channel: reader.read_uint32()?,
 952              },
 953              MSG_CHANNEL_REQUEST => Self::ChannelRequest {
 954                  recipient_channel: reader.read_uint32()?,
 955                  request: Request::decode_with(&mut reader)?,
 956              },
 957              MSG_CHANNEL_SUCCESS => Self::ChannelSuccess {
 958                  recipient_channel: reader.read_uint32()?,
 959              },
 960              MSG_CHANNEL_FAILURE => Self::ChannelFailure {
 961                  recipient_channel: reader.read_uint32()?,
 962              },
 963              unknown_message => Self::Unknown {
 964                  message: unknown_message,
 965                  payload: reader.read_remaining(),
 966              },
 967          };
 968  
 969          if reader.read_remaining().is_empty() {
 970              Ok(decoded)
 971          } else {
 972              Err(ProtocolError::TrailingPayload)
 973          }
 974      }
 975  
 976      pub fn encode(self, buffer: &mut [u8]) -> Result<&[u8], ProtocolError> {
 977          let mut writer = ObjectWriter::new(buffer);
 978  
 979          match self {
 980              Self::Ignore { data } => {
 981                  writer.write_byte(MSG_IGNORE)?;
 982                  writer.write_string(data)?;
 983              }
 984              Self::Debug {
 985                  always_display,
 986                  message,
 987                  language_tag,
 988              } => {
 989                  writer.write_byte(MSG_DEBUG)?;
 990                  writer.write_boolean(always_display)?;
 991                  writer.write_string_utf8(message)?;
 992                  writer.write_string_utf8(language_tag)?;
 993              }
 994              Self::KexInit {
 995                  cookie,
 996                  kex_algorithms,
 997                  server_host_key_algorithms,
 998                  encryption_algorithms_client_to_server,
 999                  encryption_algorithms_server_to_client,
1000                  mac_algorithms_client_to_server,
1001                  mac_algorithms_server_to_client,
1002                  compression_algorithms_client_to_server,
1003                  compression_algorithms_server_to_client,
1004                  languages_client_to_server,
1005                  languages_server_to_client,
1006                  first_kex_packet_follows,
1007                  reserved,
1008              } => {
1009                  writer.write_byte(MSG_KEX_INIT)?;
1010                  writer.write_byte_array(cookie)?;
1011                  writer.write_name_list(kex_algorithms)?;
1012                  writer.write_name_list(server_host_key_algorithms)?;
1013                  writer.write_name_list(encryption_algorithms_client_to_server)?;
1014                  writer.write_name_list(encryption_algorithms_server_to_client)?;
1015                  writer.write_name_list(mac_algorithms_client_to_server)?;
1016                  writer.write_name_list(mac_algorithms_server_to_client)?;
1017                  writer.write_name_list(compression_algorithms_client_to_server)?;
1018                  writer.write_name_list(compression_algorithms_server_to_client)?;
1019                  writer.write_name_list(languages_client_to_server)?;
1020                  writer.write_name_list(languages_server_to_client)?;
1021                  writer.write_boolean(first_kex_packet_follows)?;
1022                  writer.write_uint32(reserved)?;
1023              }
1024              Self::Unimplemented { sequence_number } => {
1025                  writer.write_byte(MSG_UNIMPLEMENTED)?;
1026                  writer.write_uint32(sequence_number)?;
1027              }
1028              Self::KexEcdhInit {
1029                  client_ephemeral_public_key,
1030              } => {
1031                  writer.write_byte(MSG_KEX_ECDH_INIT)?;
1032                  writer.write_string(client_ephemeral_public_key)?;
1033              }
1034              Self::KexEcdhReply {
1035                  server_public_host_key,
1036                  server_ephemeral_public_key,
1037                  signature,
1038              } => {
1039                  writer.write_byte(MSG_KEX_ECDH_REPLY)?;
1040                  server_public_host_key.encode_with(&mut writer)?;
1041                  writer.write_string(server_ephemeral_public_key)?;
1042                  signature.encode_with(&mut writer)?;
1043              }
1044              Self::Disconnect { reason } => {
1045                  writer.write_byte(MSG_DISCONNECT)?;
1046                  reason.encode_with(&mut writer)?;
1047              }
1048              Self::NewKeys => {
1049                  writer.write_byte(MSG_NEW_KEYS)?;
1050              }
1051              Self::ServiceAccept { service_name } => {
1052                  writer.write_byte(MSG_SERVICE_ACCEPT)?;
1053                  writer.write_string_utf8(service_name)?;
1054              }
1055              Self::ServiceRequest { service_name } => {
1056                  writer.write_byte(MSG_SERVICE_REQUEST)?;
1057                  writer.write_string_utf8(service_name)?;
1058              }
1059              Self::UserAuthRequest {
1060                  user_name,
1061                  service_name,
1062                  auth_method,
1063              } => {
1064                  writer.write_byte(MSG_USERAUTH_SUCCESS)?;
1065                  writer.write_string_utf8(user_name)?;
1066                  writer.write_string_utf8(service_name)?;
1067                  auth_method.encode_with(&mut writer)?;
1068              }
1069              Self::UserAuthFailure {
1070                  authentications_that_can_continue,
1071                  partial_success,
1072              } => {
1073                  writer.write_byte(MSG_USERAUTH_FAILURE)?;
1074                  writer.write_name_list(authentications_that_can_continue)?;
1075                  writer.write_boolean(partial_success)?;
1076              }
1077              Self::UserAuthSuccess => {
1078                  writer.write_byte(MSG_USERAUTH_SUCCESS)?;
1079              }
1080              Self::UserAuthBanner { message, language } => {
1081                  writer.write_byte(MSG_USERAUTH_BANNER)?;
1082                  writer.write_string_utf8(message)?;
1083                  writer.write_string_utf8(language)?;
1084              }
1085              Self::UserAuthPkOk {
1086                  public_key_algorithm_name,
1087                  public_key,
1088              } => {
1089                  writer.write_byte(MSG_USERAUTH_PK_OK)?;
1090                  writer.write_string_utf8(public_key_algorithm_name)?;
1091                  public_key.encode_with(&mut writer)?;
1092              }
1093              Self::GlobalRequest {
1094                  request_name,
1095                  want_reply,
1096                  payload,
1097              } => {
1098                  writer.write_byte(MSG_GLOBAL_REQUEST)?;
1099                  writer.write_string_utf8(request_name)?;
1100                  writer.write_boolean(want_reply)?;
1101                  writer.write_string(payload)?;
1102              }
1103              Self::RequestSuccess { payload } => {
1104                  writer.write_byte(MSG_REQUEST_SUCCESS)?;
1105                  writer.write_string(payload)?;
1106              }
1107              Self::RequestFailure => {
1108                  writer.write_byte(MSG_REQUEST_FAILURE)?;
1109              }
1110              Self::ChannelOpen { channel } => {
1111                  writer.write_byte(MSG_CHANNEL_OPEN)?;
1112                  channel.encode_with(&mut writer)?;
1113              }
1114              Self::ChannelOpenConfirmation {
1115                  recipient_channel,
1116                  sender_channel,
1117                  initial_window_size,
1118                  maximum_packet_size,
1119                  payload,
1120              } => {
1121                  writer.write_byte(MSG_CHANNEL_OPEN_CONFIRMATION)?;
1122                  writer.write_uint32(recipient_channel)?;
1123                  writer.write_uint32(sender_channel)?;
1124                  writer.write_uint32(initial_window_size)?;
1125                  writer.write_uint32(maximum_packet_size)?;
1126                  writer.write_byte_array(payload)?;
1127              }
1128              Self::ChannelOpenFailure {
1129                  recipient_channel,
1130                  reason,
1131              } => {
1132                  writer.write_byte(MSG_CHANNEL_OPEN_FAILURE)?;
1133                  writer.write_uint32(recipient_channel)?;
1134                  reason.encode_with(&mut writer)?;
1135              }
1136              Self::ChannelWindowAdjust {
1137                  recipient_channel,
1138                  bytes_to_add,
1139              } => {
1140                  writer.write_byte(MSG_CHANNEL_WINDOW_ADJUST)?;
1141                  writer.write_uint32(recipient_channel)?;
1142                  writer.write_uint32(bytes_to_add)?;
1143              }
1144              Self::ChannelData {
1145                  recipient_channel,
1146                  data,
1147              } => {
1148                  writer.write_byte(MSG_CHANNEL_DATA)?;
1149                  writer.write_uint32(recipient_channel)?;
1150                  data.encode_with(&mut writer)?;
1151              }
1152              Self::ChannelExtendedData {
1153                  recipient_channel,
1154                  data,
1155              } => {
1156                  writer.write_byte(MSG_CHANNEL_EXTENDED_DATA)?;
1157                  writer.write_uint32(recipient_channel)?;
1158                  data.encode_with(&mut writer)?;
1159              }
1160              Self::ChannelEof { recipient_channel } => {
1161                  writer.write_byte(MSG_CHANNEL_EOF)?;
1162                  writer.write_uint32(recipient_channel)?;
1163              }
1164              Self::ChannelClose { recipient_channel } => {
1165                  writer.write_byte(MSG_CHANNEL_CLOSE)?;
1166                  writer.write_uint32(recipient_channel)?;
1167              }
1168              Self::ChannelRequest {
1169                  recipient_channel,
1170                  request,
1171              } => {
1172                  writer.write_byte(MSG_CHANNEL_REQUEST)?;
1173                  writer.write_uint32(recipient_channel)?;
1174                  request.encode_with(&mut writer)?;
1175              }
1176              Self::ChannelSuccess { recipient_channel } => {
1177                  writer.write_byte(MSG_CHANNEL_SUCCESS)?;
1178                  writer.write_uint32(recipient_channel)?;
1179              }
1180              Self::ChannelFailure { recipient_channel } => {
1181                  writer.write_byte(MSG_CHANNEL_FAILURE)?;
1182                  writer.write_uint32(recipient_channel)?;
1183              }
1184              Self::Unknown { .. } => unreachable!(),
1185          }
1186  
1187          Ok(writer.into_written())
1188      }
1189  }
1190  
1191  // The SSH protocol uses 32-bit integers for various size quantities; these conversion
1192  // utilities will convert them to/from usize while avoiding silent integer truncation.
1193  
1194  pub fn into_u32(value: usize) -> u32 {
1195      value.try_into().expect("failed to convert usize to u32")
1196  }
1197  
1198  pub fn from_u32(value: u32) -> usize {
1199      value.try_into().expect("failed to convert u32 to usize")
1200  }