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