1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 //! auth
16 #![allow(missing_docs)]
17
18 use hdc::config::{self, *};
19 use hdc::serializer::native_struct;
20 use hdc::serializer::serialize::Serialization;
21 use hdc::transfer;
22
23 use openssl::base64;
24 use openssl::rsa::{Padding, Rsa};
25 use ylong_runtime::sync::RwLock;
26
27 use super::sys_para::*;
28 use crate::utils::hdc_log::*;
29 use std::collections::HashMap;
30 use std::fs::File;
31 use std::io::{self, prelude::*, Error, ErrorKind, Write};
32 use std::path::Path;
33 use std::process::Command;
34 use std::string::ToString;
35 use std::sync::Arc;
36
37 #[derive(Clone, PartialEq, Eq)]
38 pub enum AuthStatus {
39 Init(String), // with plain
40 Pubk((String, String)), // with (plain, pk)
41 Ok,
42 Fail,
43 }
44
45 pub enum UserPermit {
46 Refuse = 0,
47 AllowOnce = 1,
48 AllowForever = 2,
49 }
50
51 type AuthStatusMap_ = Arc<RwLock<HashMap<u32, AuthStatus>>>;
52
53 pub struct AuthStatusMap {}
54 impl AuthStatusMap {
get_instance() -> AuthStatusMap_55 fn get_instance() -> AuthStatusMap_ {
56 static mut AUTH_STATUS_MAP: Option<AuthStatusMap_> = None;
57 unsafe {
58 AUTH_STATUS_MAP
59 .get_or_insert_with(|| Arc::new(RwLock::new(HashMap::new())))
60 .clone()
61 }
62 }
63
get(session_id: u32) -> AuthStatus64 pub async fn get(session_id: u32) -> AuthStatus {
65 let instance = Self::get_instance();
66 let map = instance.read().await;
67 map.get(&session_id).unwrap().clone()
68 }
69
put(session_id: u32, auth_status: AuthStatus)70 async fn put(session_id: u32, auth_status: AuthStatus) {
71 let instance = Self::get_instance();
72 let mut map = instance.write().await;
73 map.insert(session_id, auth_status);
74 }
75 }
76
handshake_init(task_message: TaskMessage) -> io::Result<(u32, TaskMessage)>77 pub async fn handshake_init(task_message: TaskMessage) -> io::Result<(u32, TaskMessage)> {
78 if task_message.command != HdcCommand::KernelHandshake {
79 return Err(Error::new(ErrorKind::Other, "unknown command flag"));
80 }
81
82 let mut recv = native_struct::SessionHandShake::default();
83 recv.parse(task_message.payload)?;
84
85 hdc::info!("recv handshake: {:#?}", recv);
86 if recv.banner != HANDSHAKE_MESSAGE {
87 return Err(Error::new(ErrorKind::Other, "Recv server-hello failed"));
88 }
89
90 hdc::info!(
91 "client version({}) for session:{}",
92 recv.version.as_str(),
93 recv.session_id
94 );
95 if recv.version.as_str() < "Ver: 2.0.0" {
96 hdc::info!(
97 "client version({}) is too low, return OK for session:{}",
98 recv.version.as_str(),
99 recv.session_id
100 );
101 return Ok((
102 recv.session_id,
103 make_ok_message(recv.session_id, task_message.channel_id).await,
104 ));
105 }
106 if !is_auth_enable().await {
107 hdc::info!(
108 "auth enable is false, return OK for session:{}",
109 recv.session_id
110 );
111 return Ok((
112 recv.session_id,
113 make_ok_message(recv.session_id, task_message.channel_id).await,
114 ));
115 }
116
117 // auth is required
118 let buf = generate_token_wait().await;
119
120 AuthStatusMap::put(recv.session_id, AuthStatus::Init(buf.clone())).await;
121
122 let send = native_struct::SessionHandShake {
123 banner: HANDSHAKE_MESSAGE.to_string(),
124 session_id: recv.session_id,
125 connect_key: "".to_string(),
126 buf,
127 auth_type: AuthType::Publickey as u8,
128 version: get_version(),
129 };
130
131 hdc::info!("send handshake: {:#?}", send);
132 let message = TaskMessage {
133 channel_id: task_message.channel_id,
134 command: HdcCommand::KernelHandshake,
135 payload: send.serialize(),
136 };
137 Ok((recv.session_id, message))
138 }
139
make_sign_message(session_id: u32, token: String, channel_id: u32) -> TaskMessage140 async fn make_sign_message(session_id: u32, token: String, channel_id: u32) -> TaskMessage {
141 let send = native_struct::SessionHandShake {
142 banner: HANDSHAKE_MESSAGE.to_string(),
143 session_id,
144 connect_key: "".to_string(),
145 buf: token,
146 auth_type: AuthType::Signature as u8,
147 version: get_version(),
148 };
149 TaskMessage {
150 channel_id,
151 command: HdcCommand::KernelHandshake,
152 payload: send.serialize(),
153 }
154 }
155
make_ok_message(session_id: u32, channel_id: u32) -> TaskMessage156 async fn make_ok_message(session_id: u32, channel_id: u32) -> TaskMessage {
157 AuthStatusMap::put(session_id, AuthStatus::Ok).await;
158
159 let send = native_struct::SessionHandShake {
160 banner: HANDSHAKE_MESSAGE.to_string(),
161 session_id,
162 connect_key: "".to_string(),
163 auth_type: AuthType::OK as u8,
164 version: get_version(),
165 buf: match nix::unistd::gethostname() {
166 Ok(hostname) => hostname.into_string().unwrap(),
167 Err(_) => String::from("unknown"),
168 },
169 };
170 TaskMessage {
171 channel_id,
172 command: HdcCommand::KernelHandshake,
173 payload: send.serialize(),
174 }
175 }
176
get_host_pubkey_info(buf: &str) -> (String, String)177 pub fn get_host_pubkey_info(buf: &str) -> (String, String) {
178 if let Some((hostname, pubkey)) = buf.split_once(HDC_HOST_DAEMON_BUF_SEPARATOR) {
179 (hostname.to_string(), pubkey.to_string())
180 } else {
181 ("".to_string(), "".to_string())
182 }
183 }
184
get_new_session_id(task_message: &TaskMessage) -> io::Result<u32>185 pub async fn get_new_session_id(task_message: &TaskMessage) -> io::Result<u32> {
186 let mut recv = native_struct::SessionHandShake::default();
187 recv.parse(task_message.payload.clone())?;
188 Ok(recv.session_id)
189 }
190
handshake_task(task_message: TaskMessage, session_id: u32) -> io::Result<()>191 pub async fn handshake_task(task_message: TaskMessage, session_id: u32) -> io::Result<()> {
192 if let AuthStatus::Ok = AuthStatusMap::get(session_id).await {
193 hdc::info!("session {} already auth ok", session_id);
194 return Ok(());
195 }
196
197 let channel_id = task_message.channel_id;
198
199 if !is_auth_enable().await {
200 hdc::info!("auth enable is false, return OK for session:{}", session_id);
201 transfer::put(session_id, make_ok_message(session_id, channel_id).await).await;
202 return Ok(());
203 }
204
205 let mut recv = native_struct::SessionHandShake::default();
206 recv.parse(task_message.payload)?;
207 hdc::info!("recv handshake: {:#?}", recv);
208
209 if recv.auth_type == AuthType::Publickey as u8 {
210 let plain = if let AuthStatus::Init(buf) = AuthStatusMap::get(session_id).await {
211 hdc::info!("get plain success for session {}", session_id);
212 buf
213 } else {
214 hdc::error!("get plain failed for session {}", session_id);
215 handshake_fail(session_id, channel_id, "auth failed".to_string()).await;
216 return Ok(());
217 };
218 let token = plain.clone();
219
220 let (hostname, pubkey) = get_host_pubkey_info(recv.buf.trim());
221 if pubkey.is_empty() {
222 hdc::error!("get public key from host failed");
223 handshake_fail(
224 session_id,
225 channel_id,
226 "no public key, you may need update your hdc client".to_string(),
227 )
228 .await;
229 return Ok(());
230 }
231 if hostname.is_empty() {
232 hdc::error!("get hostname from host failed");
233 handshake_fail(
234 session_id,
235 channel_id,
236 "no hostname, you may need update your hdc client".to_string(),
237 )
238 .await;
239 return Ok(());
240 }
241
242 let known_hosts = read_known_hosts_pubkey();
243 if known_hosts.contains(&pubkey) {
244 hdc::info!("pubkey matches known host({})", hostname);
245 AuthStatusMap::put(session_id, AuthStatus::Pubk((plain, pubkey))).await;
246 transfer::put(
247 session_id,
248 make_sign_message(session_id, token, channel_id).await,
249 )
250 .await;
251 return Ok(());
252 }
253 match require_user_permittion(&hostname).await {
254 UserPermit::AllowForever => {
255 hdc::info!("allow forever");
256 if write_known_hosts_pubkey(&pubkey).is_err() {
257 handshake_fail(
258 session_id,
259 channel_id,
260 "write public key failed".to_string(),
261 )
262 .await;
263
264 hdc::error!("write public key failed");
265 return Ok(());
266 }
267 AuthStatusMap::put(session_id, AuthStatus::Pubk((plain, pubkey))).await;
268 transfer::put(
269 session_id,
270 make_sign_message(session_id, token, channel_id).await,
271 )
272 .await;
273 }
274 UserPermit::AllowOnce => {
275 hdc::info!("allow once");
276 AuthStatusMap::put(session_id, AuthStatus::Pubk((plain, pubkey))).await;
277 transfer::put(
278 session_id,
279 make_sign_message(session_id, token, channel_id).await,
280 )
281 .await;
282 }
283 _ => {
284 hdc::info!("user refuse");
285 handshake_fail(
286 session_id,
287 channel_id,
288 "public key refused by device".to_string(),
289 )
290 .await;
291 return Ok(());
292 }
293 }
294 } else if recv.auth_type == AuthType::Signature as u8 {
295 match validate_signature(recv.buf, session_id).await {
296 Ok(()) => {
297 transfer::put(session_id, make_ok_message(session_id, channel_id).await).await;
298 transfer::put(
299 session_id,
300 TaskMessage {
301 channel_id,
302 command: HdcCommand::KernelChannelClose,
303 payload: vec![0],
304 },
305 )
306 .await;
307 }
308 Err(e) => {
309 let errlog = e.to_string();
310 hdc::error!("validate signature failed: {}", &errlog);
311 handshake_fail(session_id, channel_id, errlog).await;
312 }
313 }
314 } else {
315 hdc::error!(
316 "invalid auth_type: {} for session {}",
317 recv.auth_type,
318 session_id
319 );
320 // handshake_fail session_id, channel_id auth failed await
321 transfer::put(session_id, make_ok_message(session_id, channel_id).await).await;
322 }
323 Ok(())
324 }
325
validate_signature(signature: String, session_id: u32) -> io::Result<()>326 async fn validate_signature(signature: String, session_id: u32) -> io::Result<()> {
327 let (plain, pubkey) =
328 if let AuthStatus::Pubk((plain, pubkey)) = AuthStatusMap::get(session_id).await {
329 (plain, pubkey)
330 } else {
331 return Err(Error::new(ErrorKind::Other, "auth failed"));
332 };
333
334 let signature_bytes = if let Ok(bytes) = base64::decode_block(&signature) {
335 bytes
336 } else {
337 return Err(Error::new(ErrorKind::Other, "signature decode failed"));
338 };
339
340 let rsa = if let Ok(cipher) = Rsa::public_key_from_pem(pubkey.as_bytes()) {
341 cipher
342 } else {
343 return Err(Error::new(ErrorKind::Other, "pubkey convert failed"));
344 };
345
346 let mut buf = vec![0_u8; config::RSA_BIT_NUM];
347 let dec_size = rsa
348 .public_decrypt(&signature_bytes, &mut buf, Padding::PKCS1)
349 .unwrap_or(0);
350
351 if plain.as_bytes() == &buf[..dec_size] {
352 Ok(())
353 } else {
354 Err(Error::new(ErrorKind::Other, "signature not match"))
355 }
356 }
357
read_known_hosts_pubkey() -> Vec<String>358 fn read_known_hosts_pubkey() -> Vec<String> {
359 let file_name = Path::new(config::RSA_PUBKEY_PATH).join(config::RSA_PUBKEY_NAME);
360 if let Ok(keys) = std::fs::read_to_string(&file_name) {
361 let mut key_vec = vec![];
362 let mut tmp_vec = vec![];
363
364 for line in keys.split('\n') {
365 if line.contains("BEGIN PUBLIC KEY") {
366 tmp_vec.clear();
367 }
368 tmp_vec.push(line);
369 if line.contains("END PUBLIC KEY") {
370 key_vec.push(tmp_vec.join("\n"));
371 }
372 }
373
374 hdc::debug!("read {} known hosts from file", key_vec.len());
375 key_vec
376 } else {
377 hdc::info!("pubkey file {:#?} not exists", file_name);
378 vec![]
379 }
380 }
381
write_known_hosts_pubkey(pubkey: &String) -> io::Result<()>382 fn write_known_hosts_pubkey(pubkey: &String) -> io::Result<()> {
383 let file_name = Path::new(config::RSA_PUBKEY_PATH).join(config::RSA_PUBKEY_NAME);
384 if !file_name.exists() {
385 hdc::info!("create pubkeys file at {:#?}", file_name);
386 let _ = std::fs::create_dir_all(config::RSA_PUBKEY_PATH);
387 let _ = std::fs::File::create(&file_name).unwrap();
388 }
389
390 let _ = match std::fs::File::options().append(true).open(file_name) {
391 Ok(mut f) => writeln!(&mut f, "{}", pubkey),
392 Err(e) => {
393 hdc::error!("write pubkey err: {e}");
394 return Err(e);
395 }
396 };
397 Ok(())
398 }
399
show_permit_dialog() -> bool400 fn show_permit_dialog() -> bool {
401 let cmd = "/system/bin/hdcd_user_permit";
402 let result = Command::new(config::SHELL_PROG).args(["-c", cmd]).output();
403 match result {
404 Ok(output) => {
405 let msg = [output.stdout, output.stderr].concat();
406 let mut str = String::from_utf8(msg).unwrap();
407 str = str.replace('\n', " ");
408 hdc::error!("show dialog over, {}.", str);
409 true
410 }
411 Err(e) => {
412 hdc::error!("show dialog failed, {}.", e.to_string());
413 false
414 }
415 }
416 }
417
is_auth_enable() -> bool418 pub async fn is_auth_enable() -> bool {
419 let (_, debug_auth_enable) = get_dev_item("rw.hdc.daemon.debug_auth_enable", "_");
420 hdc::error!("debug_auth_enable is {}.", debug_auth_enable);
421 match debug_auth_enable.trim() {
422 "force" => true,
423 "true" => {
424 let (_, auth_enable) = get_dev_item("const.hdc.secure", "_");
425 hdc::error!("const.hdc.secure is {}.", auth_enable);
426 auth_enable.trim().to_lowercase() == "1"
427 }
428 _ => false,
429 }
430 }
431
require_user_permittion(hostname: &str) -> UserPermit432 async fn require_user_permittion(hostname: &str) -> UserPermit {
433 // todo debug
434 let default_permit = "auth_result_none";
435 // clear result first
436 if !set_dev_item("persist.hdc.daemon.auth_result", default_permit) {
437 hdc::error!("debug auth result failed, so refuse this connect.");
438 return UserPermit::Refuse;
439 }
440
441 // then write para for setting
442 if !set_dev_item("persist.hdc.client.hostname", hostname) {
443 hdc::error!("set param({}) failed.", hostname);
444 return UserPermit::Refuse;
445 }
446 if !show_permit_dialog() {
447 hdc::error!("show dialog failed, so refuse this connect.");
448 return UserPermit::Refuse;
449 }
450 let permit_result = match get_dev_item("persist.hdc.daemon.auth_result", "_") {
451 (false, _) => {
452 hdc::error!("get_dev_item auth_result failed");
453 UserPermit::Refuse
454 }
455 (true, auth_result) => {
456 hdc::error!("user permit result is:({})", auth_result);
457 match auth_result.strip_prefix("auth_result:").unwrap().trim() {
458 "1" => UserPermit::AllowOnce,
459 "2" => UserPermit::AllowForever,
460 _ => UserPermit::Refuse,
461 }
462 }
463 };
464 permit_result
465 }
466
handshake_fail(session_id: u32, channel_id: u32, msg: String)467 async fn handshake_fail(session_id: u32, channel_id: u32, msg: String) {
468 AuthStatusMap::put(session_id, AuthStatus::Fail).await;
469 let send = native_struct::SessionHandShake {
470 banner: HANDSHAKE_MESSAGE.to_string(),
471 session_id,
472 auth_type: AuthType::Fail as u8,
473 buf: msg,
474 ..Default::default()
475 };
476 transfer::put(
477 session_id,
478 TaskMessage {
479 channel_id,
480 command: config::HdcCommand::KernelHandshake,
481 payload: send.serialize(),
482 },
483 )
484 .await;
485 }
486
generate_token() -> io::Result<String>487 async fn generate_token() -> io::Result<String> {
488 let mut random_file = File::open("/dev/random")?;
489 let mut buffer = [0; HDC_HANDSHAKE_TOKEN_LEN];
490 random_file.read_exact(&mut buffer)?;
491 let random_vec: Vec<_> = buffer.iter().map(|h| format!("{:02X}", h)).collect();
492 let token = random_vec.join("");
493 Ok(token)
494 }
generate_token_wait() -> String495 async fn generate_token_wait() -> String {
496 loop {
497 match generate_token().await {
498 Ok(token) => {
499 break token;
500 }
501 Err(e) => {
502 let errlog = e.to_string();
503 hdc::error!("generate token failed: {}", &errlog);
504 }
505 }
506 }
507 }
508