ssh_packet/
userauth.rs

1//! Messages involved in the SSH's **authentication** (`SSH-USERAUTH`) part of the protocol,
2//! as defined in the [RFC 4252](https://datatracker.ietf.org/doc/html/rfc4252) and [RFC 4256](https://datatracker.ietf.org/doc/html/rfc4256).
3
4use binrw::binrw;
5
6use crate::arch;
7
8/// The `SSH_MSG_USERAUTH_REQUEST` message.
9///
10/// see <https://datatracker.ietf.org/doc/html/rfc4252#section-5>.
11#[binrw]
12#[derive(Debug, Clone)]
13#[brw(big, magic = 50_u8)]
14pub struct Request<'b> {
15    /// Username for the auth request.
16    pub username: arch::Utf8<'b>,
17
18    /// Service name to query.
19    pub service_name: arch::Ascii<'b>,
20
21    #[bw(calc = method.as_ascii())]
22    auth_method: arch::Ascii<'b>,
23
24    /// Authentication method used.
25    #[br(args(auth_method))]
26    pub method: Method<'b>,
27}
28
29/// The authentication method in the `SSH_MSG_USERAUTH_REQUEST` message.
30#[binrw]
31#[derive(Debug, Clone)]
32#[br(import(method: arch::Ascii<'_>))]
33pub enum Method<'b> {
34    /// Authenticate using the `none` method,
35    /// as defined in [RFC4252 section 5.2](https://datatracker.ietf.org/doc/html/rfc4252#section-5.2).
36    #[br(pre_assert(method == Method::NONE))]
37    None,
38
39    /// Authenticate using the `publickey` method,
40    /// as defined in [RFC4252 section 7](https://datatracker.ietf.org/doc/html/rfc4252#section-7).
41    #[br(pre_assert(method == Method::PUBLICKEY))]
42    Publickey {
43        #[bw(calc = arch::Bool::from(signature.is_some()))]
44        signed: arch::Bool,
45
46        /// Public key algorithm's name.
47        algorithm: arch::Bytes<'b>,
48        /// Public key blob.
49        blob: arch::Bytes<'b>,
50
51        /// The optional signature of the authentication packet,
52        /// signed with the according private key.
53        #[br(if(*signed))]
54        signature: Option<arch::Bytes<'b>>,
55    },
56
57    /// Authenticate using the `password` method,
58    /// as defined in [RFC4252 section 8](https://datatracker.ietf.org/doc/html/rfc4252#section-8).
59    #[br(pre_assert(method == Method::PASSWORD))]
60    Password {
61        #[bw(calc = arch::Bool::from(new.is_some()))]
62        change: arch::Bool,
63
64        /// Plaintext password.
65        password: arch::Utf8<'b>,
66
67        /// In the case of a the receival of a [`PasswdChangereq`],
68        /// the new password to be set in place of the old one.
69        #[br(if(*change))]
70        new: Option<arch::Utf8<'b>>,
71    },
72
73    /// Authenticate using the `hostbased` method,
74    /// as defined in [RFC4252 section 9](https://datatracker.ietf.org/doc/html/rfc4252#section-9).
75    #[br(pre_assert(method == Method::HOSTBASED))]
76    Hostbased {
77        /// Public key algorithm for the host key.
78        algorithm: arch::Bytes<'b>,
79
80        /// Public host key and certificates for client host.
81        host_key: arch::Bytes<'b>,
82
83        /// Client host name expressed as the FQDN.
84        client_fqdn: arch::Ascii<'b>,
85
86        /// User name on the client host.
87        username: arch::Utf8<'b>,
88
89        /// The signature of the authentication packet.
90        signature: arch::Bytes<'b>,
91    },
92
93    /// Authenticate using the `keyboard-interactive` method,
94    /// as defined in [RFC4256 section 3.1](https://datatracker.ietf.org/doc/html/rfc4256#section-3.1).
95    #[br(pre_assert(method == Method::KEYBOARD_INTERACTIVE))]
96    KeyboardInteractive {
97        /// Language tag.
98        language: arch::Ascii<'b>,
99
100        /// A hint for the prefered interactive submethod.
101        submethods: arch::Utf8<'b>,
102    },
103}
104
105impl Method<'_> {
106    /// The SSH `none` authentication method.
107    pub const NONE: arch::Ascii<'static> = arch::ascii!("none");
108
109    /// The SSH `publickey` authentication method.
110    pub const PUBLICKEY: arch::Ascii<'static> = arch::ascii!("publickey");
111
112    /// The SSH `password` authentication method.
113    pub const PASSWORD: arch::Ascii<'static> = arch::ascii!("password");
114
115    /// The SSH `hostbased` authentication method.
116    pub const HOSTBASED: arch::Ascii<'static> = arch::ascii!("hostbased");
117
118    /// The SSH `keyboard-interactive` authentication method.
119    pub const KEYBOARD_INTERACTIVE: arch::Ascii<'static> = arch::ascii!("keyboard-interactive");
120
121    /// Get the [`Method`]'s SSH identifier.
122    pub fn as_ascii(&self) -> arch::Ascii<'static> {
123        match self {
124            Self::None { .. } => Self::NONE,
125            Self::Publickey { .. } => Self::PUBLICKEY,
126            Self::Password { .. } => Self::PASSWORD,
127            Self::Hostbased { .. } => Self::HOSTBASED,
128            Self::KeyboardInteractive { .. } => Self::KEYBOARD_INTERACTIVE,
129        }
130    }
131}
132
133/// The `SSH_MSG_USERAUTH_PK_OK` message.
134///
135/// see <https://datatracker.ietf.org/doc/html/rfc4252#section-7>.
136#[binrw]
137#[derive(Debug, Clone)]
138#[brw(big, magic = 60_u8)]
139pub struct PkOk<'b> {
140    /// Public key algorithm name from the request.
141    pub algorithm: arch::Bytes<'b>,
142
143    /// Public key blob from the request.
144    pub blob: arch::Bytes<'b>,
145}
146
147/// The `SSH_MSG_USERAUTH_PASSWD_CHANGEREQ` message.
148///
149/// see <https://datatracker.ietf.org/doc/html/rfc4252#section-8>.
150#[binrw]
151#[derive(Debug, Default, Clone)]
152#[brw(big, magic = 60_u8)]
153pub struct PasswdChangereq<'b> {
154    /// Password change prompt.
155    pub prompt: arch::Utf8<'b>,
156
157    /// Language tag (deprecated).
158    pub language: arch::Ascii<'b>,
159}
160
161/// The `SSH_MSG_USERAUTH_INFO_REQUEST` message.
162///
163/// see <https://datatracker.ietf.org/doc/html/rfc4256#section-3.2>.
164#[binrw]
165#[derive(Debug, Clone)]
166#[brw(big, magic = 60_u8)]
167pub struct InfoRequest<'b> {
168    /// Name of the challenge.
169    pub name: arch::Utf8<'b>,
170
171    /// Instructions for the challenge.
172    pub instruction: arch::Utf8<'b>,
173
174    /// Language tag (deprecated).
175    pub language: arch::Ascii<'b>,
176
177    #[bw(calc = prompts.len() as u32)]
178    num_prompts: u32,
179
180    /// The challenge's prompts.
181    #[br(count = num_prompts)]
182    pub prompts: Vec<InfoRequestPrompt<'static>>,
183}
184
185/// A prompt in the `SSH_MSG_USERAUTH_INFO_REQUEST` message.
186#[binrw]
187#[derive(Debug, Clone)]
188#[brw(big)]
189pub struct InfoRequestPrompt<'b> {
190    /// Challenge prompt text.
191    pub prompt: arch::Utf8<'b>,
192
193    /// Whether the client should echo back typed characters.
194    pub echo: arch::Bool,
195}
196
197/// The `SSH_MSG_USERAUTH_INFO_RESPONSE` message.
198///
199/// see <https://datatracker.ietf.org/doc/html/rfc4256#section-3.4>.
200#[binrw]
201#[derive(Debug, Clone)]
202#[brw(big, magic = 61_u8)]
203pub struct InfoResponse {
204    #[bw(calc = responses.len() as u32)]
205    num_responses: u32,
206
207    /// Responses to the provided challenge.
208    #[br(count = num_responses)]
209    pub responses: Vec<arch::Utf8<'static>>,
210}
211
212/// The `SSH_MSG_USERAUTH_FAILURE` message.
213///
214/// see <https://datatracker.ietf.org/doc/html/rfc4252#section-5.1>.
215#[binrw]
216#[derive(Debug, Default, Clone)]
217#[brw(big, magic = 51_u8)]
218pub struct Failure<'b> {
219    /// Authentications that can continue.
220    pub continue_with: arch::NameList<'b>,
221
222    /// Partial success.
223    pub partial_success: arch::Bool,
224}
225
226/// The `SSH_MSG_USERAUTH_SUCCESS` message.
227///
228/// see <https://datatracker.ietf.org/doc/html/rfc4252#section-5.1>.
229#[binrw]
230#[derive(Debug, Default, Clone)]
231#[brw(big, magic = 52_u8)]
232pub struct Success;
233
234/// The `SSH_MSG_USERAUTH_BANNER` message.
235///
236/// see <https://datatracker.ietf.org/doc/html/rfc4252#section-5.4>.
237#[binrw]
238#[derive(Debug, Default, Clone)]
239#[brw(big, magic = 53_u8)]
240pub struct Banner<'b> {
241    /// The auth banner message.
242    pub message: arch::Utf8<'b>,
243
244    /// Language tag.
245    pub language: arch::Ascii<'b>,
246}