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}